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