sigaction函數
修改信號處理動作(通常在Linux用其來注冊一個信號的捕捉函數)
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact); 成功:0;失敗:-1,設置errno
參數:
act:傳入參數,新的處理方式。oldact:傳出參數,舊的處理方式。
struct sigaction結構體
struct sigaction {
void(*sa_handler)(int);
void(*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void(*sa_restorer)(void);
};
sa_restorer:該元素是過時的,不應該使用,POSIX.1標准將不指定該元素。(棄用)
sa_sigaction:當sa_flags被指定為SA_SIGINFO標志時,使用該信號處理程序。(很少使用)
重點掌握:
① sa_handler:指定信號捕捉后的處理函數名(即注冊函數)。也可賦值為SIG_IGN表忽略 或 SIG_DFL表執行默認動作
② sa_mask: 調用信號處理函數時,所要屏蔽的信號集合(信號屏蔽字)。注意:僅在處理函數被調用期間屏蔽生效,是臨時性設置。用sigaddset函數添加需要被捕捉的信號。
③ sa_flags:通常設置為0,表使用默認屬性:為0的時候,可以屏蔽正在處理的信號(若在處理2號信號時又有2號信號,則此時傳來的2號信號會被屏蔽)。
不多說了,上代碼:
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
void func(int signal)
{
printf("%d號信號被捕捉。\n", signal);
}
int main(void)
{
struct sigaction act, oldact;
act.sa_handler = func;
act.sa_flags = 0;//為0的時候,可以屏蔽正在處理的信號(若在處理2號信號時又有2號信號,則>會被屏蔽)
sigemptyset(&act.sa_mask);//sa_mask是一個臨時信號集,將其清零(初始化I)
sigaddset(&act.sa_mask, SIGQUIT);//將3號信號添加到信號集,即:3號信號就是我們在處理2號信號的時候需要屏蔽的那個信號,也許可以添加其他信號,比如20號信號
sigaddset(&act.sa_mask, SIGTSTP);
int s_ret = sigaction(SIGINT, &act, &oldact);
if (0>s_ret)
{
perror("sigaction error");
exit(1);
}
while (1);
return 0;
}
結果:我的環境是win10子系統,經過我的測試,ctrl+\這個組合鍵不被支持,不能發送3號信號。所以在我按下ctrl+\之后並沒有反應,程序依舊執行,但是在真正的Linux獨立系統中,按下之后該程序會被殺掉的,就如同我按下ctrl+z之后,程序掛起:
接下來kill掉就是了。
———————————————隔了不到十分鍾又來更新的分割線——————————————-
我們來看看信號捕捉特性
進程正常運行時,默認PCB中有一個信號屏蔽字,假定為☆,它決定了進程自動屏蔽哪些信號。當注冊了某個信號捕捉函數,捕捉到該信號以后,要調用該函數。而該函數有可能執行很長時間,在這期間所屏蔽的信號不由☆來指定。而是用sa_mask來指定。調用完信號處理函數,再恢復為☆。
XXX信號捕捉函數執行期間,XXX信號自動被屏蔽。
阻塞的常規信號不支持排隊,產生多次只記錄一次。(后32個實時信號支持排隊)
為了模擬這個3所說的內容,我們這樣改代碼:
void func(int signal)
{
printf("%d號信號被捕捉。\n", signal);
sleep(5);//睡眠十秒,模擬處理信號的函數處理時間很長的那種情況
puts("———————————— - fiish———————");
}
我的測試結果:
第一次只按一次ctrl+c,顯示被捕捉之后瘋狂的按ctrl+c。finish之后顯示信號再次被捕捉,然后瘋狂按ctrl+c、ctrl+z。結果是:那么多次的ctrl+c只執行了三次,多次的ctrl+z也只是被執行了一次。其實原理很好理解的,我們知道,當信號被阻塞時,未決信號集中的相應編號的位置會有0翻轉為1,信號集是什么?是位圖。他不能為多次的相同的信號計數。所以,再多的相同信號在系統看來也只是一個罷了。
————————————–再更新一次————————————-
signal()和sigaction()函數是捕捉信號的函數么?是么?是么?是么?
不是,他倆只是注冊信號捕捉函數的函數,真正動手捉信號的是內核。記得啊。本質區別的。