12訊號學習之訊號捕捉特性及其多個測試案例(並總結臨時遮蔽字和系統遮蔽字的作用域關係)-->(非常重要)
阿新 • • 發佈:2021-01-30
技術標籤:Linux訊號的學習linux
1 訊號捕捉特性
- 1)程序正常執行時,預設PCB中有一個訊號遮蔽字,假定為☆,它決定了程序自動遮蔽哪些訊號。當註冊了某個訊號捕捉函式,捕捉到該訊號以後,要呼叫該函式。而該函式有可能執行很長時間,在這期間所遮蔽的訊號不由☆來指定。而是用sa_mask來指定。呼叫完訊號處理函式,再恢復為☆。
- 2)XXX訊號捕捉函式執行期間,XXX訊號自動被遮蔽。
- 3)阻塞的常規訊號不支援排隊,產生多次只記錄一次。(後32個實時訊號支援排隊)
本篇可以與上一篇對照理解。
https://blog.csdn.net/weixin_44517656/article/details/113067715
2 訊號捕捉特性的多個測試案例
2.1 為某個訊號設定捕捉函式
太簡單 了,直接參考下面的程式即可。
2.2 測試訊號捕捉特性的第2和3點
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
/*自定義的訊號捕捉函式*/
void sig_int(int signo)
{
if(signo == SIGINT){
printf("catch you %d\n", signo);
sleep(10);//模擬長時間執行
}else if(signo == SIGQUIT){
printf("catch you %d\n", signo);
}
return;
}
int main(void)
{
struct sigaction act;
act.sa_handler = sig_int;
sigemptyset(&act.sa_mask); //傳0遮蔽集,不遮蔽任何訊號,sa_mask只在sig_int函式有效
//sigprocmask(SIGINT, act, NULL);//注意呼叫該函式是將訊號集新增到系統的訊號集,所以要想只在回撥生效則不應該呼叫這一步
act.sa_flags = 0; //預設屬性
int ret = sigaction(SIGINT, &act, NULL);
if(ret == -1){
printf("sigaction failed.\n");
return -1;
}
ret = sigaction(SIGQUIT, &act, NULL);//即ctrl+\
if(ret == -1){
printf("sigaction failed.\n");
return -1;
}
printf("------------main slept 10\n");
sleep(10);
while(1);//該迴圈只是為了保證有足夠的時間來測試函式特性
return 0;
}
結果分析:
1)首先我們第一次按下ctrl+c,它會先列印一次,然後睡眠十秒。
2)在睡眠十秒的過程中,我不斷按下ctrl+c,該訊號是被遮蔽了,若無遮蔽的話,應該是重新執行該回調函式列印並重新睡眠的,但結果是仍然在睡眠。所以這裡驗證了第2點。
3)當過完十秒後,我什麼也沒做,結果終端會再次列印一次,這就驗證了第三點,常規訊號多次產生,程序只會記錄一次。
2.3 案例
驗證sa_mask在捕捉函式執行期間的遮蔽作用,即在執行捕捉函式期間,新增除了自動遮蔽本訊號的其它訊號,看其是否生效,生效就證明該臨時遮蔽字只在回撥執行有效,因為系統遮蔽字是沒有遮蔽該訊號的。
/*自動遮蔽本訊號,呼叫完畢後遮蔽自動解除*/
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
/*自定義的訊號捕捉函式*/
void sig_int(int signo)
{
if(signo == SIGINT){
printf("catch you %d\n", signo);
sleep(10);//模擬長時間執行
}
int main(void)
{
struct sigaction act, old;
act.sa_handler = sig_int;
sigemptyset(&act.sa_mask);
sigaddset(&act.sa_mask, SIGQUIT);//在回撥函式執行期間除了遮蔽本訊號,也遮蔽SIGQUIT訊號。
act.sa_flags = 0;
int ret = sigaction(SIGINT, &act, &old); //註冊訊號處理函式
if(ret == -1){
printf("sigaction failed.\n");
return -1;
}
while(1);
//sigaction(SIGINT, &old, NULL); //註冊訊號處理函式
return 0;
}
上面的結果就是第一次按下ctrl+c程式列印一次,然後睡眠,睡眠期間即回撥執行期間再按下ctrl+c或者ctrl+\程式都不會終止,因為回撥執行期間這兩個訊號被臨時遮蔽字遮蔽了。但是當程式執行完後它會儲存著一次該訊號,所以10秒之後程式自動結束,注意結束是因為觸發了3訊號的終止動作。所以我們有時候程式再執行時我們按下ctrl+c沒反應,這是因為該訊號被捕捉了,只能等待程式結束後才能執行終止動作。
3 總結臨時遮蔽字和系統遮蔽字的作用域關係
- 1)在回撥函式執行期間,臨時遮蔽字預設只遮蔽本訊號,若想在執行期間也遮蔽其它訊號,需要提前操作sa_mask新增對應的遮蔽。並且若回撥執行期間,臨時遮蔽字並未遮蔽的訊號,由系統遮蔽字處理(生效),或者說回撥期間臨時遮蔽字比系統遮蔽字優先使用。例如我註冊了2訊號,預設回撥執行期間只會遮蔽2訊號自己,當我按下ctrl+\觸發3訊號時,由於臨時遮蔽字並未遮蔽,所以由系統遮蔽字,結果是系統將被終止。
- 2)不在回撥函式執行期間,那就簡單了,系統遮蔽字有效。