Linux中的執行緒的創建與回收
- 執行緒創建
- pthread_creat函式
- 執行緒回收
- pthread_join函式 && pthread_detach函式
- 參考博客
執行緒創建
1.為什么引入執行緒
- 行程在切換時系統開銷大
- 很多做作業系統引入了輕量級行程(LWP)
- 同一執行緒共享相同的地址空間
- Linux本質上不區分行程、執行緒
2. 行程與執行緒的區別
-
行程是計算機中的程式關于某資料集合上的一次運行活動,是系統進行資源分配和調度的基本單位,是作業系統結構的基礎,這里主要強調獨立行程有獨立的地址空間,Linux為每個行程創建task_struct,每個行程都參與內核調度,互不影響,
-
執行緒是行程的一個物體, 是CPU調度和分派的基本單位,它是比行程更小的能獨立運行的基本單位.執行緒自己基本上不擁有系統資源,只擁有一點在運行中必不可少的資源(如程式計數器,一組暫存器和堆疊,下面會細說),但是它可與同屬一個行程的其他的執行緒共享行程所擁有的全部資源,
-
一個執行緒可以創建和撤銷另一個執行緒,同一個行程中的多個執行緒之間可以并發執行,
3. 使用執行緒的好處
- 大大提高了任務切換的效率
- 避免了額外的TLB&cache的重繪
每個執行緒共享的資源 每個執行緒私有的資源
- 可執行的指令 - 執行緒ID(TID)
- 靜態資料 - PC(程式計數器)和相關暫存器
- 行程中打開的檔案描述符 - 堆疊
- 當前的作業路徑 - 錯誤號(errno)
- 用戶ID - 優先級
- 用戶組ID - 執行狀態和屬性
pthread_creat函式
#include <pthread.h>
int pthread_create(pthread_t *tidp,const pthread_attr_t *attr,
void *(*start_rtn)(void*),void *arg);
/*C99中將第一個引數限定為restrict restrict 限定符,表明指標是訪問一個資料物件的唯一且初始的方式.即它告訴編譯器,所有修改該指標所指向記憶體中內容的操作都必須通過該指標來修改,而不能通過其它途徑(其它變數或指標)來修改;這樣做的好處是,能幫助編譯器進行更好的優化代碼,生成更有效率的匯編代碼.
*/
- 成功時回傳0,失敗時回傳錯誤碼
- 第一個引數 : thread 執行緒物件
- 第二個引數 : 執行緒屬性,NULL代表默認屬性
- 第三個引數 :執行緒執行的函式
- 第四個引數 :執行函式的引數
這里著重說一下第二個引數,我們可以看到第二個引數的型別是pthread_attr_t指標型別下面具體說一下
typedef struct
{
int detachstate; //執行緒的分離狀態
int schedpolicy; // 執行緒調度策略
structsched_param schedparam; //執行緒的調度引數
int inheritsched; //執行緒的繼承性
int scope; //執行緒的作用域
size_t guardsize; //執行緒堆疊末尾的警戒緩沖區大小
int stackaddr_set;
void* stackaddr; //執行緒堆疊的位置
size_t stacksize; //執行緒堆疊的大小
}pthread_attr_t;
- __detachstate —— 表示新執行緒是否與行程中其他執行緒脫離同步,如果置位則新執行緒不能用pthread_join()來同步與回收,且在退出時自行釋放所占用的資源,預設為 PTHREAD_CREATE_JOINABLE狀態,這個屬性也可以在執行緒創建并運行以后用pthread_detach()來設定,而一旦設定為 PTHREAD_CREATE_DETACH狀態(不論是創建時設定還是運行時設定)則不能再恢復到 PTHREAD_CREATE_JOINABLE狀態,這個屬性與執行緒回收相關,下面會細講兩種狀態的區別,
- __schedpolicy——表示新執行緒的調度策略,主要包括 SCHED_OTHER(正常、非實時)、SCHED_RR(實時、輪轉法)和 SCHED_FIFO(實時、先入先出)三種,預設為SCHED_OTHER,后兩種調度策略僅對超級用戶有效,運行時可以用過 pthread_setschedparam()來改變,
- __schedparam——一個struct sched_param結構,目前僅有一個sched_priority整型變數表示執行緒的運行優先級,這個引數僅當調度策略為實時(即SCHED_RR 或SCHED_FIFO)時才有效,并可以在運行時通過pthread_setschedparam()函式來改變,預設為0,
- __inheritsched——有兩種值可供選擇:PTHREAD_EXPLICIT_SCHED和PTHREAD_INHERIT_SCHED,前者表示新執行緒使用顯式指定調度策略和 調度引數(即attr中的值),而后者表示繼承呼叫者執行緒的值,預設為PTHREAD_EXPLICIT_SCHED,
- __scope——表示執行緒間競爭CPU的范圍,也就是說執行緒優先級的有效范圍,POSIX的標準中定義了兩個值: PTHREAD_SCOPE_SYSTEM和PTHREAD_SCOPE_PROCESS,前者表示與系統中所有執行緒一起競爭CPU時間,后者表示僅與同 行程中的執行緒競爭CPU,目前LinuxThreads僅實作了PTHREAD_SCOPE_SYSTEM一值,
- __stacksize——表示執行緒堆疊的大小,若不指定則默認為ulimit 中的 stack大小,一般來說是8388608位元組,如果是嵌入式開發的話,一般需要通過pthread_attr_setstacksize重新設定值,否則可能創建失敗回傳12錯誤碼(ENOMEM ).,
pthread_attr_t結構中還有一些值,但不使用pthread_create()來設定,
執行緒回收
pthread_join函式 && pthread_detach函式
int pthread_join(pthread_t thread, void **retval);int pthread_join(pthread_t thread, void **retval);
這里執行緒的回收與行程的類似,一個執行緒對應一個pthread_join()呼叫,對同一個執行緒進行多次pthread_join()呼叫是邏輯錯誤,join函式只能回收 PTHREAD_CREATE_JOINABLE狀態的執行緒,其他狀態不可以,當執行緒處于PTHREAD_CREATE_JOINABLE狀態時,如果執行緒結束運行還沒有被回收,則它的 狀態類似于行程中的Zombie Process(僵尸行程),還有一部分的資源沒有被系統回收(退出狀態碼),所以要呼叫pthread_join函式等待要結束的執行緒,并可以的到執行緒退出的狀態碼,
那么上述就可以發生執行緒沒執行完,就執行到join函式,呼叫者會被阻塞,直到執行緒執行完成并且回收,但是有時候我們不希望因執行緒未執行完而被阻塞,比如在Web服務器中當主執行緒為每個新來的鏈接創建一個子執行緒進行處理的時候,主執行緒并不希望因為呼叫pthread_join而阻塞(因為還要繼續處理之后到來的鏈接),這時可以在子執行緒中加入代碼
pthread_detach(pthread_self())
或者父執行緒呼叫
pthread_detach(thread_id)//(非阻塞,可立即回傳)
這將該子執行緒的狀態設定為detached,則該執行緒運行結束后會自動釋放所有資源,
最后關注我,點個贊再走吧(?>?<?)
參考博客
[1] https://blog.csdn.net/tongxinhaonan/article/details/42558561
[2] http://zhaojunjie.blog.51cto.com/5475365/1033968
[3] https://baike.baidu.com/item/pthread_detach
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/265449.html
標籤:其他
