Linux之信號(hào)的保存方式
文章目錄 信號(hào)相關(guān)概念信號(hào)遞達(dá)信號(hào)未決信號(hào)阻塞內(nèi)核中的示意圖 信號(hào)集的操作函數(shù)
前面對(duì)于信號(hào)的產(chǎn)生中對(duì)操作系統(tǒng)有了一個(gè)基礎(chǔ)的認(rèn)知,對(duì)于一個(gè)真正的操作系統(tǒng)來(lái)說(shuō),進(jìn)程是由操作系統(tǒng)進(jìn)行調(diào)度的,那操作系統(tǒng)本身也是代碼,是由誰(shuí)進(jìn)行調(diào)度的?
實(shí)際上是有一個(gè)CMOS時(shí)鐘這樣的硬件,通過(guò)特定的時(shí)鐘周期不斷地向CPU發(fā)送并觸發(fā)時(shí)鐘中斷,那么在觸發(fā)時(shí)鐘中斷的時(shí)候,實(shí)際上操作系統(tǒng)的內(nèi)部已經(jīng)綁定好了對(duì)應(yīng)的調(diào)度方法,所以在操作系統(tǒng)啟動(dòng)的時(shí)候,就會(huì)提前把觸發(fā)的工作做好,在啟動(dòng)之后就會(huì)變成一個(gè)死循環(huán)的軟件,這也就解釋了為什么在啟動(dòng)了之后,操作系統(tǒng)雖然是軟件,但是卻不會(huì)關(guān)機(jī),只有當(dāng)電腦關(guān)機(jī)后操作系統(tǒng)才會(huì)關(guān)機(jī)的原因,就是因?yàn)樗举|(zhì)上就是一個(gè)死循環(huán),所以基于中斷,一旦對(duì)應(yīng)的時(shí)鐘周期到了,就會(huì)執(zhí)行時(shí)鐘中斷對(duì)應(yīng)的方法,也就有了調(diào)度的方法,基于這樣的進(jìn)度就可以把進(jìn)程按照時(shí)間的節(jié)奏一步一步的走起來(lái)
其實(shí)換個(gè)角度來(lái)講,操作系統(tǒng)其實(shí)是一卡一卡的執(zhí)行的,因?yàn)樗趫?zhí)行中間的這個(gè)時(shí)間間隔就是發(fā)送時(shí)鐘中斷的時(shí)間間隔,時(shí)鐘中斷的這個(gè)時(shí)間其實(shí)就是提醒操作系統(tǒng)去執(zhí)行對(duì)應(yīng)的調(diào)度方法,同時(shí)在中斷向量表中還會(huì)綁定一些硬件對(duì)應(yīng)的操作方法,所以最后得出的結(jié)論是,操作系統(tǒng)實(shí)際上是由硬件促使操作系統(tǒng)跑起來(lái)的
有了上述的思想認(rèn)知,再進(jìn)行對(duì)于進(jìn)程信號(hào)產(chǎn)生的回顧,進(jìn)程的信號(hào)產(chǎn)生是由操作系統(tǒng)寫(xiě)入到進(jìn)程中,相當(dāng)于是操作系統(tǒng)向進(jìn)程發(fā)送信號(hào),而在前面的認(rèn)知中知道,進(jìn)程對(duì)于信號(hào)的處理也并非是及時(shí)處理,而可能會(huì)保存到某個(gè)位置,在合適的時(shí)候進(jìn)行處理,那么現(xiàn)在接下來(lái)的話題就是,這個(gè)信號(hào)會(huì)如何進(jìn)行存儲(chǔ),存儲(chǔ)之后又該如何進(jìn)行處理呢?
信號(hào)相關(guān)概念
信號(hào)遞達(dá)
第一個(gè)問(wèn)題是,信號(hào)會(huì)被記錄存儲(chǔ)在哪里,結(jié)論是會(huì)被存儲(chǔ)到PCB中的位圖中,這個(gè)是之前就已經(jīng)有的結(jié)論,每一個(gè)進(jìn)程的PCB中都會(huì)有一個(gè)用來(lái)描述進(jìn)程接受的信號(hào)的位圖,借助這個(gè)位圖就可以獲取到該進(jìn)程收到了什么信號(hào)
接下來(lái)的問(wèn)題是關(guān)于處理信號(hào)及其相關(guān)概念:
- 實(shí)際執(zhí)行信號(hào)的處理動(dòng)作稱為信號(hào)遞達(dá)
- 信號(hào)從產(chǎn)生到遞達(dá)之間的狀態(tài),稱為信號(hào)未決
- 進(jìn)程可以選擇阻塞某個(gè)信號(hào)
- 被阻塞的信號(hào)產(chǎn)生時(shí)將保持在未決狀態(tài),直到進(jìn)程解除對(duì)此信號(hào)的阻塞,才執(zhí)行遞達(dá)的動(dòng)作
注意,阻塞和忽略是不同的,只要信號(hào)被阻塞就不會(huì)遞達(dá),而忽略是在遞達(dá)之后可選的一種處理動(dòng)作
下面基于這幾個(gè)名詞進(jìn)行解釋?zhuān)紫冉忉尩男盘?hào)遞達(dá)
所謂信號(hào)遞達(dá),說(shuō)的是當(dāng)進(jìn)程收到一個(gè)信號(hào)后,它需要在合適的時(shí)候處理這個(gè)信號(hào),而這里的處理信號(hào)這個(gè)過(guò)程就叫做信號(hào)的遞達(dá),簡(jiǎn)單來(lái)說(shuō)可以理解成,已經(jīng)收到這個(gè)信號(hào),并且準(zhǔn)備處理這個(gè)信號(hào)了,這個(gè)處理的動(dòng)作就叫做信號(hào)遞達(dá)
在前面的內(nèi)容中提到過(guò),對(duì)于信號(hào)的處理有三種方式,第一種叫做忽略,第二種是默認(rèn),第三種是自定義捕捉,這其實(shí)就是說(shuō)信號(hào)遞達(dá)的問(wèn)題,當(dāng)信號(hào)遞達(dá)后,也就是說(shuō)此時(shí)信號(hào)已經(jīng)要進(jìn)行處理了,那么有上述的三種處理方式
給出下面的參考代碼
void handler(int signo) { cout << "收到了" << signo << "號(hào)信號(hào)" << endl; } int main() { cout << "pid:" << getpid() << endl; signal(2, handler); while (true) ; return 0; }
此時(shí)對(duì)進(jìn)程發(fā)送2號(hào)信號(hào),那么對(duì)應(yīng)的這個(gè)進(jìn)程就會(huì)調(diào)用自定義的處理方式,對(duì)應(yīng)的結(jié)果也符合預(yù)期,這個(gè)過(guò)程就是一個(gè)自定義捕捉的過(guò)程
SIG_DFL和SIG_IGN
void handler(int signo) { cout << "收到了" << signo << "號(hào)信號(hào)" << endl; } int main() { cout << "pid:" << getpid() << endl; signal(2, handler); signal(3, SIG_IGN); signal(4, SIG_DFL); while (true) ; return 0; }
上面的兩個(gè)選項(xiàng)也是一種處理方式,可能這里會(huì)有疑問(wèn),為什么自定義函數(shù)的能和宏放到一起呢?signal函數(shù)的第二個(gè)參數(shù)可是函數(shù)指針
其實(shí)在內(nèi)部,是通過(guò)強(qiáng)轉(zhuǎn)轉(zhuǎn)換而來(lái)的,也是把一個(gè)宏對(duì)應(yīng)的內(nèi)容轉(zhuǎn)換成了函數(shù)指針類(lèi)型
在這當(dāng)中需要理清的一個(gè)邏輯是,在這當(dāng)中是有三種處理方式,忽略默認(rèn)自定義捕捉,這個(gè)忽略該如何理解?
忽略也算是處理
忽略也算處理,現(xiàn)在進(jìn)程收到了一個(gè)信號(hào),那它該如何處理它呢?
答案是不處理,不處理就是忽略了這個(gè)信號(hào),所以說(shuō)忽略本質(zhì)上也算是三種處理方式中的一種,處理方式就是不管這個(gè)信號(hào),忽略它
所以之后對(duì)于信號(hào)處理的三種方式,默認(rèn)自定義忽略,這三種處理方式有了一個(gè)統(tǒng)一的名字就叫做信號(hào)遞達(dá),信號(hào)處理這個(gè)名詞也會(huì)被信號(hào)遞達(dá)這個(gè)概念所代替
信號(hào)未決
下面講述的概念是信號(hào)未決,信號(hào)未決通俗來(lái)講就是信號(hào)從產(chǎn)生到遞達(dá)這個(gè)階段的狀態(tài)就叫做信號(hào)未決,可以這樣理解,就是信號(hào)暫時(shí)還沒(méi)有被決定該如何處理,這個(gè)就叫做信號(hào)未決,就是說(shuō)信號(hào)此時(shí)已經(jīng)有了,但是還沒(méi)有處理,在這個(gè)階段的狀態(tài)就叫做信號(hào)未決,這也是可以理解的內(nèi)容,因?yàn)樵谶@個(gè)時(shí)間內(nèi)進(jìn)程可能在做更重要的事,還不能對(duì)這個(gè)信號(hào)做出處理,所以此時(shí)就要求需要對(duì)這個(gè)進(jìn)程有一定的保存能力,在保存信號(hào)的方面可以采用一個(gè)位圖來(lái)進(jìn)行保存普通信號(hào),所以在信號(hào)產(chǎn)生到遞達(dá)之間的狀態(tài),就叫做信號(hào)未決
換句話說(shuō),信號(hào)未決就是從產(chǎn)生到遞達(dá)這樣的一個(gè)狀態(tài),當(dāng)信號(hào)產(chǎn)生的時(shí)候就要把它保存起來(lái),遞達(dá)就要把信號(hào)處理掉,但是信號(hào)的處理不是立刻處理的,在這個(gè)過(guò)程中就是說(shuō)信號(hào)是未決的
信號(hào)阻塞
這是一個(gè)新的概念,叫做阻塞,那如何理解阻塞呢?
阻塞簡(jiǎn)單來(lái)講就是說(shuō)某一個(gè)信號(hào)可以被阻塞,也有一種說(shuō)法叫做被阻塞的信號(hào)可以保持在一個(gè)未決的狀態(tài)中,直到進(jìn)程解除對(duì)于該信號(hào)的阻塞才會(huì)調(diào)用對(duì)應(yīng)的執(zhí)行動(dòng)作。
阻塞的含義可以理解為,信號(hào)產(chǎn)生后會(huì)保存到對(duì)應(yīng)的位圖中,此時(shí)信號(hào)所處的狀態(tài)就是信號(hào)未決,信號(hào)未決后,如果該信號(hào)被阻塞,那么這個(gè)信號(hào)就會(huì)一直保持未決的狀態(tài),直到這個(gè)信號(hào)解除阻塞
忽略和阻塞
忽略是信號(hào)處理中的一種,也就是說(shuō)信號(hào)遞達(dá)中包含忽略這種處理方式,而信號(hào)阻塞是導(dǎo)致不能夠信號(hào)遞達(dá)的一個(gè)原因,這兩個(gè)概念是不一樣的。
信號(hào)忽略是說(shuō),這個(gè)信號(hào)被忽略了,對(duì)于該信號(hào)的處理方式是忽略,而信號(hào)阻塞是壓根不處理這個(gè)信號(hào),這個(gè)信號(hào)一直處于產(chǎn)生到遞達(dá)這樣的一個(gè)階段中,處于未決狀態(tài),這兩個(gè)是截然不同的兩個(gè)概念,這也是可以理解的
信號(hào)是未決的,該信號(hào)一定被阻塞?
顯然是不對(duì)的,信號(hào)是未決的,可能是出于阻塞狀態(tài),但是也可能是因?yàn)檫@個(gè)進(jìn)程正在做更重要的事,所以它暫時(shí)沒(méi)有被處理,處于未決狀態(tài),但是當(dāng)這個(gè)進(jìn)程做完了當(dāng)前最重要的事,那么它一定會(huì)立刻對(duì)信號(hào)進(jìn)行處理,此時(shí)就不再是信號(hào)未決的狀態(tài)了
內(nèi)核中的示意圖
上圖表示的是,在進(jìn)程的PCB中存儲(chǔ)的關(guān)于信號(hào)的結(jié)構(gòu)信息,在PCB中關(guān)于信號(hào)會(huì)維護(hù)三張表,分別存儲(chǔ)的是信號(hào)的阻塞情況,表示有哪些信號(hào)被阻塞了,也存儲(chǔ)了信號(hào)的未決情況,表示有哪些信號(hào)此時(shí)遞達(dá)了,但是還沒(méi)有處理,也存儲(chǔ)了信號(hào)對(duì)應(yīng)的處理方式,表示信號(hào)對(duì)應(yīng)的處理方式是什么,默認(rèn)忽略或是自定義捕捉
在內(nèi)核源碼中,對(duì)于上述這三張表的定義也總結(jié)如下,可以看到對(duì)應(yīng)的handler處理方法中存儲(chǔ)了對(duì)應(yīng)的函數(shù)指針,表示的就是不同信號(hào)的處理方式:
由此,對(duì)于信號(hào)的存儲(chǔ)有了一個(gè)更深層次的理解,為什么進(jìn)程可以識(shí)別到信號(hào),本質(zhì)上來(lái)說(shuō)就是對(duì)于幾號(hào)信號(hào)在pending位圖中已經(jīng)存儲(chǔ)好了,幾號(hào)信號(hào),是否阻塞,對(duì)應(yīng)的解決方式,都在三張表中有具體的體現(xiàn),根據(jù)數(shù)組的下標(biāo)就能很輕松的獲取到對(duì)應(yīng)的存儲(chǔ)情況和處理方式,在操作系統(tǒng)運(yùn)行的時(shí)候,最起碼的pending表和handler表是已經(jīng)存儲(chǔ)好的,所以才有上述的這一套邏輯
而對(duì)于block表來(lái)說(shuō),也有一些不同的理解:
那這個(gè)block表該如何理解呢?
block表,表示的是對(duì)特定信號(hào)的屏蔽,也可以說(shuō)是對(duì)一些信號(hào)的阻塞,換句話說(shuō),這個(gè)位圖和后面的兩個(gè)位圖是完全一樣的位圖結(jié)構(gòu),有了一個(gè)信號(hào),就先在pending位圖中記錄下這個(gè)信號(hào)已經(jīng)處于未決狀態(tài)了,再在合適的時(shí)機(jī)去到block位圖中尋找,如果這個(gè)信號(hào)沒(méi)有被阻塞,那么就執(zhí)行handler表中的方法,如果這個(gè)信號(hào)被block阻塞了,那么就讓這個(gè)信號(hào)一直處于pending的狀態(tài),等block表中什么時(shí)候恢復(fù)了,再去執(zhí)行,當(dāng)然這當(dāng)中還有邊角的問(wèn)題,比如誰(shuí)先置1和置0的問(wèn)題,后續(xù)會(huì)進(jìn)行相關(guān)的實(shí)驗(yàn)
正是因?yàn)橛辛诉@三張表,所以對(duì)于信號(hào)的操作其實(shí)都是圍繞這三張表進(jìn)行展開(kāi)的,比如對(duì)于PCB來(lái)說(shuō),這三張表是由操作系統(tǒng)提供的,那么操作系統(tǒng)就會(huì)想辦法去獲取并設(shè)置修改block表來(lái)表示對(duì)于一個(gè)或多個(gè)信號(hào)的屏蔽的目的,也可以比如說(shuō)是對(duì)于pending位圖做修改,或是獲取pending位圖,比如在之前的bash中的kill命令,本質(zhì)上就是向指定的進(jìn)程中寫(xiě)入信號(hào),實(shí)際上就是在對(duì)這個(gè)pending表進(jìn)行的寫(xiě)入工作,而在之前的signal這樣的自定義捕捉函數(shù),本質(zhì)上也是在修改handler對(duì)應(yīng)的表,這也和前面的知識(shí)進(jìn)行了一定的串聯(lián)
由此可以看出,操作系統(tǒng)提供對(duì)應(yīng)的系統(tǒng)調(diào)用,就是對(duì)于這三張表的修改過(guò)程,但是這還不夠,用戶該如何去修改?直接深入到內(nèi)核中去修改位圖中比特位的情況,這對(duì)于用戶來(lái)說(shuō)是一個(gè)很大的挑戰(zhàn),同時(shí)對(duì)于操作系統(tǒng)來(lái)說(shuō)也違背了它設(shè)計(jì)的初衷,因此操作系統(tǒng)還會(huì)提供對(duì)應(yīng)修改位圖的方法,提供了一些新的數(shù)據(jù)類(lèi)型,用來(lái)幫助用戶對(duì)于這三張表實(shí)現(xiàn)一些操作更改等
多信號(hào)問(wèn)題
現(xiàn)在保存的信號(hào)用pending位圖表示是否收到了這個(gè)信號(hào),但是這個(gè)進(jìn)程可能會(huì)在很短的時(shí)間內(nèi)同時(shí)收到信號(hào),這個(gè)時(shí)間短到可能不能及時(shí)處理這個(gè)信號(hào),在相當(dāng)短的時(shí)間內(nèi),連續(xù)收到了多個(gè)同一個(gè)信號(hào),pending位圖中只能記錄一次,換句話說(shuō),此時(shí)可能發(fā)送了10個(gè)相同的信號(hào),但是只記錄了一次,剩下的九次就相當(dāng)于直接被操作系統(tǒng)丟棄了,本質(zhì)上來(lái)說(shuō)是比特位只能是0和1,如果不斷的從1變成1,實(shí)際上也獲得不了什么新的效果,只能保存歷史上最近的一次封信,所以在進(jìn)程解除對(duì)于某個(gè)信號(hào)的阻塞之前,可能這個(gè)信號(hào)已經(jīng)被發(fā)送了很多次了,只是不能進(jìn)行獲取,不管發(fā)送多少次,最終都是一次
因此操作系統(tǒng)允許向進(jìn)程推送信號(hào)多次,但是在遞達(dá)之前,不管推送多少次,操作系統(tǒng)只看一次,這是由操作系統(tǒng)本身的位圖結(jié)構(gòu)決定的,不過(guò)這樣情況出現(xiàn)的概率不大,其次是也可以用在信號(hào)處理內(nèi)部放一個(gè)計(jì)數(shù)器,來(lái)表示如果設(shè)定不夠就重新再發(fā),這樣的處理方式也是可以接受的
不過(guò)值得注意的是,這種只記錄一次的信號(hào)叫做普通信號(hào),而與之對(duì)應(yīng)的還有一個(gè)實(shí)時(shí)信號(hào),實(shí)時(shí)信號(hào)在前面的內(nèi)容中也有所涉獵,它的實(shí)時(shí)信號(hào)中的實(shí)時(shí)概念也就體現(xiàn)在在進(jìn)程的PCB中有一個(gè)實(shí)時(shí)的信號(hào)隊(duì)列,每一個(gè)信號(hào)就相當(dāng)于一個(gè)結(jié)構(gòu)體對(duì)象,那么就用隊(duì)列的形式來(lái)管理這種信號(hào),也就叫做實(shí)時(shí)信號(hào),但是這里不考慮實(shí)時(shí)信號(hào),只是對(duì)普通信號(hào)做出一個(gè)基本的理解
信號(hào)集的操作函數(shù)
下面進(jìn)行的模塊就是對(duì)于信號(hào)集的操作函數(shù),下面進(jìn)行一一列舉內(nèi)容:
下圖描述的是對(duì)于信號(hào)的一些函數(shù),根據(jù)這些函數(shù)來(lái)對(duì)于信號(hào)的操作函數(shù)有一個(gè)基本的理解
sigemptyset函數(shù)
這個(gè)函數(shù)的主要作用是對(duì)于set所指向的操作集進(jìn)行一個(gè)基本的初始化,簡(jiǎn)單來(lái)說(shuō)就是把比特位置0,并且這當(dāng)中不應(yīng)該有任何有效的信號(hào)
sigfillset函數(shù)
這個(gè)函數(shù)的主要作用是把信號(hào)集都置為1,表示這當(dāng)中存儲(chǔ)的是有效的信號(hào)
sigaddset和sigdelset函數(shù)
這兩個(gè)函數(shù)是對(duì)于信號(hào)的增加和刪除
sigismember函數(shù)
這個(gè)函數(shù)是用來(lái)查詢某個(gè)函數(shù)是否在當(dāng)前的pending信號(hào)集中,返回值是bool類(lèi)
sigprocmask函數(shù)
這個(gè)函數(shù)是用來(lái)讀取或更改進(jìn)程的信號(hào)屏蔽字,也就是阻塞信號(hào)集,而這個(gè)后面的參數(shù),一個(gè)是用什么方法來(lái)傳遞,后面的兩個(gè)參數(shù)都是對(duì)應(yīng)的信號(hào)集,簡(jiǎn)單來(lái)說(shuō)就是通過(guò)參數(shù)來(lái)覆蓋當(dāng)前的信號(hào)集
對(duì)于第一個(gè)參數(shù)來(lái)說(shuō),它有下面的幾種方式進(jìn)行傳遞
SIG_BLOCK
這個(gè)操作會(huì)把當(dāng)前信號(hào)阻塞集合和set所指向的信號(hào)集合取并集,簡(jiǎn)單來(lái)說(shuō)是把set集合加入到當(dāng)前的信號(hào)阻塞集合中
SIG_SETMASK
這個(gè)操作會(huì)把當(dāng)前信號(hào)阻塞集合設(shè)置為set所指向的信號(hào)集合,會(huì)把當(dāng)前集合直接覆蓋掉
SIG_UNBLOCK
這個(gè)操作是把當(dāng)前信號(hào)阻塞集合與set集合中的信號(hào)的補(bǔ)集取交集,簡(jiǎn)單來(lái)說(shuō)就是把set中的信號(hào)進(jìn)行解除
后面的兩個(gè)參數(shù)值得注意一下,一個(gè)是set,一個(gè)是oset,這兩個(gè)參數(shù)是有其對(duì)應(yīng)的意義的,第一個(gè)set表示的是要傳入覆蓋的對(duì)應(yīng)的位圖是什么樣的,第二個(gè)oset是一個(gè)輸出型參數(shù),它保存的是當(dāng)前位圖的情況,所以本質(zhì)上來(lái)說(shuō)可以理解成是一個(gè)保存了前面位圖的參數(shù),這樣可以方便后續(xù)進(jìn)行恢復(fù)等等操作,具體的后續(xù)進(jìn)行使用
代碼實(shí)踐
下面用代碼實(shí)踐來(lái)表示
第一個(gè)要完成的動(dòng)作是把2號(hào)信號(hào)加到信號(hào)屏蔽集中,現(xiàn)在有一個(gè)問(wèn)題是,我設(shè)置了加到屏蔽集合中就真的屏蔽了嗎?嚴(yán)格意義來(lái)說(shuō)并不是,因?yàn)檫@些內(nèi)容本質(zhì)上是在棧上開(kāi)辟的空間,所以它本質(zhì)上是在代碼區(qū)域上,并沒(méi)有真正設(shè)置到操作系統(tǒng)中,所以此時(shí)把2號(hào)信號(hào)添加到集合中也只是在棧上修改了一個(gè)變量的信息,這只是語(yǔ)言層面上的設(shè)置,而只有通過(guò)調(diào)用sigprocmask函數(shù)后,才能是真正意義上的進(jìn)行屏蔽的操作,表示的是直接修改了在內(nèi)核中對(duì)于阻塞表的操作,修改了內(nèi)核的字段,不過(guò),從廣義的角度來(lái)講,其實(shí)這樣的操作就被叫做是加入到了內(nèi)核中
這里由于是第一次使用,所以要將語(yǔ)言層面和內(nèi)核層面分開(kāi),再怎么說(shuō)對(duì)于位圖的修改也只是語(yǔ)言層面上,實(shí)際的運(yùn)用中并沒(méi)有進(jìn)行位圖的修改,而只有用sigprocmask函數(shù)之后,才是進(jìn)入內(nèi)核的層面上修改了內(nèi)核中的相應(yīng)字段
寫(xiě)出示例代碼,如下所示
void handler(int signo) { cout << "收到了" << signo << "號(hào)信號(hào)" << endl; } int main() { signal(2, handler); cout << "當(dāng)前pid:" << getpid() << endl; // 1. 屏蔽2號(hào)信號(hào) sigset_t set, oset; sigemptyset(&set); sigemptyset(&oset); sigaddset(&set, 2); sigprocmask(SIG_BLOCK, &set, &oset); while(true) sleep(1); return 0; }
對(duì)上述代碼進(jìn)行運(yùn)行得到如下結(jié)果:
由此可以看出,此時(shí)確實(shí)對(duì)于2號(hào)信號(hào)進(jìn)行了屏蔽效果,只有發(fā)送其他信號(hào)才會(huì)有反應(yīng)
這是由于,經(jīng)過(guò)了sigprocmask之后,此時(shí)的2號(hào)信號(hào)已經(jīng)存儲(chǔ)在了pending表中,那么它此時(shí)就不能再被執(zhí)行了
kill -9
9號(hào)信號(hào)是最特殊的信號(hào),它本身是不能被屏蔽的,它也被叫做管理員信號(hào),也叫做管理員之光,如果有任何進(jìn)程出現(xiàn)問(wèn)題,都可以用kill -9來(lái)殺掉,并且保證這個(gè)信號(hào)不會(huì)被屏蔽
sigpending函數(shù)
這個(gè)函數(shù)的作用也很簡(jiǎn)單,就是讀取當(dāng)前進(jìn)程的pending信號(hào)集,通過(guò)set參數(shù)傳出,調(diào)用成功返回0,失敗返回-1
則可以借助這個(gè)函數(shù)實(shí)現(xiàn)下面的代碼內(nèi)容:
void handler(int signo) { cout << "收到了" << signo << "號(hào)信號(hào)" << endl; } void PrintSignal(const sigset_t &set) { for (int i = 31; i >= 1; i--) { if (sigismember(&set, i)) cout << "1"; else cout << "0"; } cout << endl; } int main() { signal(2, handler); cout << "當(dāng)前pid:" << getpid() << endl; // 1. 屏蔽2號(hào)信號(hào) sigset_t set, oset; sigemptyset(&set); sigemptyset(&oset); sigaddset(&set, 2); sigprocmask(SIG_BLOCK, &set, &oset); // 2. 讓進(jìn)程獲取現(xiàn)在的pending sigset_t pending; while(true) { sigpending(&pending); PrintSignal(pending); sleep(1); } while (true) sleep(1); return 0; }
而想要解除屏蔽也很簡(jiǎn)單,這個(gè)時(shí)候就用上了oset的內(nèi)容:
void handler(int signo) { cout << "收到了" << signo << "號(hào)信號(hào)" << endl; } void PrintSignal(const sigset_t &set) { for (int i = 31; i >= 1; i--) { if (sigismember(&set, i)) cout << "1"; else cout << "0"; } cout << endl; } int main() { signal(2, handler); cout << "當(dāng)前pid:" << getpid() << endl; // 1. 屏蔽2號(hào)信號(hào) sigset_t set, oset; sigemptyset(&set); sigemptyset(&oset); sigaddset(&set, 2); sigprocmask(SIG_BLOCK, &set, &oset); // 2. 讓進(jìn)程獲取現(xiàn)在的pending sigset_t pending; int cut = 0; while (true) { sigpending(&pending); PrintSignal(pending); cut++; sleep(1); if (cut == 5) { // 3. 解除屏蔽 cout << "已解除屏蔽" << endl; sigprocmask(SIG_SETMASK, &oset, nullptr); sigpending(&pending); PrintSignal(pending); sleep(1); } } while (true) sleep(1); return 0; }
由此,信號(hào)的保存也就完成了
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Linux下部署springboot項(xiàng)目的方法步驟
這篇文章主要介紹了Linux下部署springboot項(xiàng)目的方法步驟,由于springboot是內(nèi)嵌了tomcat,所以可以直接將項(xiàng)目打包上傳至服務(wù)器上,具體實(shí)例方法大家參考下本文2018-06-06ubuntu 16.04系統(tǒng)完美解決pip不能升級(jí)的問(wèn)題
這篇文章主要介紹了ubuntu 16.04系統(tǒng)完美解決pip不能升級(jí)的問(wèn)題 ,本文圖文并茂給大家介紹的非常詳細(xì),需要的朋友可以參考下2018-04-04