使用System V信號(hào)量不是那么熟練. 寫了一個(gè)Monitor監(jiān)測線程, 一個(gè)實(shí)際執(zhí)行的Product線程.
本來的想法兩個(gè)線程一個(gè)一個(gè)的調(diào), 但是我忘了把另外一個(gè)線程注釋掉了.然后坑就這么產(chǎn)生了.
先看Monitor代碼:
然后gdb去調(diào)試的時(shí)候, 總是出現(xiàn)
我一開始以為我的程序出錯(cuò)了, 因?yàn)槲襍ystem V信號(hào)量用的不是很熟練, 但是我發(fā)現(xiàn)我寫的沒有錯(cuò)呀, 都是這樣用的呀. 一番查找下, 我就確定我這樣用是沒錯(cuò)的, 就去Google了一下, 發(fā)現(xiàn)了真相.
原來GDB在調(diào)試的時(shí)候是會(huì)發(fā)生這種情況的.具體的內(nèi)容自己查看
GDB 引起Interrupted system call原因:
- 必須是多線程
- 其中一個(gè)線程必須因?yàn)閟ystem call阻塞(例如程序中的semop)
- 而另外一個(gè)程序由于斷點(diǎn)或者其他什么原因, 就會(huì)引起正在阻塞的線程提前結(jié)束
文檔中還說明了, GDB使用內(nèi)核中斷的方式監(jiān)測線程庫, 例如線程的創(chuàng)建财剖、銷毀等情況. 如果當(dāng)這些情況發(fā)生時(shí),盡管程序在我們的預(yù)想中不能結(jié)束, 但是系統(tǒng)調(diào)用可能提前結(jié)束, 就導(dǎo)致出現(xiàn)Interrupted system call
盡管文檔沒有詳細(xì)說明引起的原因, 但是已經(jīng)夠了. 我知道了我的程序出錯(cuò)的原因, 我把另外一個(gè)線程注釋掉, 然后再調(diào)這個(gè)線程, 這沒有這個(gè)問題發(fā)生了.
PS:如果不注釋掉另外一個(gè)線程, 但是不用GDB去跑, 也不會(huì)發(fā)生Interrupted system call, 這和文檔說明的情況是一樣的.
add:2016-9-22
今天才發(fā)現(xiàn)原來《UNIX網(wǎng)絡(luò)編程--進(jìn)程間通信》[P230]中也有說明
"當(dāng)一個(gè)線程被投入睡眠以等待某個(gè)信號(hào)量操作完成之時(shí)(我們將看到該線程既可以等待改信號(hào)量的值變?yōu)?, 也可等待它變?yōu)榇笥?), 如果它捕獲了一個(gè)信號(hào), 那么其信號(hào)處理程序的返回將中斷引起睡眠的semop函數(shù), 該函數(shù)于是返回一個(gè)EINTR錯(cuò)誤.按照UNPv1的術(shù)語定義, semop是需被所捕獲的信號(hào)中斷的慢系統(tǒng)調(diào)用"
解決方法:
解決方法其實(shí)很簡單,就是我們要接受一下Interrupted system call(EINTR)信號(hào)就可以了
比如上面的代碼,修改如下
semop用法
int semop(int semid, struct sembuf *opstr, size_t nops)
semval: 信號(hào)量當(dāng)前值
struct sembuf { short sem_num; short sem_op; sem_flag; }
- sem_op是正數(shù), 其值就加到semval上, 對應(yīng)于釋放由某個(gè)信號(hào)控制的資源
- sem_op是0, 如果調(diào)用者希望等待到semval為0, 如果semval已經(jīng)是0, 那么立即返回; 如果semval不為0, 調(diào)用線程則被阻塞到semval變?yōu)?
- 如果sem_op是負(fù)數(shù),那么調(diào)用者希望等待semval變?yōu)榇笥诨蛘叩扔趕emop的絕對值.
- 如果semval大于或者等于sem_op的絕對值, 那就從semval中減掉sem_op的絕對值.
- 如果semval小于sem_op的絕對值, 那么調(diào)用線程就阻塞到semval變?yōu)榇笥诨蛘叩扔趕em_op的絕對值. 到線程解除阻塞, 還將從semval中減掉sem_op的絕對值.
代碼
有關(guān)詳細(xì)封裝的代碼請查看我的github