


unix上防止程序死鎖的一些手段
在unix上做C的開發(fā)已經(jīng)快2年了,一直在我們部門的一個(gè)主要產(chǎn)品項(xiàng)目組工作,該產(chǎn)品在市場上經(jīng)受了一年半的考驗(yàn),可以說已經(jīng)是很成熟的產(chǎn)品了,該產(chǎn)品在大部分客戶那里一直穩(wěn)定的運(yùn)行,沒有任何問題,而在少數(shù)幾個(gè)客戶那里,時(shí)不時(shí)的出現(xiàn)整個(gè)系統(tǒng)的吊死,而且該問題沒有任何規(guī)律可尋,除了系統(tǒng)吊死時(shí)候,我們對整個(gè)系統(tǒng)用pstack進(jìn)行所有進(jìn)程堆棧的跟蹤記錄外,我們沒有任何其它線索,沒有系統(tǒng)崩潰時(shí)候產(chǎn)生的CORE,我們開始面對來自客戶強(qiáng)大的壓力。。。。我們幾乎喘不過起來,我們要給客戶提交故障報(bào)告,而這些故障報(bào)告的問題都是這一個(gè)問題,這個(gè)問題開始成為懸在我們頭上的一把利劍。
我開始被指派來解決這個(gè)問題。其實(shí)我們很早的就從進(jìn)程的堆棧跟蹤里知道這個(gè)問題是死鎖問題,但是,它是怎么發(fā)生的那,我們幾乎排查了整個(gè)系統(tǒng)的代碼,但是一無所獲。。。
在今年大年初一的時(shí)候,我們的系統(tǒng)又一次出現(xiàn)了該問題,當(dāng)接到我們維護(hù)工程師的電話的時(shí)候,我的心情非常的沉重,我沒有做到我作為一個(gè)程序員應(yīng)有的職責(zé),還是象往常一樣,除了進(jìn)程堆棧跟蹤外,我沒有任何其它線索,我還是照例接收郵件,查看我們維護(hù)工程師發(fā)回來的堆棧跟蹤記錄,可能是過年放假在家里休息了一段時(shí)間的緣故,腦袋好像特別清醒,面對堆棧跟蹤記錄,結(jié)合源碼,我迅速的意識(shí)到造成死鎖的原因是經(jīng)典的競態(tài)條件問題,是一個(gè)進(jìn)程準(zhǔn)備退出的時(shí)候,它會(huì)喚醒它里面的一個(gè)線程,該線程首先會(huì)獲得一個(gè)鎖,進(jìn)行后續(xù)出來,然后解鎖退出,但是由于該進(jìn)程的主線程沒有采用任何方式來等待該線程的退出,而是直接通過return的方式進(jìn)行了退出,我們知道,當(dāng)主線程退出的時(shí)候,操作系統(tǒng)會(huì)直接終止該進(jìn)程里面的其它線程,不會(huì)留任何機(jī)會(huì)讓那個(gè)線程做退出處理。而那個(gè)線程可能恰恰剛剛獲的了鎖,而還沒來得及解鎖,就被扼殺了,于是就造成了其它進(jìn)程或線程再加這個(gè)鎖的時(shí)候,就會(huì)被阻塞,系統(tǒng)死鎖問題也就浮現(xiàn)了出來。
當(dāng)然,我知道了是競態(tài)條件問題造成了死鎖,就會(huì)通過pthread_join來同步等待那個(gè)線程退出,來消除這個(gè)競態(tài)條件,也就消除了死鎖,問題其實(shí)也就解決了。但是,我們有沒有辦法來消除由于一個(gè)鎖的owner沒有釋放該鎖,就死掉了,其它線程再加這個(gè)鎖的時(shí)候而造成的死鎖問題那?
關(guān)于上面這個(gè)問題,我曾經(jīng)在chinaunix請教過很多人,有的人想通過一個(gè)網(wǎng)絡(luò)鎖(就是加鎖、解鎖都要訪問網(wǎng)絡(luò)上的一臺(tái)機(jī)器)來解決,但是這些方法都不成熟,也很復(fù)雜,也好像有高手對這個(gè)問題不屑。我通過搜集很多資料發(fā)現(xiàn),原來解決這個(gè)問題非常的簡單,簡單的不能在簡單了。
在很多系統(tǒng)上,當(dāng)一個(gè)鎖的owner沒有釋放該鎖,就退出了,那么默認(rèn)的方式就是其它線程再去加這個(gè)鎖的時(shí)候,就會(huì)阻塞,造成死鎖。而通過不同的屬性初始化這個(gè)鎖,我們能夠改變這種默認(rèn)的方式:
pthread_mutexattr_setprotocol(&mattr, PTHREAD_PRIO_INHERIT);
pthread_mutexattr_setrobust_np(&mattr,PTHREAD_MUTEX_ROBUST_NP);
通過設(shè)置鎖的上面兩個(gè)屬性,我們就改變了默認(rèn)的行為,當(dāng)一個(gè)鎖的owner死掉后,其它線程再去加這個(gè)鎖的時(shí)候,不會(huì)被阻塞,而是通過返回值EOWNERDEAD來報(bào)告錯(cuò)誤,那么你可以根據(jù)這個(gè)錯(cuò)誤來進(jìn)行處理:首先是應(yīng)該調(diào)用pthread_mutex_consistent_np函數(shù)來恢復(fù)該鎖的一致性,然后調(diào)用解鎖pthread_mutex_unlock,接下來在調(diào)用加鎖,這樣該鎖的行為就恢復(fù)正常了。如果上面這個(gè)函數(shù)在恢復(fù)鎖的一致性時(shí)候沒有成功,那么你只需要調(diào)用解鎖函數(shù)就OK了,然后直接返回,而不要去調(diào)用加鎖函數(shù),那么接下來的線程在調(diào)用加鎖函數(shù)的時(shí)候,會(huì)得到返回值ENOTRECOVERABLE,那么需要你做的就是調(diào)用pthread_mutex_destroy來destroy掉該鎖,然后重新用鎖的屬性和鎖的初始化函數(shù)來重新初始化該鎖。
上面的這些解決死鎖方式比較適合在系統(tǒng)中只有一個(gè)鎖的情況,如果系統(tǒng)的死鎖是由于多把鎖的資源互相等待而造成的,那么這種解決方式無能為力。。。
注:上面有一些函數(shù)后面有np后綴的,表示not portable,就是不可移值的意思,這些函數(shù)是一些系統(tǒng)自己實(shí)現(xiàn)的,而不是POSIX標(biāo)準(zhǔn)。
關(guān)鍵了:程序、系統(tǒng)、POSIX
新文章:
- CentOS7下圖形配置網(wǎng)絡(luò)的方法
- CentOS 7如何添加刪除用戶
- 如何解決centos7雙系統(tǒng)后丟失windows啟動(dòng)項(xiàng)
- CentOS單網(wǎng)卡如何批量添加不同IP段
- CentOS下iconv命令的介紹
- Centos7 SSH密鑰登陸及密碼密鑰雙重驗(yàn)證詳解
- CentOS 7.1添加刪除用戶的方法
- CentOS查找/掃描局域網(wǎng)打印機(jī)IP講解
- CentOS7使用hostapd實(shí)現(xiàn)無AP模式的詳解
- su命令不能切換root的解決方法
- 解決VMware下CentOS7網(wǎng)絡(luò)重啟出錯(cuò)
- 解決Centos7雙系統(tǒng)后丟失windows啟動(dòng)項(xiàng)
- CentOS下如何避免文件覆蓋
- CentOS7和CentOS6系統(tǒng)有什么不同呢
- Centos 6.6默認(rèn)iptable規(guī)則詳解