Linux信號機(jī)制

理論部分

簡單來說

信號是用來通知進(jìn)程發(fā)生了異步事件

比如标捺,在終端運(yùn)行程序氛堕,按下ctrl+c就產(chǎn)生一個(gè)中端信號顾瞪,大概過程是這樣的:

  • 用戶從shell下啟動(dòng)一個(gè)進(jìn)程掷邦;
  • 用戶按下ctrl+c汪诉,產(chǎn)生一個(gè)硬件中端信號废恋;
  • cpu從用戶態(tài)切換到進(jìn)程態(tài),處理中端扒寄;(這個(gè)過程當(dāng)年讀書的時(shí)候在《計(jì)算機(jī)組成原理》看過)
  • 終端驅(qū)動(dòng)程序?qū)trl+c解釋成一個(gè)SIGINT信號鱼鼓,記在該進(jìn)程的PCB中(也可以說發(fā)送了一個(gè)SIGINT信號給該進(jìn)程)。
  • 當(dāng)某個(gè)時(shí)刻要從內(nèi)核返回到該進(jìn)程的用戶空間代碼繼續(xù)執(zhí)行之前,首先處理PCB中記錄的信號该编,發(fā)現(xiàn)有一個(gè)SIGINT信號待處理迄本,而這個(gè)信號的默認(rèn)處理動(dòng)作是終止進(jìn)程,所以直接終止進(jìn)程而不再返回它的用戶空間代碼執(zhí)行课竣。

前臺(tái)進(jìn)程在運(yùn)行過程中用戶隨時(shí)可能按下ctrl+c而產(chǎn)生一個(gè)信號嘉赎,也就是說該進(jìn)程的用戶空間代碼執(zhí)行到任何地方都有可能收到SIGINT信號而終止,所以信號相對于進(jìn)程的控制流程來說是異步的于樟。

kill -l 可以查看系統(tǒng)定義的信號公条,這些定義是在signal.h中。

1.png

也可以通過man 7 signal來查看迂曲。

2.png

其中Action代表默認(rèn)處理動(dòng)作靶橱,

Term : 終止當(dāng)前進(jìn)程
Core : 終止并且Core Dump
Ing   : 忽略
Stop : 停止當(dāng)前進(jìn)程
Cont: 繼續(xù)執(zhí)行先前停止的進(jìn)程

注:當(dāng)一個(gè)進(jìn)程要異常終止時(shí),可以選擇把進(jìn)程的用戶空間內(nèi)存數(shù)據(jù)全部保存到磁盤上路捧,文件名通常是core关霸,這叫做Core Dump。

產(chǎn)生信號的條件主要是:

  • 終端的按鍵鬓长,如ctrl+c產(chǎn)生SIGINT信號谒拴,ctrl+\產(chǎn)生SIGQUIT信號,ctrl+z產(chǎn)生SIGTSTP信號涉波。
  • 硬件異常產(chǎn)生信號英上。
  • 一個(gè)進(jìn)程調(diào)用kill (man 2 kill) 可以發(fā)送信號給另一個(gè)進(jìn)程炭序。
  • 可以調(diào)用kill (man 1 kill)。
  • 當(dāng)內(nèi)核檢測到某種軟件條件發(fā)生時(shí)也可以通過信號通知進(jìn)程苍日,例如鬧鐘超時(shí)產(chǎn)生SIGALRM信號惭聂,向讀端已關(guān)閉的管道寫數(shù)據(jù)時(shí)產(chǎn)生SIGPIPE信號。

用戶程序可以調(diào)用sigaction(man 2 sigaction)函數(shù)告訴內(nèi)核如何處理某種信號相恃,可選的操作有

  • 忽略
  • 執(zhí)行默認(rèn)動(dòng)作
  • 提供一個(gè)信號處理函數(shù)辜纲,要求內(nèi)核在處理該信號時(shí)切換到用戶態(tài)執(zhí)行這個(gè)處理函數(shù),這種方式稱為捕捉一個(gè)信號拦耐。

發(fā)送信號可以用:

#include <signal.h> 
int kill(pid_t pid, int signo);//向其他進(jìn)程發(fā)信號
int raise(int signo);//向自己發(fā)信號

#include <stdlib.h>
void abort(void);//使當(dāng)前進(jìn)程接收到SIGABRT信號而異常終止

#include <unistd.h>
unsigned int alarm(unsigned int seconds);//內(nèi)核在seconds秒之后給當(dāng)前進(jìn)程發(fā)SIGALRM信號

信號從產(chǎn)生到遞達(dá)之間的狀態(tài)耕腾,稱為信號未決。
每個(gè)信號都有兩個(gè)標(biāo)志位分別表示阻塞和未決杀糯,還有一個(gè)函數(shù)指針表示處理動(dòng)作

