1.創建thread.
int pthread_create(pthread_t *restrict thread, const pthread_attr_t *restrict attr,
void *(*start_routine)(void*), void *restrict arg);
參數1:pthread_t *restrict thread:創建thread的thread ID.
參數2:const pthread_attr_t *restrict attr:創建線程的屬性。
參數3:void *(*start_routine)(void*):thread服務程序。
參數4:void *restrict arg:thread服務程序參數。
2. 等待目標線程終止:
pthread_join() 函數會一直阻塞調用線程,直到指定的線程終止。
指定的線程必須位於當前的進程中,而且不得是分離線程。所有創建時屬性爲PTHREAD_CREATE_JOINABLE的非分離thread. 最終都需要調用pthread_join() or pthread_detach() 。這樣thread所佔資源和 Thread ID 才被釋放。
3. 分離thread:
int pthread_detach(pthread_t thread);
pthread_detach()指出當thread 結束時,thread所佔資源和Thread ID會被釋放和再利用。如果調用pthread_detach()時,thread沒有結束,它並不會導致thread退出。它只對PTHREAD_CREATE_JOINABLE 非分離thread有效。
4. 獲取thread ID:
pthread_t pthread_self(void);
返回調用thread的thread ID.
5. 比較thread ID:
int pthread_equal(pthread_t t1, pthread_t t2);如果 tid1 和 tid2 相等,pthread_equal() 將返回非零值,否則將返回零。
6. 向thread發信號:
int pthread_kill(pthread_t thread, int sig);
tid 所指定的線程必須與調用線程在同一個進程中。sig 參數必須來自 signal(5) 提供的列表。
7. 退出線程:
void pthread_exit(void *value_ptr);
pthread_exit()用來終止調用thread並置位value_ptr.這個值會交給pthread_join。
Thread的取消:
同一進程內,某個Thread可以向其它thread發送取消要求,要求目標thread退出運行。
取消請求的處理方式取決於目標線程的狀態。狀態由以下兩個函數確定:pthread_setcancelstate() 和pthread_setcanceltype()。
pthread_setcancelstate() 啓用或禁用線程取消功能。創建線程時,缺省情況下線程取消功能處於啓用狀態。
pthread_setcanceltype() 可以將取消類型設置爲延遲或異步模式。創建線程時,缺省情況下會將取消類型設置爲延遲模式。在延遲模式下,只能在取消點取消線程。在異步模式下,可以在執行過程中的任意一點取消線程。因此建議不使用異步模式。
執行取消操作存在一定的危險。大多數危險都與完全恢復不變量和釋放共享資源有關。取消線程時一定要格外小心,否則可能會使互斥保留爲鎖定狀態,從而導致死鎖。或者,已取消的線程可能保留已分配的內存區域,但是系統無法識別這一部分內存,從而無法釋放它。
如果創建thread時使用缺省設置,則thread可以被取消,併爲異步方式,所以向某一thread發送pthread_cancel()後,並不保證什麼時候目標thread會被取消。只有當目標thread運行至取消點時纔會真正退出。
類似Read,write等阻塞函數可以被看作取消點,但Sam記得並不能保證。所以建議使用手動添加取消點。
pthread_testcancel();
當線程取消功能處於啓用狀態且取消類型設置爲延遲模式時,pthread_testcancel() 函數有效。如果在取消功能處於禁用狀態下調用 pthread_testcancel(),則該函數不起作用。
請務必僅在線程取消操作安全的序列中插入 pthread_testcancel()。
例如:Sam一直以爲poll()函數這樣的阻賽類函數爲cancel點,但其實不是,需要手動添加cancel點。
幾個誤區及注意點:
誤區1: 分離線程不能被cancel.
這是將pthread_join與pthread_cancel搞混了。
thread分離可以在創建時設定,也可以用pthread_detach()在創建後設定。
被設定成分離線程後,表明它在退出thread時會自動回收資源。所以不需要pthread_join. 但分離thread完全可以接收pthread_cancel()來退出。
誤區2:已經退出的thread,再去對它pthread_cancel()會出錯。
不會出錯,如果某thread已經退出,再向它發送pthread_cancel().不會出錯。但會返回ESRCH。此值爲3。
ESRCH No thread could be found corresponding to that specified by the given thread ID.
這裏顯示出:一個thread,不管自身return或pthread_exit(). 此thread都算停掉了。只是不分離thread需要使用pthread_join來回收資源而已。
注意點1:不管是否分離,主thread先於其它thread退出,都是不可控的。也就是說會不可預知錯誤。
所以,主thread不要使用return,exit等退出。 而是使用pthread_exit().
主thread使用pthread_exit(). 則會阻賽之,直到所有子thread退出後才退出。
推薦的做法:
常常有這樣的需求,一個子thread既需要在某些事件發生時自己退出,也可能被主thread要求退出。
則可以做如下設計:
子thread自己退出時,使用pthread_exit().
其它thread要求它退出時,是用pthread_cancel(). pthread_join().
則當其它thread先要求它退出時,走正常途徑,pthread_cancel()導致其退出。pthread_join()確保其退出並回收資源。
當其自動使用pthread_exit()退出時,最終主thread也會調用pthread_cancel(),則返回錯誤。但pthread_join()則確保回收資源。
pthread系列函數錯誤碼:
大多數系統函數執行正確返回0。否則返回-1。錯誤碼在errno中。所以可以使用perror()來顯示錯誤。
但pthread系列函數卻通過返回值傳遞error code. 並不向errno中寫入錯誤碼。所以不能使用perror()來查看錯誤原因。
可以使用strerror(pthread_rel) 來打印錯誤原因:
iRel_pthread = pthread_create(&mRtid, NULL, thread_Read_Data, this);
if(iRel_pthread != 0)
{
std::cout <<"kDriver: Create Scan_Device thread Error." << strerror(iRel_pthread) <<std::endl;
}