Posix執行緒程式設計指南 4 執行緒終止

2022-03-12 03:39:27 字數 3021 閱讀 2599

執行緒終止方式

一般來說,posix的執行緒終止有兩種情況:正常終止和非正常終止。執行緒主動呼叫pthread_exit()或者從執行緒函式中return都將使執行緒正常退出,這是可預見的退出方式;非正常終止是執行緒在其他執行緒的干預下,或者由於自身執行出錯(比如訪問非法位址)而退出,這種退出方式是不可預見的。

回頁首執行緒終止時的清理

不論是可預見的執行緒終止還是異常終止,都會存在資源釋放的問題,在不考慮因執行出錯而退出的前提下,如何保證執行緒終止時能順利的釋放掉自己所占用的資源,特別是鎖資源,就是乙個必須考慮解決的問題。

最經常出現的情形是資源獨佔鎖的使用:執行緒為了訪問臨界資源而為其加上鎖,但在訪問過程中被外界取消,如果執行緒處於響應取消狀態,且採用非同步方式響應,或者在開啟獨佔鎖以前的執行路徑上存在取消點,則該臨界資源將永遠處於鎖定狀態得不到釋放。外界取消操作是不可預見的,因此的確需要乙個機制來簡化用於資源釋放的程式設計。

在posix執行緒api中提供了乙個pthread_cleanup_push()/pthread_cleanup_pop()函式對用於自動釋放資源--從pthread_cleanup_push()的呼叫點到pthread_cleanup_pop()之間的程式段中的終止動作(包括呼叫pthread_exit()和取消點終止)都將執行pthread_cleanup_push()所指定的清理函式。api定義如下:

void pthread_cleanup_push(void (*routine) (void  *),  void *arg)

void pthread_cleanup_pop(int execute)

pthread_cleanup_push()/pthread_cleanup_pop()採用先入後出的棧結構管理,void routine(void *arg)函式在呼叫pthread_cleanup_push()時壓入清理函式棧,多次對pthread_cleanup_push()的呼叫將在清理函式棧中形成乙個函式鏈,在執行該函式鏈時按照壓棧的相反順序彈出。execute引數表示執行到pthread_cleanup_pop()時是否在彈出清理函式的同時執行該函式,為0表示不執行,非0為執行;這個引數並不影響異常終止時清理函式的執行。

pthread_cleanup_push()/pthread_cleanup_pop()是以巨集方式實現的,這是pthread.h中的巨集定義:

#define pthread_cleanup_push(routine,arg)                                     \

可見,pthread_cleanup_push()帶有乙個"",因此這兩個函式必須成對出現,且必須位於程式的同一級別的**段中才能通過編譯。在下面的例子裡,當執行緒在"do some work"中終止時,將主動呼叫pthread_mutex_unlock(mut),以完成解鎖動作。

pthread_cleanup_push(pthread_mutex_unlock, (void *) &mut);

pthread_mutex_lock(&mut);

/* do some work */

pthread_mutex_unlock(&mut);

pthread_cleanup_pop(0);

必須要注意的是,如果執行緒處於pthread_cancel_asynchronous狀態,上述**段就有可能出錯,因為cancel事件有可能在pthread_cleanup_push()和pthread_mutex_lock()之間發生,或者在pthread_mutex_unlock()和pthread_cleanup_pop()之間發生,從而導致清理函式unlock乙個並沒有加鎖的mutex變數,造成錯誤。因此,在使用清理函式的時候,都應該暫時設定成pthread_cancel_deferred模式。為此,posix的linux實現中還提供了一對不保證可移植的pthread_cleanup_push_defer_np()/pthread_cleanup_pop_defer_np()擴充套件函式,功能與以下**段相當:

回頁首執行緒終止的同步及其返回值

一般情況下,程序中各個執行緒的執行都是相互獨立的,執行緒的終止並不會通知,也不會影響其他執行緒,終止的執行緒所占用的資源也並不會隨著執行緒的終止而得到釋放。正如程序之間可以用wait()系統呼叫來同步終止並釋放資源一樣,執行緒之間也有類似機制,那就是pthread_join()函式。

void pthread_exit(void *retval) 

int pthread_join(pthread_t th, void **thread_return)

int pthread_detach(pthread_t th)

pthread_join()的呼叫者將掛起並等待th執行緒終止,retval是pthread_exit()呼叫者執行緒(執行緒id為th)的返回值,如果thread_return不為null,則*thread_return=retval。需要注意的是乙個執行緒僅允許唯一的乙個執行緒使用pthread_join()等待它的終止,並且被等待的執行緒應該處於可join狀態,即非detached狀態。

如果程序中的某個執行緒執行了pthread_detach(th),則th執行緒將處於detached狀態,這使得th執行緒在結束執行時自行釋放所占用的記憶體資源,同時也無法由pthread_join()同步,pthread_detach()執行之後,對th請求pthread_join()將返回錯誤。

乙個可join的執行緒所占用的記憶體僅當有執行緒對其執行了pthread_join()後才會釋放,因此為了避免記憶體洩漏,所有執行緒的終止,要麼已設為detached,要麼就需要使用pthread_join()來**。

回頁首關於pthread_exit()和return

理論上說,pthread_exit()和執行緒宿體函式退出的功能是相同的,函式結束時會在內部自動呼叫pthread_exit()來清理執行緒相關的資源。但實際上二者由於編譯器的處理有很大的不同。

在程序主函式(main())中呼叫pthread_exit(),只會使主函式所在的執行緒(可以說是程序的主線程)退出;而如果是return,編譯器將使其呼叫程序退出的**(如_exit()),從而導致程序及其所有執行緒結束執行。

Posix執行緒程式設計指南 2

概念及作用 在單執行緒程式中,我們經常要用到 全域性變數 以實現多個函式間共享資料。在多執行緒環境下,由於資料空間是共享的,因此全域性變數也為所有執行緒所共有。但有時應用程式設計中有必要提供執行緒私有的全域性變數,僅在某個執行緒中有效,但卻可以跨多個函式訪問,比如程式可能需要每個執行緒維護乙個鍊錶,...

Posix執行緒程式設計指南 5

posix執行緒程式設計指南 5 日期 2006 2 13 14 46 00 host01.com 訪問 是乙個關於posix執行緒程式設計的專欄。作者在闡明概念的基礎上,將向您詳細講述posix執行緒庫api。本文是第五篇將向您講述pthread self pthread equal 和pthre...

POSIX 執行緒程式設計指南(二)

例程 int pthread create pthread t thread const pthread attr t attr void start routine void void arg 注 原文通篇沒有引數型別,對於一些必要的介面,我會從上面copy後貼上與此 建立執行緒 程序能建立的執行...