信號的產生方式:
1、鍵盤輸入
如 Ctrl+C 表示產生一個SIGINT信號
2、異常產生信號
如 程序執行到 2/0 這種情況、 管道的讀段已經關閉而寫端仍向管道中寫入數據這種情況 等...
3、通過命令向指定進程發送信號
對信號的處理方式:
1、忽略
2、執行默認處理(通常為終止程序)
3、執行自定義動作 (信號的捕捉)
舉個例子。
下面這段程序,從0開始,每隔一秒輸出一個不斷增長的數值
執行:
顯然 它是一個死循環,將會一直執行下去
用信號中斷它,可以直接用Ctrl + C
這樣內核會對該進程發送一個 SIGINT 信號,結束當前進程:
此外,執行程序後 另外打開一個終端
(其實在執行命令的語句後面加上 & 就可以讓當前進程在後台運行,也就不需要另外打開中斷了,這裡這樣做是為了更直觀一些)
先用 ps aux 命令查找到當前進程的 PID
然後用 killl -l 命令查看所有信號:
這裡能夠發現, Ctrl+C快捷鍵發送的 SIGINT 信號對應的2,
而我當前進程的PID 為:20262
那麼,執行命令 : kill -2 20262 或者 kill -SIGINT 20262
發現死循環的進程終止了
接下來介紹幾個信號集操作函數:
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);
int sigprocmask(int how, const sigset_t *set, sigset_t *oset);
int sigpending(sigset_t *set);
第一個函數:
sigemptyset 用來初始化 set 指向的 信號集,使所有信號對應的bit清零,表示該信號集不包含任何有效信號
成功返回0,出錯返回 -1
第二個函數:
sigfillset 同樣用來初始化,不過跟上面那個 sigemptyset 作用相反,它表示該信號集包括系統支持的所有信號
成功返回0,出錯返回 -1
在使用 sigset_t 類型變量之前,必須調用上述兩個初始化闡述中的任意一個
第三個函數:
sigaddset 的作用是向指定信號集 set 中添加 有效信號
成功返回0,出錯返回 -1
第四個函數:
sigdelset 的作用是在指定信號集 set 中 刪除有效信號
成功返回0,出錯返回 -1
第五個函數:
sigismember 用來判斷指定的信號是否在指定信號集中
若存在,返回1; 若不存在,返回0; 若出錯,返回-1
第六個函數:
sigprocmask 可以讀取或更改進程的信號屏蔽字
int sigprocmask(int how, const sigset_t *set, sigset_t *oset);
成功返回0,失敗返回-1
其中第一個參數 how表示處理方式,有以下三種:
・SIG_BLOCK :
set包含了我們希望添加到當前信號屏蔽字的信號 //相當於mask = mask | set
・SIG_UNBLOCK :
set包含了我們希望從當前信號屏蔽字中解除阻塞的信號 //相當於 mask = mask | ~set
・SIG_SETMASK :
設置當前信號屏蔽字為set所指向的值 //相當於 mask = set
第七個函數:
sigpending 讀取當前進程的未決信號集,通過set參數傳出
成功返回0,失敗返回-1
接下來,用上面介紹的7個函數,實現一段功能
這裡我定義的 print_sig 函數的作用是 將指定信號集的所有信號的存在情況打印出來
main函數中, 第35行 將SIGINT信號添加進 s 信號集當中
然後37行的 sigprocmask 執行完畢後, SIGINT信號就相當於被阻塞了,同時,o保存的信號集就是之前的s(全 0)
while循環 每次讀取並打印 當前的未決信號集 每循環5次就恢復一次阻塞,如果沒有信號被阻塞,則打印“recover block” 並繼續執行循環,
如果有信號被阻塞,那麼在49行恢復阻塞完畢後,程序就會終止掉。
運行結果: