Posix執行緒程式設計指南(4)-執行緒終止 (轉)
Linux/thread/posix_thread/part4/author1">楊沙洲
2001 年 11 月
這是一個關於Posix執行緒的專欄。作者在闡明概念的基礎上,將向您詳細講述Posix執行緒庫API。本文是第四篇將向您講述執行緒中止。
一般來說,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) { struct _pthread_cleanup_buffer _buffer; _pthread_cleanup_push (&_buffer, (routine), (arg)); #define pthread_cleanup_pop(execute) _pthread_cleanup_pop (&_buffer, (execute)); }
可見,pthread_cleanup_push()帶有一個"{",而pthread_cleanup_pop()帶有一個"}",因此這兩個函式必須成對出現,且必須位於程式的同一級別的程式碼段中才能透過編譯。在下面的例子裡,當執行緒在"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()擴充套件函式,功能與以下程式碼段相當:
{ int oldtype; pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype); pthread_cleanup_push(routine, arg); ... pthread_cleanup_pop(execute); pthread_setcanceltype(oldtype, NULL); }
一般情況下,程式中各個執行緒的執行都是相互獨立的,執行緒的終止並不會通知,也不會影響其他執行緒,終止的執行緒所佔用的資源也並不會隨著執行緒的終止而得到釋放。正如程式之間可以用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()和執行緒宿體函式退出的功能是相同的,函式結束時會在內部自動呼叫pthread_exit()來清理執行緒相關的資源。但實際上二者由於的處理有很大的不同。
在程式主函式(main())中呼叫pthread_exit(),只會使主函式所在的執行緒(可以說是程式的主執行緒)退出;而如果是return,編譯器將使其呼叫程式退出的程式碼(如_exit()),從而導致程式及其所有執行緒結束執行。
其次,線上程宿主函式中主動呼叫return,如果return語句包含在pthread_cleanup_push()/pthread_cleanup_pop()對中,則不會引起清理函式的執行,反而會導致segment fault。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752019/viewspace-982164/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Posix執行緒程式設計指南(3)-執行緒同步 (轉)執行緒程式設計
- Posix執行緒程式設計指南(1)-執行緒建立與取消 (轉)執行緒程式設計
- Posix執行緒程式設計指南(2)-執行緒私有資料 (轉)執行緒程式設計
- Posix執行緒程式設計指南(5)-Misc (轉)執行緒程式設計
- POSIX執行緒程式設計起步(2)-執行緒同步 (轉)執行緒程式設計
- 併發程式設計——如何終止執行緒程式設計執行緒
- Java執行緒中斷與終止執行緒執行Java執行緒
- POSIX執行緒程式設計起步(1)-Hello World (轉)執行緒程式設計
- 執行緒的基本操作:新建和終止執行緒執行緒
- POSIX執行緒詳解 (轉)執行緒
- .NET多執行緒程式設計(4):執行緒池和非同步程式設計 (轉)執行緒程式設計非同步
- Thread執行緒終止interruptthread執行緒
- 問題:執行緒的終止執行緒
- POSIX 執行緒詳解(3) (轉)執行緒
- POSIX執行緒詳解(2) (轉)執行緒
- .NET多執行緒程式設計(3):執行緒同步 (轉)執行緒程式設計
- java執行緒程式設計(一):執行緒基礎(轉)Java執行緒程式設計
- Java之 join 等待執行緒終止Java執行緒
- 如何正確終止正在執行的子執行緒執行緒
- 多執行緒程式設計(轉)執行緒程式設計
- [短文速讀 -5] 多執行緒程式設計引子:程式、執行緒、執行緒安全執行緒程式設計
- 併發程式設計之多執行緒執行緒安全程式設計執行緒
- 終止java執行緒的2種方法Java執行緒
- Java關閉Socket來終止執行緒Java執行緒
- 執行緒同步(C#程式設計指南)執行緒C#程式設計
- .NET多執行緒程式設計(1):多工和多執行緒 (轉)執行緒程式設計
- Java多執行緒設計模式(6)兩階段終止模式Java執行緒設計模式
- 使用執行緒池優化多執行緒程式設計執行緒優化程式設計
- iOS多執行緒程式設計:執行緒同步總結iOS執行緒程式設計
- 多執行緒------執行緒與程式/執行緒排程/建立執行緒執行緒
- 程式設計思想之多執行緒與多程式(4):C++ 中的多執行緒程式設計執行緒C++
- 如何"優雅"地終止一個執行緒?執行緒
- 多執行緒程式設計執行緒程式設計
- 執行緒程式設計(一)執行緒程式設計
- 多執行緒程式設計基礎(一)-- 執行緒的使用執行緒程式設計
- 多執行緒程式設計,處理多執行緒的併發問題(執行緒池)執行緒程式設計
- 程式設計思想之多執行緒與多程式(2):執行緒優先順序與執行緒安全程式設計執行緒
- 執行緒4--執行緒間通訊執行緒