Linux線程退出方式總結(jié)(推薦)
在編寫(xiě)多線程代碼時(shí),經(jīng)常面臨線程安全退出的問(wèn)題。
一般情況下,選擇檢查標(biāo)志位的方式:
在線程的while循環(huán)中,執(zhí)行完例程后,都對(duì)標(biāo)志位進(jìn)行檢查,如果標(biāo)志位指示繼續(xù)執(zhí)行則再次執(zhí)行例程,如果標(biāo)志位設(shè)置為退出狀態(tài),則跳出循環(huán),結(jié)束線程的運(yùn)行。
這個(gè)標(biāo)志位需要主線程(或其他線程)設(shè)置,設(shè)置后,主線程調(diào)用pthread_join接口進(jìn)入休眠(接口參數(shù)指定了等待的線程控制指針),子線程退出后,主線程會(huì)接收到系統(tǒng)的信號(hào),從休眠中恢復(fù),這個(gè)時(shí)候就可以去做相關(guān)的資源清除動(dòng)作。
這個(gè)方法可以保證子線程完全退出,主線程再去做相關(guān)的資源清除操作
時(shí)序圖如下
但是某些應(yīng)用中,或許會(huì)發(fā)生下面情況:
子線程阻塞在某個(gè)操作無(wú)法被喚醒,即使主線程設(shè)置了標(biāo)志位,由于子線程進(jìn)入了休眠無(wú)法醒過(guò)來(lái),也沒(méi)有辦法去檢查標(biāo)志位,這個(gè)時(shí)候調(diào)用pthread_join進(jìn)入休眠的主線程等待不到子線程退出的信號(hào),也會(huì)一直休眠,系統(tǒng)進(jìn)入死鎖。
為了更安全地使線程退出,主線程通過(guò)pthread_cancel函數(shù)來(lái)請(qǐng)求取消同一進(jìn)程中的其他線程,再調(diào)用pthread_join等待指定線程退出。使用pthread_cancel接口,需要了解Linux下線程的兩個(gè)屬性,可取消狀態(tài)和可取消類(lèi)型,以及取消點(diǎn)的概念。
可取消狀態(tài):包括PTHREAD_CANCEL_ENABLE和PTHREAD_CANCEL_DISABLE。當(dāng)線程處于PTHREAD_CANCEL_ENABLE,收到cancel請(qǐng)求會(huì)使該線程退出運(yùn)行;反之,若處于PTHREAD_CANCEL_DISABLE,收到的cancel請(qǐng)求將處于未決狀態(tài),線程不會(huì)退出。線程啟動(dòng)時(shí)的默認(rèn)可取消狀態(tài)為PTHREAD_CANCEL_ENABLE,可以通過(guò)接口pthread_setcancelstate改變可取消狀態(tài)的屬性。
可取消類(lèi)型:包括PTHREAD_CANCEL_DEFERRED和PTHREAD_CANCEL_ASYNCHRONOUS。當(dāng)處于PTHREAD_CANCEL_DEFERRED,線程在收到cancel請(qǐng)求后,需要運(yùn)行到取消點(diǎn)才能退出運(yùn)行;如果處于PTHREAD_CANCEL_ASYNCHRONOUS,可以在任意時(shí)間取消,只要收到cancel請(qǐng)求即可馬上退出。線程啟動(dòng)時(shí)默認(rèn)可取消類(lèi)型為PTHREAD_CANCEL_DEFERRED,可通過(guò)pthread_setcanceltype修改可取消類(lèi)型。
取消點(diǎn):線程檢查是否被取消并按照請(qǐng)求進(jìn)行動(dòng)作的一個(gè)位置。
采用PTHREAD_CANCEL_DEFERRED取消方式是因?yàn)榫€程可能在獲取臨界資源后(如獲取鎖),未釋放資源前收到退出信號(hào),如果使用PTHREAD_CANCEL_ ASYNCHRONOUS的方式,無(wú)論線程運(yùn)行到哪個(gè)位置,都會(huì)馬上退出,而占有的資源卻得不到釋放。
采用PTHREAD_CANCEL_DEFERRED取消方式,線程需要運(yùn)行到取消點(diǎn)才退出,而主線程在調(diào)用pthread_cancel后,不能馬上進(jìn)行線程資源釋放,必須調(diào)用pthread_join進(jìn)入休眠,直至等待指定線程退出。
使用PTHREAD_CANCEL_DEFERRED方式并不能完全避免這個(gè)問(wèn)題,因?yàn)闊o(wú)法保證在獲取臨界資源后(比如lock操作)不會(huì)進(jìn)行可以作為取消點(diǎn)的操作(如進(jìn)行sleep),此時(shí)主線程如果對(duì)該線程發(fā)送cancel信號(hào),線程將會(huì)在不釋放鎖的情況下直接結(jié)束運(yùn)行,即還是會(huì)出現(xiàn)在釋放資源前線程就退出的問(wèn)題。
為了避免上述情況,不僅需要設(shè)置可取消類(lèi)型,還需要設(shè)置可取消狀態(tài)。將獲取臨界資源-釋放臨界資源之間的代碼塊都設(shè)置成PTHREAD_CANCEL_DISABLE狀態(tài),其余的代碼塊都設(shè)置成PTHREAD_CANCEL_ENABLE狀態(tài),確保線程在安全的地方退出。如果在可以安全退出的代碼塊不存在取消點(diǎn)系統(tǒng)調(diào)用,可以調(diào)用pthread_testcancel函數(shù)自己添加取消點(diǎn)。
偽代碼描述如下:
void* subThread(void*) { pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,&oldCancleState); …;//不存在獲取臨界資源操作,可以安全退出的代碼塊 pthread_testcancel();//如果可以安全退出的代碼塊不存在取消點(diǎn)操作,可以自己添加pthread_testcancel調(diào)用,線程執(zhí)行到這個(gè)調(diào)用就會(huì)退出 /*還有一種方法,在可以安全退出的代碼塊,我們將線程的可取消類(lèi)型設(shè)置成PTHREAD_CANCEL_ ASYNCHRONOUS,這樣即使沒(méi)有取消點(diǎn)也可以馬上退出*/ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,&oldCancleState); /*存在獲取-釋放臨界資源操作,如果在lock和unlock之間的運(yùn)行收到cancel信號(hào),且可取消狀態(tài)為enable,則鎖永遠(yuǎn)無(wú)法被釋放*/ Lock(); …; Unlock(); } void* mainThread(void*) { pthread_cancel(subThread);//給subThread發(fā)送退出信號(hào) pthread_join(subThread,null);//進(jìn)入休眠,直到subThread退出成功 }
無(wú)論使用哪種方式,核心點(diǎn)就是要保證線程退出的時(shí)候不會(huì)獲取了某些臨界資源而無(wú)法釋放
POSIX.1定義的取消點(diǎn)見(jiàn)下:
注意:當(dāng)主線程調(diào)用pthread_cancel接口后,只是將取消請(qǐng)求發(fā)送給指定線程,
對(duì)接口的成功調(diào)用不能保證指定線程已經(jīng)退出,需要調(diào)用pthread_join等待指定線程完全退出,再進(jìn)行相關(guān)資源的釋放。
以上就是小編為大家?guī)?lái)的Linux線程退出方式總結(jié)(推薦)全部?jī)?nèi)容了,希望大家多多支持腳本之家~
相關(guān)文章
xshell5使用ssh連接阿里云服務(wù)器的實(shí)現(xiàn)步驟
本文主要介紹了xshell5使用ssh連接阿里云服務(wù)器的實(shí)現(xiàn)步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-08-08虛擬機(jī)Linux系統(tǒng)忘記密碼修改root或其他用戶密碼的方法
這篇文章主要介紹了虛擬機(jī)Linux系統(tǒng)忘記密碼修改root或其他用戶密碼的方法,在文章需要大家注意本文基于centos7環(huán)境進(jìn)行操作,由于centos的版本是有差異的,所以需要大家確認(rèn)版本,感興趣的朋友跟隨小編一起看看吧2018-08-08CentOS 7更新時(shí)出現(xiàn):Multilib version problems問(wèn)題的解決方法
這篇文章主要給大家介紹了關(guān)于CentOS 7系統(tǒng)更新時(shí)出現(xiàn):Multilib version problems問(wèn)題的解決方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起看看吧。2017-11-11linux小技巧之利用screen管理你的遠(yuǎn)程會(huì)話
這篇文章主要介紹了關(guān)于linux中的一個(gè)小技巧之利用screen如何管理你的遠(yuǎn)程會(huì)話的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2017-04-04詳解Lamp環(huán)境搭建Linux CentOS6.5編譯安裝mysql5.6
這篇文章主要介紹了詳解Lamp環(huán)境搭建Linux CentOS6.5編譯安裝mysql5.6,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-05-05linux使用tcpdump命令監(jiān)視指定網(wǎng)絡(luò)數(shù)據(jù)包的方法
linux使用tcpdump命令監(jiān)視指定網(wǎng)絡(luò)數(shù)據(jù)包的方法,大家參考使用吧2013-12-12Ubuntu18.04 linux系統(tǒng)安裝JDK與Mysql的方法
這篇文章主要介紹了Ubuntu18.04 linux系統(tǒng)安裝JDK與Mysql的方法,需要的朋友可以參考下2020-02-02Apache ab并發(fā)負(fù)載壓力測(cè)試實(shí)現(xiàn)方法
Apache的ab命令模擬多線程并發(fā)請(qǐng)求,測(cè)試服務(wù)器負(fù)載壓力,也可以測(cè)試nginx、lighthttp、IIS等其它Web服務(wù)器的壓力2019-09-09基于Centos7 部署Varnish緩存代理服務(wù)器
這篇文章主要介紹了基于Centos7 部署Varnish緩存代理服務(wù)器,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-01-01