pthread_cleanup_push
線(xiàn)程終止時(shí)的清理
不論是可預(yù)見(jiàn)的線(xiàn)程終止還是異常終止,都會(huì)存在資源釋放的問(wèn)題,在不考慮因運(yùn)行出錯(cuò)而退出的前提下,如何保證線(xiàn)程終止時(shí)能順利的釋放掉自己所占用的資源,特別是鎖資源,就是一個(gè)必須考慮解決的問(wèn)題。
最經(jīng)常出現(xiàn)的情形是資源獨(dú)占鎖的使用:線(xiàn)程為了訪問(wèn)臨界資源而為其加上鎖,但在訪問(wèn)過(guò)程中被外界取消,如果線(xiàn)程處于響應(yīng)取消狀態(tài),且采用異步方式響應(yīng),或者在打開(kāi)獨(dú)占鎖以前的運(yùn)行路徑上存在取消點(diǎn),則該臨界資源將永遠(yuǎn)處于鎖定狀態(tài)得不到釋放。外界取消操作是不可預(yù)見(jiàn)的,因此的確需要一個(gè)機(jī)制來(lái)簡(jiǎn)化用于資源釋放的編程。
在POSIX線(xiàn)程API中提供了一個(gè)pthread_cleanup_push()/pthread_cleanup_pop()函數(shù)對(duì)用于自動(dòng)釋放資源--從pthread_cleanup_push()的調(diào)用點(diǎn)到pthread_cleanup_pop()之間的程序段中的終止動(dòng)作(包括調(diào)用pthread_exit()和取消點(diǎn)終止)都將執(zhí)行pthread_cleanup_push()所指定的清理函數(shù)。API定義如下:
| ? void pthread_cleanup_push(void (*routine) (void *), void *arg)void pthread_cleanup_pop(int execute) |
?
pthread_cleanup_push()/pthread_cleanup_pop()采用先入后出的棧結(jié)構(gòu)管理,void routine(void *arg)函數(shù)在調(diào)用pthread_cleanup_push()時(shí)壓入清理函數(shù)棧,多次對(duì)pthread_cleanup_push()的調(diào)用將在清理函數(shù)棧中形成一個(gè)函數(shù)鏈,在執(zhí)行該函數(shù)鏈時(shí)按照壓棧的相反順序彈出。execute參數(shù)表示執(zhí)行到pthread_cleanup_pop()時(shí)是否在彈出清理函數(shù)的同時(shí)執(zhí)行該函數(shù),為0表示不執(zhí)行,非0為執(zhí)行;這個(gè)參數(shù)并不影響異常終止時(shí)清理函數(shù)的執(zhí)行。
pthread_cleanup_push()/pthread_cleanup_pop()是以宏方式實(shí)現(xiàn)的,這是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)); } |
?
可見(jiàn),pthread_cleanup_push()帶有一個(gè)"{",而pthread_cleanup_pop()帶有一個(gè)"}",因此這兩個(gè)函數(shù)必須成對(duì)出現(xiàn),且必須位于程序的同一級(jí)別的代碼段中才能通過(guò)編譯。在下面的例子里,當(dāng)線(xiàn)程在"do some work"中終止時(shí),將主動(dòng)調(diào)用pthread_mutex_unlock(mut),以完成解鎖動(dòng)作。
| ? pthread_cleanup_push(pthread_mutex_unlock, (void *) &mut);pthread_mutex_lock(&mut);/* do some work */pthread_mutex_unlock(&mut);pthread_cleanup_pop(0); |
?
必須要注意的是,如果線(xiàn)程處于PTHREAD_CANCEL_ASYNCHRONOUS狀態(tài),上述代碼段就有可能出錯(cuò),因?yàn)镃ANCEL事件有可能在pthread_cleanup_push()和pthread_mutex_lock()之間發(fā)生,或者在pthread_mutex_unlock()和pthread_cleanup_pop()之間發(fā)生,從而導(dǎo)致清理函數(shù)unlock一個(gè)并沒(méi)有加鎖的mutex變量,造成錯(cuò)誤。因此,在使用清理函數(shù)的時(shí)候,都應(yīng)該暫時(shí)設(shè)置成PTHREAD_CANCEL_DEFERRED模式。為此,POSIX的Linux實(shí)現(xiàn)中還提供了一對(duì)不保證可移植的pthread_cleanup_push_defer_np()/pthread_cleanup_pop_defer_np()擴(kuò)展函數(shù),功能與以下代碼段相當(dāng):
| ? { int oldtype; pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype); pthread_cleanup_push(routine, arg); ... pthread_cleanup_pop(execute); pthread_setcanceltype(oldtype, NULL); } |
?
?
線(xiàn)程終止的同步及其返回值
一般情況下,進(jìn)程中各個(gè)線(xiàn)程的運(yùn)行都是相互獨(dú)立的,線(xiàn)程的終止并不會(huì)通知,也不會(huì)影響其他線(xiàn)程,終止的線(xiàn)程所占用的資源也并不會(huì)隨著線(xiàn)程的終止而得到釋放。正如進(jìn)程之間可以用wait()系統(tǒng)調(diào)用來(lái)同步終止并釋放資源一樣,線(xiàn)程之間也有類(lèi)似機(jī)制,那就是pthread_join()函數(shù)。
| ? void pthread_exit(void *retval) int pthread_join(pthread_t th, void **thread_return)int pthread_detach(pthread_t th) |
?
pthread_join()的調(diào)用者將掛起并等待th線(xiàn)程終止,retval是pthread_exit()調(diào)用者線(xiàn)程(線(xiàn)程ID為th)的返回值,如果thread_return不為NULL,則*thread_return=retval。需要注意的是一個(gè)線(xiàn)程僅允許唯一的一個(gè)線(xiàn)程使用pthread_join()等待它的終止,并且被等待的線(xiàn)程應(yīng)該處于可join狀態(tài),即非DETACHED狀態(tài)。
如果進(jìn)程中的某個(gè)線(xiàn)程執(zhí)行了pthread_detach(th),則th線(xiàn)程將處于DETACHED狀態(tài),這使得th線(xiàn)程在結(jié)束運(yùn)行時(shí)自行釋放所占用的內(nèi)存資源,同時(shí)也無(wú)法由pthread_join()同步,pthread_detach()執(zhí)行之后,對(duì)th請(qǐng)求pthread_join()將返回錯(cuò)誤。
一個(gè)可join的線(xiàn)程所占用的內(nèi)存僅當(dāng)有線(xiàn)程對(duì)其執(zhí)行了pthread_join()后才會(huì)釋放,因此為了避免內(nèi)存泄漏,所有線(xiàn)程的終止,要么已設(shè)為DETACHED,要么就需要使用pthread_join()來(lái)回收。
?
關(guān)于pthread_exit()和return
理論上說(shuō),pthread_exit()和線(xiàn)程宿體函數(shù)退出的功能是相同的,函數(shù)結(jié)束時(shí)會(huì)在內(nèi)部自動(dòng)調(diào)用pthread_exit()來(lái)清理線(xiàn)程相關(guān)的資源。但實(shí)際上二者由于編譯器的處理有很大的不同。
在進(jìn)程主函數(shù)(main())中調(diào)用pthread_exit(),只會(huì)使主函數(shù)所在的線(xiàn)程(可以說(shuō)是進(jìn)程的主線(xiàn)程)退出;而如果是return,編譯器將使其調(diào)用進(jìn)程退出的代碼(如_exit()),從而導(dǎo)致進(jìn)程及其所有線(xiàn)程結(jié)束運(yùn)行。
其次,在線(xiàn)程宿主函數(shù)中主動(dòng)調(diào)用return,如果return語(yǔ)句包含在pthread_cleanup_push()/pthread_cleanup_pop()對(duì)中,則不會(huì)引起清理函數(shù)的執(zhí)行,反而會(huì)導(dǎo)致segment fault。
http://blog.csdn.net/newnewman80/article/details/6276788
轉(zhuǎn)載于:https://www.cnblogs.com/newlist/archive/2012/02/11/2346285.html
總結(jié)
以上是生活随笔為你收集整理的pthread_cleanup_push的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【原】display:inline-bl
- 下一篇: 鼠标事件的