pthread_cleanup_push/pop

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

void pthread_cleanup_pop(int execute);//這裏的int參數,0是不執行push的內容,非0是執行。

原型很簡單,功能跟atexit()差不多,只不過一個是線程一個是進程。
用來設置在push/pop內線程退出時要做的事情。

需要注意的問題有幾點:
1,push與pop一定是成對出現的,其實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 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進來的函數指針指向的函數,沒錯,是不執行,真要執行了就麻煩了。

那爲啥還得寫這句呢?

那是因爲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,則會再次釋放,錯就錯在這裏了,釋放了兩次。

所以,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_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.
pthread_cleanup_push(void(*fun)(void* arg),void* arg);
pthread_cleanup_pop(int);
注意pthread_cleanup_pop(int)用法
如果pthread_cleanup_push 和pthread_cleanup_pop 包含的代碼正常執行了,那麼在遇到
pthread_cleanup_pop這句時,如果參數爲0,將不會執行push進的函數,否則執行.
發佈了15 篇原創文章 · 獲贊 1 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章