线程的创建和控制
線程的定義:
線程,有時被稱為輕量級進程(Lightweight Process,LWP),是程序執(zhí)行流的最小單元。一個標準的線程由線程ID,當前指令指針(PC),寄存器集合和堆棧組成。另外,線程是進程中的一個實體,是被系統(tǒng)獨立調(diào)度和分派的基本單位,線程自己不擁有系統(tǒng)資源,只擁有一點兒在運行中必不可少的資源,但它可與同屬一個進程的其它線程共享進程所擁有的全部資源。一個線程可以創(chuàng)建和撤消另一個線程,同一進程中的多個線程之間可以并發(fā)執(zhí)行。由于線程之間的相互制約,致使線程在運行中呈現(xiàn)出間斷性。線程也有就緒、阻塞和運行三種基本狀態(tài)。就緒狀態(tài)是指線程具備運行的所有條件,邏輯上可以運行,在等待處理機;運行狀態(tài)是指線程占有處理機正在運行;阻塞狀態(tài)是指線程在等待一個事件(如某個信號量),邏輯上不可執(zhí)行。每一個程序都至少有一個線程,若程序只有一個線程,那就是程序本身。
線程是程序中一個單一的順序控制流程。進程內(nèi)一個相對獨立的、可調(diào)度的執(zhí)行單元,是系統(tǒng)獨立調(diào)度和分派CPU的基本單位指運行中的程序的調(diào)度單位。在單個程序中同時運行多個線程完成不同的工作,稱為多線程。
各線程還共享以下進程資源和環(huán)境:
1. 文件描述符表
2. 每種信號的處理方式(SIG_IGN、 SIG_DFL或者自定義的信號處理函數(shù))
3. 當前工作目錄
4. 用戶id和組id
但有些資源是每個線程各有一份的:
1. 線程id
2. 上下文,包括各種寄存器的值、程序計數(shù)器和棧指針
3. 棧空間
4. errno變量
5. 信號屏蔽字
6. 調(diào)度優(yōu)先級
我們將要學習的線程庫函數(shù)是由POSIX標準定義的,稱為POSIX thread或者pthread。在Linux上線 程函數(shù)位于libpthread共享庫中,因此在編譯時要加上-lpthread選項。
線程創(chuàng)建:
相關函數(shù):
返回值:成功返回0,失敗返回錯誤號。在一個線程中調(diào)用pthread_create()創(chuàng)建新的線程后,當前線程從pthread_create()返回繼續(xù)往下執(zhí)行,而新的線程所執(zhí)行的代碼由我們傳給pthread_create的函數(shù)指針start_routine決 定。start_routine函數(shù)接收一個參數(shù),是通過pthread_create的arg參數(shù)傳遞給它的,該
參數(shù)的類型為void *,這個指針按什么類型解釋由調(diào)用者自己定義。
start_routine的返回值類型也是void *,這個指針的含義同樣由調(diào)用者自己定義。 start_routine返回時,這個線程就退出了,其它線程 可以調(diào)用pthread_join得到start_routine的返回值,類似于父進程調(diào)用wait(2)得到子進程的退出 狀態(tài)。
代碼實現(xiàn):
#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; }運行結果:
分析:1、在Linux上,thread_t類型是一個地址值,屬于同一進程的多個線程調(diào)用getpid(2)可以得到相同的進程號,而調(diào)用pthread_self(3)得到的線程號各不相同。
2、由于pthread_create的錯誤碼不保存在errno中,因此不能直接用perror(3)打印錯誤信息,可以先用strerror(3)把錯誤碼轉換成錯誤信息再打印。
3、如果任意一個線程調(diào)用了exit或_exit,則整個進程的所有線程都終止,由于從main函數(shù)return也相當于調(diào)用exit,為了防止新創(chuàng)建的線程還沒有得到執(zhí)行就終止,我們在main函數(shù)return之前延 時1秒,這只是一種權宜之計,即使主線程等待1秒,內(nèi)核也不一定會調(diào)度新創(chuàng)建的線程執(zhí)行
線程終止:
1. 從線程函數(shù)return。這種方法對主線程不適用,從main函數(shù)return相當于調(diào)用exit。
2. 一個線程可以調(diào)用pthread_cancel終止同一進程中的另一個線程。
3. 線程可以調(diào)用pthread_exit終止自己。
線程等待:
1. 如果thread線程通過return返回,value_ptr所指向的單元里存放的是thread線程函數(shù)的返回值。
2. 如果thread線程被別的線程調(diào)用pthread_cancel異常終掉,value_ptr所指向的單元里存放的是常數(shù)PTHREAD_CANCELED。
3. 如果thread線程是自己調(diào)用pthread_exit終止的,value_ptr所指向的單元存放的是傳給pthread_exit的參數(shù)。 如果對thread線程的終止狀態(tài)不感興趣,可以傳NULL給value_ptr參數(shù)
相關函數(shù):
代碼實現(xiàn):
#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; }運行結果:
線程分離:
線程是可結合的( joinable)或者是分離的( detached) 。 一個可結合的線程能夠被其他線程收回其資源和殺死。在被其他線程回收之前,它的存儲器資源(例如棧)是不釋放的。 相反, 一個分離的線程是不能被其他線程回收或殺死的,它的存儲器 資源在它終止時由系統(tǒng)自動釋放。
線程默認情況下被創(chuàng)建成可結合的,為了避免存儲器泄漏,每個可結合線程都應該要么被顯示地回收(調(diào)用pthread_join),要么通過調(diào)用pthread_detach被分離。調(diào)用pthread_join后,如果線程沒有運行結束,調(diào)用者會被阻塞。
相關函數(shù):
代碼:
#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; }運行結果:
轉載于:https://blog.51cto.com/760470897/1766824
總結
- 上一篇: Mysql中Innodb大量插入数据时S
- 下一篇: 第二天 Linux常见命令