【进程通信】Signal信号
信號(signal)
??軟中斷信號(signal,又簡稱為信號)是Linux下用來在進程間傳遞消息的方式之一,也是進程間唯一的異步通信方式。從命名中可以看出信號的實質(zhì)很像中斷。進程間可以通過調(diào)用kill庫函數(shù)發(fā)送軟中斷信號,Linux內(nèi)核也可能給進程發(fā)送信號,用以告知該進程發(fā)生了某個異步事件。
??注意,信號只用來告知進程發(fā)生了某個異步事件,并不用來傳遞數(shù)據(jù)。進程收到信號后會有三種處理方式:
- 忽略,不做任何處理
- 執(zhí)行預(yù)先設(shè)置的處理函數(shù)(就像中斷服務(wù)程序一樣)
- 采用系統(tǒng)的默認操作,大部分是終止進程
?
信號的來源
用戶
一般是鍵盤的輸入會作為信號發(fā)送給進程,比如:Ctrl + C 發(fā)送SIGINT信號給進程,默認動作為終止進程;Ctrl + \ 發(fā)送SIGQUIT信號給進程,默認動作為終止進程并進行內(nèi)核映像轉(zhuǎn)儲(core dump)
內(nèi)核
當進程執(zhí)行出錯時,內(nèi)核給進程發(fā)送一個對應(yīng)信號,例如:非法內(nèi)存引用、浮點數(shù)溢出、執(zhí)行非法指令
進程
C++的kill庫函數(shù)用于進程間發(fā)送信號
?
信號的類型
| SIGINT | 2 | 終止進程 | 鍵盤中斷Ctrl+c |
| SIGQUIT | 3 | 終止進程并進行內(nèi)核映像轉(zhuǎn)儲 | 鍵盤的退出鍵被按下 |
| SIGKILL | 9 | 終止進程,并且不能被捕獲、忽略 | 采用kill -9 進程編號 強制殺死程序。 |
| SIGSEGV | 11 | 終止進程并進行內(nèi)核映像轉(zhuǎn)儲 | 無效的內(nèi)存引用 |
| SIGTERM | 15 | 終止進程 | 采用“kill 進程編號”或“killall 程序名”通知程序。 |
| SIGCHLD | 20,17,18 | 忽略此信號 | 子進程結(jié)束信號 |
PS:
? 內(nèi)核映像轉(zhuǎn)儲(core dump),內(nèi)核映像轉(zhuǎn)儲是指將進程數(shù)據(jù)在內(nèi)存的映像和進程在內(nèi)核結(jié)構(gòu)中的部分內(nèi)容以一定格式轉(zhuǎn)儲到文件系統(tǒng),并且進程退出執(zhí)行,這樣做的好處是為程序員 提供了方便,使得他們可以得到進程當時執(zhí)行時的數(shù)據(jù)值,允許他們確定轉(zhuǎn)儲的原因,并且可以調(diào)試他們的程序。
?
信號的捕獲處理
#include <signal.h> sighandler_t signal(int signum, sighandler_t handler) //signum 表示信號的編號//handler 表示信號的處理方式,有三種:1. SIG_IGN:忽略改信號,不作為2. SIG_DFL:恢復該信號的默認處理方法3. 自定義處理函數(shù),注意函數(shù)參數(shù)為 (int signum)?
信號的發(fā)送
int kill(pid_t pid, int sig) //pid 目標進程號,有三種情況:1. pid>0 將信號sig傳給號為pid的進程2. pid=0 將信號sig傳給同進程組的所有進程(包括自己),常用于父進程給子進程發(fā)送信號3. pid=-1 將信號廣播到系統(tǒng)內(nèi)所有進程,例如系統(tǒng)關(guān)機時向所有登錄窗口廣播關(guān)機信息//sig 被發(fā)送的信號編號?
信號的應(yīng)用
屏蔽信號
??通常為了程序不被干擾,程序開頭通常會屏蔽所有信號,然后再用signal函數(shù)對關(guān)心的信號設(shè)置相應(yīng)的處理方式。
for(int i=0; i<100; i++) signal(i, SIG_IGN);?
搞點好玩的
??改變信號 SIGINT 和 SIGTERM的捕獲處理,設(shè)計一個 ctrl+C 和 kill 都殺不掉的進程:
#include <stdio.h> #include <stdlib.h> #include <signal.h>void func(int sig) {if (sig == SIGINT)printf("\b\b殺不死,哈哈哈哈。\n");else if (sig == SIGTERM)printf("還是殺不死,哈哈哈哈。\n"); }int main() {for (int ii = 0; ii < 100; ii++)signal(ii, SIG_IGN); // 屏蔽全部的信號signal(SIGINT, func);signal(SIGTERM, func); // 設(shè)置SIGINT和SIGTERM的處理函數(shù)while (1); }效果:
使用Ctrl+C 嘗試關(guān)掉進程:
用 ps -ef | grep signal 找到其進程號,嘗試用 kill 直接干掉:
可以看見,kill + 進程號 或 killall + 進程名 對它都無效,那改怎么殺死這個進程呢?如圖,用 kill -9 進程號:
因為kill -9 進程號 發(fā)送的信號是 SIGKILL,這個信號無法被捕獲或忽略,能夠快準狠殺掉進程
?
使系統(tǒng)休眠
這個是我嘗試用 kill() 函數(shù)向系統(tǒng)所有進程發(fā)送 SIGKILL 信號后發(fā)現(xiàn)的,當然是在虛擬機上,我可不敢在主機上這樣搞:
#include <stdio.h> #include <signal.h>int main() {kill(-1, SIGKILL); }效果是虛擬機進入休眠,輸入密碼后能再進入,原以為會直接關(guān)機呢
總結(jié)
以上是生活随笔為你收集整理的【进程通信】Signal信号的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 标准输入/出与重定向
- 下一篇: 点到点链路的滑动窗口协议