信號集操作函數(shù)

sigset_t類型對于每種信號用一個(gè)bit表示“有效”或“無效”狀態(tài)扫俺,至于這個(gè)類型內(nèi)部如何存儲(chǔ)這些bit則依賴于系統(tǒng)實(shí)現(xiàn),從使用者的角度是不必關(guān)心的固翰,使用者只能調(diào)用以下函數(shù)來操作sigset_t變量狼纬,而不應(yīng)該對它的內(nèi)部數(shù)據(jù)做任何解釋。

#include<signal.h>
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set, int signo);
int sigdelset(sigset_t *set, int signo);
int sigismember(const sigset_t *set, int signo);

函數(shù)sigemptyset初始化set所指向的信號集骂际,使其中所有信號的對應(yīng)bit清零疗琉,表示該信號集不包含任何有效信號。函數(shù)sigfillset初始化set所指向的信號集歉铝,使其中所有信號的對應(yīng)bit置位盈简,表示該信號集的有效信號包括系統(tǒng)支持的所有信號。注意太示,在使用sigset_t類型的變量之前送火,一定要調(diào)用sigemptyset或sigfillset做初始化,使信號集處于確定的狀態(tài)先匪。初始化sigset_t變量之后就可以在調(diào)用sigaddset和sigdelset在該信號集中添加或刪除某種有效信號种吸。這四個(gè)函數(shù)都是成功返回0,出錯(cuò)返回-1呀非。sigismember是一個(gè)布爾函數(shù)坚俗,用于判斷一個(gè)信號集的有效信號中是否包含某種信號,若包含則返回1岸裙,不包含則返回0猖败,出錯(cuò)返回-1。

#include<signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oset);//讀取或更改進(jìn)程的信號屏蔽字
3.png
#include<signal.h>
int sigpending(sigset_t *set);//讀取當(dāng)前進(jìn)程的未決信號集降允,通過set參數(shù)傳出

信號補(bǔ)捉過程

4.png
#include<signal.h>
int sigaction(int signo, const struct sigaction *act, struct sigaction *oact);//讀取和修改與指定信號相關(guān)聯(lián)的處理動(dòng)作

act和oact指向sigaction結(jié)構(gòu)體

struct sigaction {
     void (*sa_handler)(int); /* addr of signal handler, */ 
    /* or SIG_IGN, or SIG_DFL */ 
    sigset_t sa_mask; /* additional signals to block */ 
    int sa_flags; /* signal options, Figure 10.16 */ 
    /* alternate handler */ 
    void (*sa_sigaction)(int, siginfo_t *, void *);
};

將sa_handler賦值為常數(shù)SIG_IGN傳給sigaction表示忽略信號恩闻,賦值為常數(shù)SIG_DFL表示執(zhí)行系統(tǒng)默認(rèn)動(dòng)作,賦值為一個(gè)函數(shù)指針表示用自定義函數(shù)捕捉信號剧董,或者說向內(nèi)核注冊了一個(gè)信號處理函數(shù)幢尚,該函數(shù)返回值為void破停,可以帶一個(gè)int參數(shù),通過參數(shù)可以得知當(dāng)前信號的編號尉剩,這樣就可以用同一個(gè)函數(shù)處理多種信號真慢。顯然,這也是一個(gè)回調(diào)函數(shù)理茎,不是被main函數(shù)調(diào)用黑界,而是被系統(tǒng)所調(diào)用。
當(dāng)某個(gè)信號的處理函數(shù)被調(diào)用時(shí)皂林,內(nèi)核自動(dòng)將當(dāng)前信號加入進(jìn)程的信號屏蔽字朗鸠,當(dāng)信號處理函數(shù)返回時(shí)自動(dòng)恢復(fù)原來的信號屏蔽字,這樣就保證了在處理某個(gè)信號時(shí)础倍,如果這種信號再次產(chǎn)生童社,那么它會(huì)被阻塞到當(dāng)前處理結(jié)束為止。如果在調(diào)用信號處理函數(shù)時(shí)著隆,除了當(dāng)前信號被自動(dòng)屏蔽之外,還希望自動(dòng)屏蔽另外一些信號呀癣,則用sa_mask字段說明這些需要額外屏蔽的信號美浦,當(dāng)信號處理函數(shù)返回時(shí)自動(dòng)恢復(fù)原來的信號屏蔽字。

#include<unistd.h>
int pause(void);//使調(diào)用進(jìn)程掛起直到有信號遞達(dá)

當(dāng)捕捉到信號時(shí)项栏,不論進(jìn)程的主控制流程當(dāng)前執(zhí)行到哪兒浦辨,都會(huì)先跳到信號處理函數(shù)中執(zhí)行,從信號處理函數(shù)返回后再繼續(xù)執(zhí)行主控制流程沼沈。信號處理函數(shù)是一個(gè)單獨(dú)的控制流程流酬,因?yàn)樗椭骺刂屏鞒淌钱惒降模卟淮嬖谡{(diào)用和被調(diào)用的關(guān)系列另,并且使用不同的堆椦刻冢空間。引入了信號處理函數(shù)使得一個(gè)進(jìn)程具有多個(gè)控制流程页衙,如果這些控制流程訪問相同的全局資源(全局變量摊滔、硬件資源等),就有可能出現(xiàn)沖突店乐。

理解部分

關(guān)于信號艰躺,之前接觸的比較多的是kill這個(gè)命令,現(xiàn)在看來眨八,發(fā)送信號給進(jìn)程是一種交互方式腺兴。當(dāng)進(jìn)程中實(shí)現(xiàn)了補(bǔ)捉信號以及處理的函數(shù)時(shí),就可以與用戶進(jìn)行簡單的交互廉侧,之所以簡單是因?yàn)樾盘枖?shù)量很少页响。所以一般用做進(jìn)程的啟動(dòng)篓足,重啟,停止拘泞,錯(cuò)誤處理等等纷纫。若使用其他的信息傳遞方式我想也是可以實(shí)現(xiàn)的,就是麻煩了一些陪腌。
下面來實(shí)現(xiàn)一個(gè)簡單的例子辱魁,后臺(tái)跑一個(gè)進(jìn)程,打印出發(fā)送給該進(jìn)程的信號诗鸭。
#include <stdio.h>
#include <signal.h>
#include <unistd.h>

void show_handler(int sig)
{
    printf("I got signal %d\n", sig);
}

int main(void)
{
    int i = 0;
    struct sigaction act, oldact;
    act.sa_handler = show_handler;
    sigaddset(&act.sa_mask, SIGQUIT);
    act.sa_flags = 0;
    sigaction(SIGINT, &act, &oldact);
    sigaction(SIGCONT, &act, &oldact);
    while(1) {
        sleep(1);
        i++;
    }
}

貼上運(yùn)行圖

s.png

注:sigaction 是不能接收SIGKILL 和 SIGSTOP的信號

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末染簇,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子强岸,更是在濱河造成了極大的恐慌锻弓,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蝌箍,死亡現(xiàn)場離奇詭異青灼,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)妓盲,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進(jìn)店門杂拨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人悯衬,你說我怎么就攤上這事弹沽。” “怎么了筋粗?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵策橘,是天一觀的道長。 經(jīng)常有香客問我娜亿,道長丽已,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任买决,我火速辦了婚禮促脉,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘策州。我一直安慰自己瘸味,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布够挂。 她就那樣靜靜地躺著旁仿,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上枯冈,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天毅贮,我揣著相機(jī)與錄音,去河邊找鬼尘奏。 笑死滩褥,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的炫加。 我是一名探鬼主播瑰煎,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼俗孝!你這毒婦竟也來了酒甸?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤赋铝,失蹤者是張志新(化名)和其女友劉穎插勤,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體革骨,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡农尖,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了良哲。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片盛卡。...
    茶點(diǎn)故事閱讀 38,617評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖臂外,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情喇颁,我是刑警寧澤漏健,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站橘霎,受9級特大地震影響蔫浆,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜姐叁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一瓦盛、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧外潜,春花似錦原环、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至滔驾,卻和暖如春谒麦,著一層夾襖步出監(jiān)牢的瞬間俄讹,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工绕德, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留患膛,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓耻蛇,卻偏偏與公主長得像踪蹬,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子城丧,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 進(jìn)程之間可以通過信號傳遞信息延曙,信號是一種軟中斷機(jī)制,通過信號用來通知進(jìn)程發(fā)生了異步事件亡哄。進(jìn)程之間可以互相通過系統(tǒng)調(diào)...
    lintong閱讀 407評論 0 2
  • 信號(signal)是Linux進(jìn)程間通信的一種機(jī)制枝缔,全稱為軟中斷信號,也被稱為軟中斷蚊惯。信號本質(zhì)上是在軟件層次上對...
    小小小小諾閱讀 3,780評論 0 3
  • 對于 Linux來說愿卸,實(shí)際信號是軟中斷,許多重要的程序都需要處理信號截型。信號趴荸,為 Linux 提供了一種處理異步事件...
    故事狗閱讀 84,743評論 2 62
  • 文 | 季風(fēng)無忌 目錄: 《缺失的愛》第 1 卷 簡單的愛(1)《缺失的愛》第 1 卷 簡單的愛(2)《缺失的愛》...
    季風(fēng)無忌閱讀 3,910評論 0 4
  • 誰知道哪里有微信支付的相關(guān)知識(shí)的測試問卷啊
    昵稱ok閱讀 300評論 0 0