http://blog.csdn.net/slj_win/article/details/7267483
首先你必須知道pthread_cleanup_push與pthread_cleanup_pop的目的(作用)是什么。
比如thread1:
執行
pthread_mutex_lock(&mutex);
//一些會阻塞程序運行的調用,比如套接字的accept,等待客戶連接
sock = accept(......);? ?? ?? ?? ?//這里是隨便找的一個可以阻塞的接口
pthread_mutex_unlock(&mutex);
這個例子中,如果線程1執行accept時,線程會阻塞(也就是等在那里,有客戶端連接的時候才返回,或則出現其他故障),線程等待中......
這時候線程2發現線程1等了很久,不賴煩了,他想關掉線程1,于是調用pthread_cancel()或者類似函數,請求線程1立即退出。
這時候線程1仍然在accept等待中,當它收到線程2的cancel信號后,就會從accept中退出,然后終止線程,注意這個時候線程1還沒有執行:
pthread_mutex_unlock(&mutex);
也就是說鎖資源沒有釋放,這回造成其他線程的死鎖問題。
所以必須在線程接收到cancel后用一種方法來保證異常退出(也就是線程沒達到終點)時可以做清理工作(主要是解鎖方面),pthread_cleanup_push與pthread_cleanup_pop就是這樣的。
pthread_cleanup_push(some_clean_func,...)
pthread_mutex_lock(&mutex);
//一些會阻塞程序運行的調用,比如套接字的accept,等待客戶連接
sock = accept(......);? ?? ?? ?? ?//這里是隨便找的一個可以阻塞的接口
pthread_mutex_unlock(&mutex);
pthread_cleanup_pop(0);
return NULL;
上面的代碼,如果accept被cancel后線程退出,會自動調用some_clean_func函數,在這個函數中你可以釋放鎖資源。如果accept沒有被cancel,那么線程繼續執行,當pthread_mutex_unlock(&mutex);表示線程自己正確的釋放資源了,而執行pthread_cleanup_pop(0);也就是取消掉前面的some_clean_func函數。接著return線程就正確的結束了。
不曉得你明白沒,通俗點就是:
pthread_cleanup_push注冊一個回調函數,如果你的線程在對應的pthread_cleanup_pop之前異常退出(return是正常退出,其他是異常),那么系統就會執行這個回調函數(回調函數要做什么你自己決定)。但是如果在pthread_cleanup_pop之前沒有異常退出,pthread_cleanup_pop就把對應的回調函數取消了,
關于取消點的解釋:
比如你執行:
? ?? ???printf("thread sleep\n");
? ?? ???sleep(10);
? ?? ???printf("thread wake...\n");
在sleep函數中,線程睡眠,結果收到cancel信號,這時候線程從sleep中醒來,但是線程不會立刻退出。這是應為pthread與C庫方面的原因(具體是啥我也不清楚),pthread的建議是,如果一個函數是阻塞的,那么你必須在這個函數前后建立取消點,比如:
? ?? ???printf("thread sleep\n");
? ?? ???pthread_testcancel();
? ?? ???sleep(10);
? ?? ???pthread_testcancel();
? ?? ???printf("thread wake...\n");
這樣,就添加了兩個取消掉。在執行到pthread_testcancel的位置時,線程才可能響應cancel退出進程。
額外的知識:
對于cancel信號,線程有兩種方法: 忽略,和響應。默認是響應
接收到cancel信號,線程有兩種處理類型: 立即響應 和 延遲響應(在最近的取消點響應),默認是延遲響應