|
原文: http://hi.baidu.com/tju_ant/item/507566a7549bcadc5af19144
語法: void pthread_cleanup_push(void (*routine)(void*), void *arg); void pthread_cleanup_pop(int execute);//這里的int參數(shù),0是不執(zhí)行push的內容,非0是執(zhí)行。 pthread_cleanup_push很簡單,功能跟atexit()差不多,只不過一個是線程一個是進程。 用來push一些函數(shù)入棧,以便線程退出時調用。 pthread_cleanup_pop 則表示彈出通過pthread_cleanup_push入棧的函數(shù)中的棧頂函數(shù),它遵循“先進后出原則” 。如果參數(shù)為0,則表示僅僅是彈出棧頂函數(shù)但不執(zhí)行該函數(shù),如果參數(shù)為非0,則表示彈出該函數(shù)并執(zhí)行該函數(shù)。 需要注意的問題有幾點: 1,push與pop一定是成對出現(xiàn)的,少一個不行。 2,push可以有多個,同樣的pop也要對應的數(shù)量,遵循"先進后出原則"。 push進去的函數(shù)可能在以下三個時機執(zhí)行: 1,顯示的調用pthread_exit(); 2,在cancel點線程被cancel。 3,pthread_cleanup_pop()的參數(shù)不為0時。 以上動作都限定在push/pop涵蓋的代碼內。 前面的2個比較好理解,關鍵是pthread_cleanup_pop參數(shù)問題,其實int那是因為c沒有bool,這里的參數(shù)只有0與非0的區(qū)別,對pthread_cleanup_pop,參數(shù)是5和10都是一樣的,都是非0。 我們經(jīng)常會看到這樣的代碼:
為啥pthread_cleanup_pop是0呢,他根本就不會執(zhí)行push進來的函數(shù)指針指向的函數(shù)而是pop該函數(shù),沒錯,是不執(zhí)行,真要執(zhí)行了就麻煩了。 那為啥還得寫這句呢? 那是因為push和pop是必須成對出現(xiàn)的,不寫就是語法錯誤。 這么寫的目的主要是為了保證mutex一定可以被unlock,因為,在pthread_mutex_lock和pthread_mutex_unlock之間可能發(fā)生任何事情,比如,存在N個cancel點導致線程被main或者其他線程給cancel,而cancel動作是不會釋放互斥鎖的,這樣就鎖死啦。 通過pthread_cleanup_push加入一個函數(shù)pthread_mutex_unlock,參照上面執(zhí)行時機的說明,在線程被cancel的時候,就可以作釋放鎖的清理動作。如果線程正常執(zhí)行,知道運行到pthread_cleanup_pop,那么鎖已經(jīng)被中間代碼里的pthread_mutex_unlock給釋放了,這時候如果pthread_cleanup_pop的參數(shù)不為0,則會在pop并執(zhí)行前面通過pthread_cleanup_push而push的函數(shù),這樣鎖就會再次釋放,當然也就不對了,釋放了兩次。 所以,pthread_cleanup_pop(0)是必須的,因為,首先要成對出現(xiàn),其次,我們不希望他真的執(zhí)行到這里釋放兩次。 同樣道理:
exit1函數(shù)是在pthread_exit(NULL)的時候執(zhí)行的,pthread_cleanup_pop的參數(shù)是不是0沒有關系,因為根本執(zhí)行不到這里。 而換成這樣:
則exit1不會執(zhí)行,因為pop的參數(shù)是0,如果把pop的參數(shù)修改為1則會執(zhí)行exit1,那會執(zhí)行兩次嗎?NO,因為執(zhí)行pthread_cleanup_pop(0)時,已經(jīng)把通過pthread_cleanup_push(exit1,NULL)壓入棧的函數(shù)exit1彈出棧了,而且pthread_exit在push/pop block的外面,他不會觸發(fā)exit1.
那0和1分別控制的是誰?配對原則,從外到里一對一對的拔掉就可以了,顯然,0控制的是exit2. |
|
|
來自: lifei_szdz > 《linux線程》