線程的定義:
線程,有時被稱爲輕量級進程(Lightweight Process,LWP),是程序執行流的最小單元。一個標準的線程由線程ID,當前指令指針(PC),寄存器集合和堆棧組成。另外,線程是進程中的一個實體,是被系統獨立調度和分派的基本單位,線程本身不擁有系統資源,只擁有一點兒在運行中必不可少的資源,但它可與同屬一個進程的其它線程共享進程所擁有的所有資源。一個線程能夠建立和撤消另外一個線程,同一進程中的多個線程之間能夠併發執行。因爲線程之間的相互制約,導致線程在運行中呈現出間斷性。線程也有就緒、阻塞和運行三種基本狀態。就緒狀態是指線程具有運行的全部條件,邏輯上能夠運行,在等待處理機;運行狀態是指線程佔有處理機正在運行;阻塞狀態是指線程在等待一個事件(如某個信號量),邏輯上不可執行。每個程序都至少有一個線程,若程序只有一個線程,那就是程序自己。
線程是程序中一個單一的順序控制流程。進程內一個相對獨立的、可調度的執行單元,是系統獨立調度和分派CPU的基本單位指運行中的程序的調度單位。在單個程序中同時運行多個線程完成不一樣的工做,稱爲多線程。
各線程還共享如下進程資源和環境:
1. 文件描述符表
2. 每種信號的處理方式(SIG_IGN、 SIG_DFL或者自定義的信號處理函數)
3. 當前工做目錄
4. 用戶id和組id
但有些資源是每一個線程各有一份的:
1. 線程id
2. 上下文,包括各類寄存器的值、程序計數器和棧指針
3. 棧空間
4. errno變量
5. 信號屏蔽字
6. 調度優先級
咱們將要學習的線程庫函數是由POSIX標準定義的,稱爲POSIX thread或者pthread。在Linux上線 程函數位於libpthread共享庫中,所以在編譯時要加上-lpthread選項。
線程建立:
相關函數:多線程
返回值:成功返回0,失敗返回錯誤號。在一個線程中調用pthread_create()建立新的線程後,當前線程從pthread_create()返回繼續往下執行,而新的線程所執行的代碼由咱們傳給pthread_create的函數指針start_routine決 定。start_routine函數接收一個參數,是經過pthread_create的arg參數傳遞給它的,該
參數的類型爲void *,這個指針按什麼類型解釋由調用者本身定義。
start_routine的返回值類型也是void *,這個指針的含義一樣由調用者本身定義。 start_routine返回時,這個線程就退出了,其它線程 能夠調用pthread_join獲得start_routine的返回值,相似於父進程調用wait(2)獲得子進程的退出 狀態。併發
代碼實現:ide
#include<stdio.h> #include<stdlib.h> #include<pthread.h> pthread_t tid; void* thread_run(void* _val) { printf("%s:pid is :%d,tid is:%u\n", (char*)_val,(int)getpid(),(unsigned long long)pthread_self()); return NULL; } int main() { int err=pthread_create(&tid,NULL,thread_run,"other thread run"); if(err!=0) { printf("create thread error!info is:%s\n",strerror(err)); exit(err); } printf("main thread run:pid is:%d,tid is:%u\n",(int)getpid(),(unsigned long long)pthread_self()); sleep(1); return 0; }
運行結果:函數
分析:一、在Linux上,thread_t類型是一個地址值,屬於同一進程的多個線程調用getpid(2)能夠獲得相同的進程號,而調用pthread_self(3)獲得的線程號各不相同。
二、因爲pthread_create的錯誤碼不保存在errno中,所以不能直接用perror(3)打印錯誤信息,能夠先用strerror(3)把錯誤碼轉換成錯誤信息再打印。
三、若是任意一個線程調用了exit或_exit,則整個進程的全部線程都終止,因爲從main函數return也至關於調用exit,爲了防止新建立的線程尚未獲得執行就終止,咱們在main函數return以前延 時1秒,這只是一種權宜之計,即便主線程等待1秒,內核也不必定會調度新建立的線程執行
線程終止:
1. 從線程函數return。這種方法對主線程不適用,從main函數return至關於調用exit。
2. 一個線程能夠調用pthread_cancel終止同一進程中的另外一個線程。
3. 線程能夠調用pthread_exit終止本身。學習
線程等待:
1. 若是thread線程經過return返回,value_ptr所指向的單元裏存放的是thread線程函數的返回值。
2. 若是thread線程被別的線程調用pthread_cancel異常終掉,value_ptr所指向的單元裏存放的是常數PTHREAD_CANCELED。
3. 若是thread線程是本身調用pthread_exit終止的,value_ptr所指向的單元存放的是傳給pthread_exit的參數。 若是對thread線程的終止狀態不感興趣,能夠傳NULL給value_ptr參數spa
相關函數:線程
代碼實現:指針
#include<stdio.h> #include<stdlib.h> #include<pthread.h> void *thread1(void *_val) { printf("thread1 returning...\n"); return (void*)1; } void *thread2(void *_val) { printf("thread2 returning...\n"); pthread_exit( (void*)2); } void *thread3(void *_val) { while(1) { printf("pthread 3 is running,wait for be cancel...\n"); sleep(1); } return NULL; } int main() { pthread_t tid; void *tret; pthread_create(&tid,NULL,thread1,NULL); pthread_join(tid,&tret); printf("thread return,thread id is:%u,return code is:%d\n",(unsigned long)tid,(int)tret); pthread_create(&tid,NULL,thread2,NULL); pthread_join(tid,&tret); printf("thread exit,thread id is:%u,exit code is:%d\n",(unsigned long)tid,(int)tret); pthread_create(&tid,NULL,thread3,NULL); sleep(3); pthread_cancel(tid); pthread_join(tid,&tret); printf("thread return,thread id is:%u,cancel code is:%d\n",(unsigned long)tid,(int)tret); return 0; }
運行結果:code
線程分離:
線程是可結合的( joinable)或者是分離的( detached) 。 一個可結合的線程可以被其餘線程收回其資源和殺死。在被其餘線程回收以前,它的存儲器資源(例如棧)是不釋放的。 相反, 一個分離的線程是不能被其餘線程回收或殺死的,它的存儲器 資源在它終止時由系統自動釋放。
線程默認狀況下被建立成可結合的,爲了不存儲器泄漏,每一個可結合線程都應該要麼被顯示地回收(調用pthread_join),要麼經過調用pthread_detach被分離。調用pthread_join後,若是線程沒有運行結束,調用者會被阻塞。blog
相關函數:
代碼:
#include<stdio.h> #include<stdlib.h> #include<pthread.h> void *thread_run(void *_val) { pthread_detach(pthread_self()); printf("%s\n",(char*)_val); return NULL; } int main() { pthread_t tid; int tret=pthread_create(&tid,NULL,thread_run,"thread1 run..."); if(tret!=0) { printf("create thread error!,info is:%s\n",strerror(tret)); return tret; } int ret=0; sleep(1); if(0==pthread_join(tid,NULL)) { printf("pthread wait success!\n"); ret=0; } else { printf("pthread wait failed!\n"); ret=1; } return ret; }
運行結果: