語法: void pthread_cleanup_push(void (*routine)(void*), void *arg); void pthread_cleanup_pop(int execute);//這裏的int參數,0是不執行push的內容,非0是執行。 pthread_cleanup_push很簡單,功能跟atexit()差很少,只不過一個是線程一個是進程。 用來push一些函數入棧,以便線程退出時調用。 pthread_cleanup_pop 則表示彈出經過pthread_cleanup_push入棧的函數中的棧頂函數,它遵循「先進後出原則」 。若是參數爲0,則表示僅僅是彈出棧頂函數但不執行該函數,若是參數爲非0,則表示彈出該函數並執行該函數。 須要注意的問題有幾點: 1,push與pop必定是成對出現的,少一個不行。 2,push能夠有多個,一樣的pop也要對應的數量,遵循"先進後出原則"。 push進去的函數可能在如下三個時機執行: 1,顯示的調用pthread_exit(); 2,在cancel點線程被cancel。 3,pthread_cleanup_pop()的參數不爲0時。 以上動做都限定在push/pop涵蓋的代碼內。 前面的2個比較好理解,關鍵是pthread_cleanup_pop參數問題,其實int那是由於c沒有bool,這裏的參數只有0與非0的區別,對pthread_cleanup_pop,參數是5和10都是同樣的,都是非0。 咱們常常會看到這樣的代碼: void PTHREAD_MUTEX_UNLOCK(void* mutex) { printf("thread 1 exit ,unlock mutxt\n"); pthread_mutex_unlock((pthread_mutex_t*)mutex); } void child(void *t) { pthread_cleanup_push(PTHREAD_MUTEX_UNLOCK,&mutex); pthread_mutex_lock(&mutex); .............. pthread_mutex_unlock(&mutex); pthread_cleanup_pop(0); } 爲啥pthread_cleanup_pop是0呢,他根本就不會執行push進來的函數指針指向的函數而是pop該函數,沒錯,是不執行,真要執行了就麻煩了。 那爲啥還得寫這句呢? 那是由於push和pop是必須成對出現的,不寫就是語法錯誤。 這麼寫的目的主要是爲了保證mutex必定能夠被unlock,由於,在pthread_mutex_lock和pthread_mutex_unlock之間可能發生任何事情,好比,存在N個cancel點致使線程被main或者其餘線程給cancel,而cancel動做是不會釋放互斥鎖的,這樣就鎖死啦。 經過pthread_cleanup_push加入一個函數pthread_mutex_unlock,參照上面執行時機的說明,在線程被cancel的時候,就能夠做釋放鎖的清理動做。若是線程正常執行,知道運行到pthread_cleanup_pop,那麼鎖已經被中間代碼裏的pthread_mutex_unlock給釋放了,這時候若是pthread_cleanup_pop的參數不爲0,則會在pop並執行前面經過pthread_cleanup_push而push的函數,這樣鎖就會再次釋放,固然也就不對了,釋放了兩次。 因此,pthread_cleanup_pop(0)是必須的,由於,首先要成對出現,其次,咱們不但願他真的執行到這裏釋放兩次。 一樣道理: void *exit1(void *t) { printf("exit1\n"); } void *child(void *t) { pthread_cleanup_push(exit1,NULL); ..... pthread_exit(NULL); pthread_cleanup_pop(0); } exit1函數是在pthread_exit(NULL)的時候執行的,pthread_cleanup_pop的參數是否是0沒有關係,由於根本執行不到這裏。 而換成這樣: pthread_cleanup_push(exit1,NULL); ...... pthread_cleanup_pop(0); pthread_exit(NULL); 則exit1不會執行,由於pop的參數是0,若是把pop的參數修改成1則會執行exit1,那會執行兩次嗎?NO,由於執行pthread_cleanup_pop(0)時,已經把經過pthread_cleanup_push(exit1,NULL)壓入棧的函數exit1彈出棧了,並且pthread_exit在push/pop block的外面,他不會觸發exit1. pthread_cleanup_push(exit1,NULL); pthread_cleanup_push(exit2,NULL); ........ pthread_cleanup_pop(0); pthread_cleanup_pop(1); 那0和1分別控制的是誰?配對原則,從外到裏一對一對的拔掉就能夠了,顯然,0控制的是exit2.