Linux進(jìn)程信號(hào)的發(fā)送和保存方法
一、信號(hào)發(fā)送
1、信號(hào)動(dòng)作
通過(guò)指令man -7 signal
查看信號(hào)的手冊(cè),然后往下翻翻可以看到普通信號(hào)發(fā)出后對(duì)應(yīng)的操作,以及它們的信號(hào)編號(hào),和詳細(xì)描述信息
2、信號(hào)發(fā)送的本質(zhì)
普通信號(hào)
信號(hào)發(fā)送的本質(zhì)實(shí)際上是寫(xiě)信號(hào),把信號(hào)寫(xiě)到進(jìn)程PCB結(jié)構(gòu)體對(duì)應(yīng)的位圖上去,在進(jìn)程的PCB中有這么一個(gè)位圖(是pending位圖,下面會(huì)說(shuō))正好對(duì)應(yīng)著我們從1 ~ 31的普通信號(hào)編號(hào),收到哪個(gè)信號(hào)就將哪一位對(duì)應(yīng)的比特位置為1,表示收到信號(hào),然后PCB再做對(duì)應(yīng)的工作
值得注意的是,如果連續(xù)發(fā)普通信號(hào),那么進(jìn)程只會(huì)處理最后一次的信號(hào),每次寫(xiě)都是覆蓋寫(xiě)的
實(shí)時(shí)信號(hào)
我們前面說(shuō)過(guò)信號(hào)分為31個(gè)普通信號(hào)和31個(gè)實(shí)時(shí)信號(hào),實(shí)時(shí)信號(hào)的作用類(lèi)似于我們嵌入式RTOS實(shí)時(shí)運(yùn)轉(zhuǎn)場(chǎng)景,要保持實(shí)時(shí)性,實(shí)時(shí)信號(hào)發(fā)送的本質(zhì)類(lèi)似于普通信號(hào),不過(guò)此時(shí)我們保存信號(hào)的載體不再是一個(gè)位圖,而是一個(gè)結(jié)構(gòu)體,它們被組織在信號(hào)隊(duì)列當(dāng)中,誰(shuí)先發(fā)送誰(shuí)就先入隊(duì),隊(duì)列遵循先入先出的規(guī)則,所以先發(fā)送也代表著先被處理
值得注意的是,如果連續(xù)發(fā)實(shí)時(shí)信號(hào),那么進(jìn)程會(huì)將隊(duì)列中的信號(hào)一個(gè)個(gè)全部處理
3、core dump
當(dāng)程序在運(yùn)行過(guò)程中發(fā)生崩潰(如段錯(cuò)誤、除零錯(cuò)誤等),Core dump 會(huì)記錄下程序崩潰瞬間的內(nèi)存狀態(tài),包括寄存器的值、調(diào)用棧信息、全局變量和局部變量的值等,開(kāi)發(fā)人員可以使用調(diào)試工具(如 GDB)加載 Core dump 文件,通過(guò)分析這些信息,準(zhǔn)確地找到程序崩潰的位置和原因
我們可以通過(guò)ulimit -c 10240將core文件的大小限制修改為10240字節(jié),出現(xiàn)錯(cuò)誤的時(shí)候core文件可能瞬間會(huì)被打滿(mǎn)的,所以我們?cè)品?wù)器上一般默認(rèn)core文件的大小限制為0,我們要是用的話(huà)再修改它的大小限制即可
形成的文件叫做core.pid,pid就是出錯(cuò)進(jìn)程的pid,假設(shè)test進(jìn)程出現(xiàn)錯(cuò)誤,12314是它的pid,我們可以通過(guò)在gdb模式下輸入gdb test core.12314打印錯(cuò)誤信息和原因
二、信號(hào)的保存
1、前置概念
實(shí)際執(zhí)行信號(hào)的處理動(dòng)作稱(chēng)為信號(hào)遞達(dá)
信號(hào)從產(chǎn)生到遞達(dá)之間的狀態(tài),稱(chēng)為信號(hào)未決
被阻塞的信號(hào)產(chǎn)生是將保持在未決狀態(tài),直到進(jìn)程解除對(duì)此信號(hào)的阻塞,才執(zhí)行遞達(dá)的動(dòng)作
2、阻塞信號(hào)
信號(hào)被阻塞就是將信號(hào)阻塞在信號(hào)未決狀態(tài),具體實(shí)現(xiàn)阻塞功能的,是一個(gè)位圖block
block
是一個(gè)位圖,共31位,對(duì)應(yīng)1 ~ 31號(hào)信號(hào),當(dāng)對(duì)應(yīng)比特位為1時(shí),表示該編號(hào)信號(hào)被阻塞,為0則表示不阻塞
如果信號(hào)被阻塞則進(jìn)入阻塞態(tài),若沒(méi)有被阻塞那么信號(hào)進(jìn)入未決狀態(tài)
3、保存信號(hào)
未決狀態(tài)的作用就是保存信號(hào),它保存信號(hào)的方式也是通過(guò)位圖pending
pending
也是一個(gè)位圖,與block
一致,對(duì)應(yīng)的下標(biāo)和信號(hào)編號(hào)也是一一對(duì)應(yīng),當(dāng)對(duì)應(yīng)比特位為1時(shí),表示該編號(hào)信號(hào)處于未決狀態(tài),為0則信號(hào)遞達(dá)
實(shí)際上block
和pending
都屬于保存信號(hào),只不過(guò)因?yàn)橛袃蓚€(gè)位圖,我們分開(kāi)來(lái)說(shuō)罷了
4、信號(hào)遞達(dá)
信號(hào)遞達(dá)后的信號(hào),會(huì)執(zhí)行相對(duì)應(yīng)的行為,有SIG_DFL
:默認(rèn)處理動(dòng)作,SIG_IGN
:忽略,和自定義處理sighandler
,這在前面提到過(guò)
5、總結(jié)
一個(gè)信號(hào),首先要經(jīng)過(guò)block,block為0來(lái)到pending,pending為0來(lái)到handler執(zhí)行動(dòng)作,其中,9號(hào)和19號(hào)新號(hào)還是特例,它們是不能被阻塞和保存的,這兩個(gè)信號(hào)一旦發(fā)出就是直接handler,其實(shí)也不用handler了,它們對(duì)應(yīng)的不可能為忽略和信號(hào)捕捉后的自定義函數(shù),只能為默認(rèn)動(dòng)作終止和暫停
三、信號(hào)集操作函數(shù)
信號(hào)集操作函數(shù)顧名思義就是操作信號(hào)集的函數(shù),sigset_t
被稱(chēng)作信號(hào)集,是操作系統(tǒng)提供的數(shù)據(jù)類(lèi)型,用于描述位圖,下面就是信號(hào)集操作函數(shù)
#include <signal.h> int sigemptyset(sigset_t *set); // 將位圖全部設(shè)置為 0 int sigfillset(sigset_t *set); // 將位圖全部都設(shè)置為 1 int sigaddset (sigset_t *set, int signo); // 將位圖中的某一位設(shè)置為 1 int sigdelset(sigset_t *set, int signo); // 將位圖中的某一位設(shè)置為 0 int sigismember(const sigset_t *set, int signo); // 判斷一個(gè)信號(hào)是否在信號(hào)集中,不在返回0,在返回1,出錯(cuò)返回-1
1、設(shè)置block位圖
sigprocmask
是一個(gè)在信號(hào)處理中非常重要的系統(tǒng)調(diào)用,主要用于檢查、修改進(jìn)程的信號(hào)掩碼(阻塞信號(hào)集)
#include <signal.h> int sigprocmask(int how, const sigset_t *set, sigset_t *oset);
返回值:若成功則為0,若出錯(cuò)則為-1
how
:指定對(duì)信號(hào)掩碼的操作方式
how 取值 | 含義 | 示例說(shuō)明 |
---|---|---|
SIG_BLOCK | 將 set 所指向的信號(hào)集中的信號(hào)添加到當(dāng)前的信號(hào)掩碼中,即阻塞 set 中的信號(hào) | 若當(dāng)前信號(hào)掩碼已阻塞 SIGINT ,使用 SIG_BLOCK 并傳入包含 SIGTERM 的信號(hào)集,SIGTERM 也會(huì)被阻塞 |
SIG_UNBLOCK | 從當(dāng)前的信號(hào)掩碼中移除 set 所指向的信號(hào)集中的信號(hào),即解除對(duì) set 中信號(hào)的阻塞 | 若當(dāng)前信號(hào)掩碼阻塞了 SIGINT 和 SIGTERM ,使用 SIG_UNBLOCK 并傳入包含 SIGINT 的信號(hào)集,SIGINT 信號(hào)的阻塞狀態(tài)將被解除 |
SIG_SETMASK | 將當(dāng)前的信號(hào)掩碼設(shè)置為 set 所指向的信號(hào)集,覆蓋原來(lái)的信號(hào)掩碼 | 若原信號(hào)掩碼阻塞 SIGINT ,使用 SIG_SETMASK 并傳入包含 SIGTERM 的信號(hào)集,信號(hào)掩碼將只阻塞 SIGTERM |
set
:指向一個(gè)sigset_t
類(lèi)型的信號(hào)集,該信號(hào)集包含了要操作的信號(hào),如果how
的值為SIG_BLOCK
或SIG_UNBLOCK
,則set
表示要添加或移除的信號(hào)集;如果how
的值為SIG_SETMASK
,則set
表示要設(shè)置的新的信號(hào)掩碼,若該參數(shù)為NULL
,則不改變當(dāng)前的信號(hào)掩碼,僅獲取當(dāng)前信號(hào)掩碼,此時(shí)oset
不能為NULL
oset
:指向一個(gè)sigset_t
類(lèi)型的信號(hào)集,用于存儲(chǔ)調(diào)用sigprocmask
之前的信號(hào)掩碼,如果不需要保存舊的信號(hào)掩碼,可以將該參數(shù)設(shè)置為NULL
2、設(shè)置pending位圖
sigpending
是一個(gè)用于獲取進(jìn)程當(dāng)前未決信號(hào)集的系統(tǒng)調(diào)用
#include <signal.h> int sigpending(sigset_t *set);
返回值:成功返回0,失敗返回-1
set
:sigpending
函數(shù)會(huì)將當(dāng)前進(jìn)程中處于未決狀態(tài)(即已發(fā)送但由于被阻塞而尚未被處理)的信號(hào)集存儲(chǔ)到set
所指向的sigset_t
對(duì)象中
3、設(shè)置handler行為
三種情況,默認(rèn),忽略和自定義,自定義那當(dāng)然是signal
函數(shù),前面有,不再贅述
四、驗(yàn)證信號(hào)保存行為
#include <iostream> #include <signal.h> #include <unistd.h> using namespace std; //打印出位圖 void PrintPending(const sigset_t &pset) { for(int i = 31; i >= 1; i--) { cout << sigismember(&pset, i); } cout << endl; } void handler(int signum) { cout << "catch a signum: " << signum << endl; } int main() { //自定義捕捉2號(hào)信號(hào) signal(2, handler); sigset_t bset, oset; sigemptyset(&bset); // bset信號(hào)集清空 sigemptyset(&oset); // oset信號(hào)集清空 sigaddset(&bset, 2); // 將bset的第2位設(shè)為1,也就是給bset中添加上2號(hào)信號(hào) // 調(diào)用系統(tǒng)調(diào)用,將數(shù)據(jù)設(shè)置進(jìn)內(nèi)核,設(shè)置block,此時(shí)2號(hào)信號(hào)被阻塞 sigprocmask(SIG_SETMASK, &bset, &oset); // 重復(fù)打印當(dāng)前進(jìn)程的 pending 信號(hào)集,期間向進(jìn)程發(fā)送 2號(hào)信號(hào) // 因?yàn)?2號(hào)信號(hào)被阻塞了,所以 2號(hào)信號(hào)會(huì)一直被保存在 pending 中 sigset_t pset; sigemptyset(&pset);// pset信號(hào)集清空 int cnt = 0; //在15秒內(nèi),未接受信號(hào)前,都是一直打印0 while(true) { int n = sigpending(&pset); if(n < 0) continue; //打印位圖 PrintPending(pset); sleep(1); cnt++; if(cnt == 15) { cout << "unblock 2 signo" << endl; // 打印15次位圖后解除阻塞 sigdelset(&bset, 2);//將bset的第2位設(shè)置為0,也就是給bset去除2號(hào)新號(hào),不阻塞2號(hào) //設(shè)置當(dāng)前信號(hào)屏蔽字為oset指向的值,也就是0 sigprocmask(SIG_SETMASK, &oset, nullptr); } } return 0; }
查看一下效果,在3秒后,我按下ctrl+c
,然后我們的捕捉信號(hào)函數(shù)沒(méi)有工作,說(shuō)明信號(hào)被阻塞了,然后15秒后我們自動(dòng)放開(kāi)阻塞,瞬間打印出handler
函數(shù)定義要打印的信息,再按ctrl+c
就正常進(jìn)行handler
行為了
到此這篇關(guān)于Linux進(jìn)程信號(hào)的發(fā)送和保存方法的文章就介紹到這了,更多相關(guān)Linux進(jìn)程信號(hào)發(fā)送和保存內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
apache time_wait連接數(shù)太多問(wèn)題解決方法
這篇文章主要介紹了apache time_wait連接數(shù)太多問(wèn)題解決方法,本文使用調(diào)整內(nèi)核參數(shù)來(lái)解決,需要的朋友可以參考下2014-11-11CentOS服務(wù)器apache綁定多個(gè)域名的方法
這篇文章主要為大家詳細(xì)介紹了CentOS服務(wù)器apache綁定多個(gè)域名的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-11-11windows10 更新Ubuntu20.04 LTS的方法步驟
這篇文章主要介紹了windows10 更新Ubuntu20.04 LTS的方法步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06Linux VPS配置Web網(wǎng)站環(huán)境一鍵包(LNMP/LAMP/LNMPA)
如果我們是資深Linux用戶(hù),可能不屑于網(wǎng)上免費(fèi)Linux Web一鍵包、管理面板的安裝,然后自己編譯或者自由的一套環(huán)境安裝配置環(huán)境。但是,對(duì)于大部分用戶(hù)而言,麥子個(gè)人建議還是選擇較為成熟的WEB一鍵包或者面板安裝環(huán)境2017-02-02cloudera manager 設(shè)置開(kāi)機(jī)自啟的方法
下面小編就為大家?guī)?lái)一篇cloudera manager 設(shè)置開(kāi)機(jī)自啟的方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-01-01Apache?Pulsar集群搭建部署詳細(xì)過(guò)程
這篇文章主要介紹了Apache?Pulsar集群搭建過(guò)程,搭建Pulsar集群至少需要3個(gè)組件:ZooKeeper集群、BookKeeper集群和Broker集群,本文給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-02-02Xshell實(shí)現(xiàn)Windows上傳文件到Linux主機(jī)的方法
這篇文章主要介紹了Xshell實(shí)現(xiàn)Windows上傳文件到Linux主機(jī)的方法,需要的朋友可以參考下2017-12-12