sigaction的使用
時間:2018-09-29 來源:未知
具有我們的信號處理的功能但是在大部分時間的時候它的可調節能力也不具備。簡單的說就是sigaction函數更加靈活,同樣的也就復雜。下面簡單的介紹一下sigaction函數以及使用方法。
sigaction函數的功能是檢查或修改與指定信號相關聯的處理動作(可同時兩種操作)。
他是POSIX的信號接口,而signal()是標準C的信號接口(如果程序必須在非POSIX系統上運行,那么就應該使用這個接口)
給信號signum設置新的信號處理函數act, 同時保留該信號原有的信號處理函數oldact
int sigaction(int signo,const struct sigaction *restrict act,
struct sigaction *restrict oact);
結構sigaction定義如下:
struct sigaction{
void (*sa_handler)(int);
sigset_t sa_mask;
int sa_flag;
void (*sa_sigaction)(int,siginfo_t *,void *);
};
sa_handler字段包含一個信號捕捉函數的地址
sa_mask字段說明了一個信號集,在調用該信號捕捉函數之前,這一信號集要加進進程的信號屏蔽字中。僅當從信號捕捉函數返回時再將進程的信號屏蔽字復位為原先值。
sa_flags 用來設置信號處理的其他相關操作,下列的數值可用。
OR 運算(|)組合
A_NOCLDSTOP : 如果參數signum為SIGCHLD,則當子進程暫停時并不會通知父進程
SA_ONESHOT/SA_RESETHAND:當調用新的信號處理函數前,將此信號處理方式改為系統預設的方式。
SA_RESTART:被信號中斷的系統調用會自行重啟
SA_NOMASK/SA_NODEFER:在處理此信號未結束前不理會此信號的再次到來。
如果參數oldact不是NULL指針,則原來的信號處理方式會由此結構sigaction 返回。
返回值 執行成功則返回0,如果有錯誤則返回-1。
錯誤代碼 EINVAL 參數signum 不合法,或是企圖攔截SIGKILL/SIGSTOPSIGKILL信號
EFAULT 參數act,oldact指針地址無法存取。
EINTR 此調用被中斷。
使用示例為:
1. #include <stdio.h>
2. #include <signal.h>
3. void WrkProcess(int nsig)
4. {
5. printf("WrkProcess .I get signal.%d threadid:%d/n",nsig,pthread_self());
6. int i=0;
7. while(i<5){
8. printf("%d/n",i);
9. sleep(1);
10. i++;
11. }
12. }
13. int main()
14. {
15. struct sigaction act,oldact;
16. act.sa_handler = WrkProcess;
17. // sigaddset(&act.sa_mask,SIGQUIT);
18. // sigaddset(&act.sa_mask,SIGTERM)
19. act.sa_flags = SA_NODEFER | SA_RESETHAND;
20. // act.sa_flags = 0;
21. sigaction(SIGINT,&act,&oldact);
22. printf("main threadid:%d/n",pthread_self());
23. while(1)sleep(5);
24. return 0;
25. }
1)執行改程序時,ctrl+c,第一次不會導致程序的結束。而是繼續執行,當用戶再次執行ctrl+c的時候,程序采用結束。
2)如果對程序稍微進行一下改動,則會出現另外一種情況。
改動為:act.sa_flags = SA_NODEFER;
經過這種改變之后,無論對ctrl+d操作多少次,程序都不會結束。
3)下面如果再對程序進行一次改動,則會出現第三種情況。
For example: act.sa_flags = 0;
在執行信號處理函數這段期間,多次操作ctrl+c,程序也不會調用信號處理函數,而是在本次信號處理函數完成之后,在執行一次信號處理函數(無論前面產生了多少次ctrl+c信號)。
如果在2)執行信號處理函數的過程中,再次給予ctrl+c信號的時候,會導致再次調用信號處理函數。
4)如果在程序中設置了sigaddset(&act.sa_mask,SIGQUIT);程序在執行信號處理函數的過程中,發送ctrl+/信號,程序也不會已經退出,而是在信號處理函數執行完畢之后才會執行SIGQUIT的信號處理函數,然后程序退出。如果不添加這項設置,則程序將會在接收到ctrl+/信號后馬上執行退出,無論是否在ctrl+c的信號處理函數過程中。
原因如下:
1)情況下,第一次產生ctrl+c信號的時候,該信號被自己設定的信號處理函數進行了處理。在處理過程中,由于我們設定了SA_RESETHAND標志位,又將該信號的處理函數設置為默認的信號處理函數(系統默認的處理方式為IGN),所以在第二次發送ctrl+d信號的時候,是由默認的信號處理函數處理的,導致程序結束;
2)情況下,我們去掉了SA_RESETHAND了標志位,導致程序中所有的ctrl+d信號均是由我們自己的信號處理函數來進行了處理,所以我們發送多少次ctrl+c信號程序都不會退出;
3)情況下,我們去掉了SA_NODEFER標志位。程序在執行信號處理函數過程中,ctrl+c信號將會被阻止,但是在執行信號處理函數期發送的ctrl+c信號將會被阻塞,知道信號處理函數執行完成,才有機會處理信號函數執行期間產生的ctrl+c,但是在信號函數執行產生的多次ctrl+c,后只會產生ctrl+c。2)情況下,由于設置了SA_NODEF,ctrl+c信號將不會被阻塞。所以能夠并行執行下次的信號處理函數。
4)情況下,我們是設置了在執行信號處理函數過程中,我們將屏蔽該信號,當屏蔽該信號的處理函數執行完畢后才會進行處理該信號。
附:
當我們按下ctrl+c的時候,操作為:向系統發送SIGINT信號,SIGINT信號的默認處理,退出程序。
當我們按下ctrl+/的時候,操作為:向系統發送SIGQUIT信號,該信號的默認處理為退出程序。
以上是對sigaction的簡單講解,主要與signal的區別在于對于結構體部分的使用,了解其結構體部分,就可以很好的使用sigaction函數。

