線程的創建及終止
線程 ID
線程 ID 只在它所屬的進程環境有效,並用 pthread_t 數據類型來表示,實現的時候可以用一個結構來代表 pthread_t 數據類型,所以在可移植的操作系統實現不能把它當做為整數來處理。因此必須使用函數(pthread_equal)來對兩個線程 ID 進行比較。可以用 pthread_self 獲取自身線程 ID 。
線程的創建
線程創建時並不能保證哪個線程先運行 : 是新創建的線程還是調用線程。新創建的線程可以訪問進程的地址空間,並且繼承調用線程的浮點環境和信號屏蔽字,但是該線程的未決信號集被清除。
errno
注意 pthread 函數在調用失敗時通常會返回錯誤代碼,它們並不像其他的 POSIX 函數一樣設置 errno。每個線程都提供 errno 的副本,這只是為了與使用 errno 的現有函數兼容。在線程中,從函數中返回的錯誤碼更為清晰整潔,不需要依賴那些隨着函數執行不斷變化的全局狀態,因而可以把錯誤的范圍限制在引起出錯的函數中。
線程的終止
如果進程中的任一線程調用了 exit,_Exit,或者_exit,那么整個進程就會終止。於此類似,如果信號的默認動作是終止進程,那么,把該信號發送到線程會終止整個進程。
單個線程終止三種方式
-
- 線程只是從啟動例程中返回,返回值是線程的退出碼。
- 線程可以被同一進程的其他線程取消(線程可以通過 pthread_cancel 函數來請求取消同一進程中的其他線程,默認情況下,pthread_cancel 函數會使得指定的線程的行為表現為如同調用了參數為 PTHREAD_CANCELED 的 pthread_exit 函數。但是線程可以選擇忽略取消方式或是控制取消方式,,pthread_cancel 並不等待線程終止,它僅僅提交請求)。
- 線程調用 pthread_ext (在 pthread_exit 可以在退出的時候可以傳遞一些信息,那這些信息可以用 pthread_join 函數獲得,那么調用 pthread_join 函數將會一直阻塞,直到指定的線程調用 pthread_exit)。
在默認情況下,線程的終止狀態會保存到該線程調用 pthread_join,如果線程已經處於分離狀態,線程的底層存儲資源可以在線程終止時立即被回收。當線程被分離時,並不能用 pthread_join 函數等待它的終止狀態。對分離狀態的線程進行 pthread_join 的調用可以產生失敗,返回 EINVAL。pthread_detach 調用可以用於使線程進入分離狀態。
資料:
-
- pthread_join 監控線程退出的狀態 http://www.cnblogs.com/shishuirunian/archive/2012/05/18/2508070.html
- POSIX線程的創建與取消—pthreads線程庫實例筆記1 http://www.cnblogs.com/blueclue/archive/2010/06/11/1754899.html
- POSIX線程的創建與取消—pthreads線程庫實例筆記2 http://www.cnblogs.com/blueclue/archive/2010/07/02/1758301.html
- pthread_join: http://www.cnblogs.com/dongzhiquan/archive/2012/02/16/2355032.html
線程清理處理程序
線程可以安排它退出時需要的函數,這與進程可以用 atexit 函數安排進程退出時需要調用的函數是類似的。這樣的函數稱為線程清理處理程序。線程可以建立多個清理處理程序,處理程序記錄在棧中,也就是說它們的執行順序與它們注冊時的順序相反
-
- pthread_cleanup_push(..) 將線程清理處理程序壓棧
- pthread_cleanup_pop(..) 將線程清理處理程序出棧
當線程執行以下動作時調用清理函數,調用參數 arg,清理函數 rtn 的調用順序是由 pthread_cleanup_push 函數來安排的。
-
- 調用 pthread_exit 時
- 響應取消請求時
- 用非零 execute 參數調用 pthread_cleanup_pop 時
如果 execute 參數設置為 0,清理函數將不會被調用。無論哪種情況,pthread_cleanup_pop 都將刪除上次 pthread_clean_push 調用建立的清理處理程序
線程睡眠、阻塞、掛起的區別與解釋
首先這些術語都是對於線程來說的。對線程的控制就好比你控制了一個雇工為你干活。你對雇工的控制是通過編程來實現的。
-
- 掛起線程的意思就是你對主動對雇工說:“你睡覺去吧,用着你的時候我主動去叫你,然后接着干活”。
- 線程睡眠的意思就是你主動對雇工說:“你睡覺去吧,某時某刻過來報到,然后接着干活”。
- 線程阻塞的意思就是,你突然發現,你的雇工不知道在什么時候沒經過你允許,自己睡覺呢,但是你不能怪雇工,肯定你這個雇主沒注意,本來你讓雇工掃地,結果掃帚被偷了或被鄰居家借去了,你又沒讓雇工繼續干別的活,他就只好睡覺了。至於掃帚回來后,雇工會不會知道,會不會繼續干活,你不用擔心,雇工一旦發現掃帚回來了,他就會自己去干活的。因為雇工受過良好的培訓。這個培訓機構就是操作系統。
例子:
線程的創建以及等待其終止

#include<iostream> #include<pthread.h> #include<unistd.h> using namespace std; void *th_fn(void *arg) { cout<<"new thread"<<endl; return (void *)10; } int main() { pthread_t ptid; void *tret; pthread_create(&ptid, NULL,th_fn ,NULL); pthread_join(ptid, &tret); cout<<"code 2 exit id = "<<(int)tret<<endl; return 0; }
運行結果:
線程的屬性與限制
線程限制
線程的限制可以通過 sysconf 函數來進行查詢。
-
- PTHREAD_DESTRUCTOR_ITERATIONS 線程退出時,操作系統實現試圖銷毀線程私有數據的最大次數。
- PTHREAD_KEYS_MAX 進程可以創建的鍵的最大數目
- PTHREAD_STACK_MIN 一個線程的棧可用的最小字節數
- PTHREAD_THREADS_MAX 進程可以創建的最大線程數
線程的屬性
初始化線程屬性/銷毀線程屬性
-
- pthread_attr_init(..)
- pthread_attr_destroy(..)
如果要去除對 pthread_attr_t 結構的初始化,可以調用 pthread_attr_destroy 函數。如果 pthread_attr_init 實現時為屬性對象分配了動態內存空間,pthread_attr_destroy 將會釋放內存空間。除此之外, pthread_attr_destroy 還會用無效的值初始化屬性對象,因此如果該屬性對象被誤用,將會導致 pthread_create 函數返回錯誤。
-
- detachstate(..) 線程的分離狀態屬性(如果對現有的某個線程的終止狀態不感興趣的話,可以使用 pthread_detach 函數讓操作系統在線程退出時收回它所占用的資源)
- guardsize(..) 線程棧末尾的警戒緩沖區大小
- stackaddr(..) 線程棧的最低地址
- stacksize(..) 線程棧的大小
設置和獲得線程的分離屬性
-
- pthread_attr_getdetachstate(..)
- pthread_attr_setdetachstate(..)