pthread 立即停止线程_线程取消(pthread_cancel)
基本概念
pthread_cancel調(diào)用并不等待線程終止,它只提出請(qǐng)求。線程在取消請(qǐng)求(pthread_cancel)發(fā)出后會(huì)繼續(xù)運(yùn)行,
直到到達(dá)某個(gè)取消點(diǎn)(CancellationPoint)。取消點(diǎn)是線程檢查是否被取消并按照請(qǐng)求進(jìn)行動(dòng)作的一個(gè)位置.
與線程取消相關(guān)的pthread函數(shù)
int pthread_cancel(pthread_t thread)
發(fā)送終止信號(hào)給thread線程,如果成功則返回0,否則為非0值。發(fā)送成功并不意味著thread會(huì)終止。
int pthread_setcancelstate(int state,?? int *oldstate)
設(shè)置本線程對(duì)Cancel信號(hào)的反應(yīng),state有兩種值:PTHREAD_CANCEL_ENABLE(缺省)和PTHREAD_CANCEL_DISABLE,
分別表示收到信號(hào)后設(shè)為CANCLED狀態(tài)和忽略CANCEL信號(hào)繼續(xù)運(yùn)行;old_state如果不為NULL則存入原來(lái)的Cancel狀態(tài)以便恢復(fù)。
int pthread_setcanceltype(int type, int *oldtype)
設(shè)置本線程取消動(dòng)作的執(zhí)行時(shí)機(jī),type由兩種取值:PTHREAD_CANCEL_DEFFERED和PTHREAD_CANCEL_ASYCHRONOUS,僅當(dāng)Cancel狀態(tài)為Enable時(shí)有效,分別表示收到信號(hào)后繼續(xù)運(yùn)行至下一個(gè)取消點(diǎn)再退出和立即執(zhí)行取消動(dòng)作(退出);oldtype如果不為NULL則存入運(yùn)來(lái)的取消動(dòng)作類型值。
void pthread_testcancel(void)
是說(shuō)pthread_testcancel在不包含取消點(diǎn),但是又需要取消點(diǎn)的地方創(chuàng)建一個(gè)取消點(diǎn),以便在一個(gè)沒(méi)有包含取消點(diǎn)的執(zhí)行代碼線程中響應(yīng)取消請(qǐng)求.
線程取消功能處于啟用狀態(tài)且取消狀態(tài)設(shè)置為延遲狀態(tài)時(shí),pthread_testcancel()函數(shù)有效。
如果在取消功能處處于禁用狀態(tài)下調(diào)用pthread_testcancel(),則該函數(shù)不起作用。
請(qǐng)務(wù)必僅在線程取消線程操作安全的序列中插入pthread_testcancel()。除通過(guò)pthread_testcancel()調(diào)用以編程方式建立的取消點(diǎn)意外,pthread標(biāo)準(zhǔn)還指定了幾個(gè)取消點(diǎn)。測(cè)試退出點(diǎn),就是測(cè)試cancel信號(hào).
取消點(diǎn):
線程取消的方法是向目標(biāo)線程發(fā)Cancel信號(hào),但如何處理Cancel信號(hào)則由目標(biāo)線程自己決定,或者忽略、或者立即終止、或者繼續(xù)運(yùn)行至Cancelation-point(取消點(diǎn)),由不同的Cancelation狀態(tài)決定。
線程接收到CANCEL信號(hào)的缺省處理(即pthread_create()創(chuàng)建線程的缺省狀態(tài))是繼續(xù)運(yùn)行至取消點(diǎn),也就是說(shuō)設(shè)置一個(gè)CANCELED狀態(tài),線程繼續(xù)運(yùn)行,只有運(yùn)行至Cancelation-point的時(shí)候才會(huì)退出。
pthreads標(biāo)準(zhǔn)指定了幾個(gè)取消點(diǎn),其中包括:
(1)通過(guò)pthread_testcancel調(diào)用以編程方式建立線程取消點(diǎn)。
(2)線程等待pthread_cond_wait或pthread_cond_timewait()中的特定條件。
(3)被sigwait(2)阻塞的函數(shù)
(4)一些標(biāo)準(zhǔn)的庫(kù)調(diào)用。通常,這些調(diào)用包括線程可基于阻塞的函數(shù)。
缺省情況下,將啟用取消功能。有時(shí),您可能希望應(yīng)用程序禁用取消功能。如果禁用取消功能,則會(huì)導(dǎo)致延遲所有的取消請(qǐng)求,
直到再次啟用取消請(qǐng)求。
根據(jù)POSIX標(biāo)準(zhǔn),pthread_join()、pthread_testcancel()、pthread_cond_wait()、pthread_cond_timedwait()、sem_wait()、sigwait()等函數(shù)以及
read()、write()等會(huì)引起阻塞的系統(tǒng)調(diào)用都是Cancelation-point,而其他pthread函數(shù)都不會(huì)引起Cancelation動(dòng)作。
但是pthread_cancel的手冊(cè)頁(yè)聲稱,由于LinuxThread庫(kù)與C庫(kù)結(jié)合得不好,因而目前C庫(kù)函數(shù)都不是Cancelation-point;但CANCEL信號(hào)會(huì)使線程從阻塞的系統(tǒng)調(diào)用中退出,并置EINTR錯(cuò)誤碼,因此可以在需要作為Cancelation-point的系統(tǒng)調(diào)用前后調(diào)用pthread_testcancel(),從而達(dá)到POSIX標(biāo)準(zhǔn)所要求的目標(biāo).
即如下代碼段:
pthread_testcancel();
retcode = read(fd, buffer, length);
pthread_testcancel();
注意:
程序設(shè)計(jì)方面的考慮,如果線程處于無(wú)限循環(huán)中,且循環(huán)體內(nèi)沒(méi)有執(zhí)行至取消點(diǎn)的必然路徑,則線程無(wú)法由外部其他線程的取消請(qǐng)求而終止。因此在這樣的循環(huán)體的必經(jīng)路徑上應(yīng)該加入pthread_testcancel()調(diào)用.
取消類型(Cancellation Type)
我們會(huì)發(fā)現(xiàn),通常的說(shuō)法:某某函數(shù)是 Cancellation Points,這種方法是容易令人混淆的。
因?yàn)楹瘮?shù)的執(zhí)行是一個(gè)時(shí)間過(guò)程,而不是一個(gè)時(shí)間點(diǎn)。其實(shí)真正的 Cancellation Points 只是在這些函數(shù)中 Cancellation Type 被修改為 PHREAD_CANCEL_ASYNCHRONOUS 和修改回 PTHREAD_CANCEL_DEFERRED 中間的一段時(shí)間。
POSIX的取消類型有兩種,一種是延遲取消(PTHREAD_CANCEL_DEFERRED),這是系統(tǒng)默認(rèn)的取消類型,即在線程到達(dá)取消點(diǎn)之前,不會(huì)出現(xiàn)真正的取消;另外一種是異步取消(PHREAD_CANCEL_ASYNCHRONOUS),使用異步取消時(shí),線程可以在任意時(shí)間取消。
線程終止的清理工作
Posix的線程終止有兩種情況:正常終止和非正常終止。
線程主動(dòng)調(diào)用pthread_exit()或者從線程函數(shù)中return都將使線程正常退出,這是可預(yù)見(jiàn)的退出方式;
非正常終止是線程在其他線程的干預(yù)下,或者由于自身運(yùn)行出錯(cuò)(比如訪問(wèn)非法地址)而退出,這種退出方式是不可預(yù)見(jiàn)的。
不論是可預(yù)見(jiàn)的線程終止還是異常終止,都會(huì)存在資源釋放的問(wèn)題,在不考慮因運(yùn)行出錯(cuò)而退出的前提下,如何保證線程終止時(shí)能順利的釋放掉自己所占用的資源,特別是鎖資源,就是一個(gè)必須考慮解決的問(wèn)題。
最經(jīng)常出現(xiàn)的情形是資源獨(dú)占鎖的使用:線程為了訪問(wèn)臨界資源而為其加上鎖,但在訪問(wèn)過(guò)程中被外界取消,如果線程處于響應(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線程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ù)鏈;
從pthread_cleanup_push的調(diào)用點(diǎn)到pthread_cleanup_pop之間的程序段中的終止動(dòng)作(包括調(diào)用pthread_exit()和異常終止,不包括return)
都將執(zhí)行pthread_cleanup_push()所指定的清理函數(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)線程在"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);
或者void cleanup(void *arg)
{
pthread_mutex_unlock(&mutex);
}void* thread0(void*arg)
{
pthread_cleanup_push(cleanup, NULL);//thread cleanup handler p
thread_mutex_lock(&mutex);
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);
pthread_cleanup_pop(0);
pthread_exit(NULL);
}
總結(jié)
以上是生活随笔為你收集整理的pthread 立即停止线程_线程取消(pthread_cancel)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: okhttp3测试框架_easy-okh
- 下一篇: mysql 修改配置生效_MySQL修改