函數函數sigaction、signal


函數函數sigaction

1. 函數sigaction原型:

int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);

分析:

  • 參數 signum :要捕獲的信號。
  • 參數act:truct sigaction 結構體,后面具體講解傳入參數,新的處理方式
  • 參數oldact:返回舊的 struct sigaction 結構體,傳出參數,舊的處理方式

 

1.2 struct sigaction 結構體

1 struct sigaction
2 {
3     void(*sa_handler)(int);
4     void(*sa_sigaction)(int, siginfo_t *, void *);
5     sigset_t sa_mask;
6     int sa_flags;
7     void(*sa_restorer)(void);
8 };

分析:

  • sa_handler : 不帶附加參數的信號處理函數指針
  • sa_sigaction: 帶有附加參數的信號處理函數指針(兩個信號處理函數指針只能二選一)
  • sa_mask: 在執行信號處理函數時,應該屏蔽掉哪些信號
  • sa_flags: 用於控制信號行為,它的值可以是下面選項的組合。
  • SA_SIGINFO:如果指定該選項,則向信號處理函數傳遞參數(這時應該使用 sa_sigaction 成員而不是 sa_handler).
  • sa_restorer:該成員在早期是用來清理函數棧的,如今已被廢棄不用。

注意:sa_flags 的選項比較多,大部分可又自己做實驗驗證,有些是需要額外的知識,比如 SA_ONESTACK 和 SA_RESTART,這些放到后面講解。本節示例中,只需要把 sa_flags 設置為 0 即可。

 

信號捕捉特性:

  • 進程正常運行時,默認PCB有一個信號屏蔽字,假定為☆,它決定了進程自動屏蔽哪些信號,當注冊了某個信號步捕捉函數,捕捉到該信號以后,要調用該函數,而該函數有可能執行很長時間,在這期間所屏蔽的信號不由☆指定,而由sa_mask來指定,調用完信號處理函數,再恢復為☆。
  • xxx信號捕捉函數執行期間,XXX信號自動屏蔽。
  • 阻塞的常規信號不支持排隊,產生多次只記錄一次(后32個實時信號支持排隊)

 

1. 測試代碼:

 1 #include<stdio.h>
 2 #include<signal.h>
 3 #include<stdlib.h>
 4 #include<unistd.h>
 5  
 6 void docatch(int signo)
 7 {
 8     printf("%d signal is catch\n", signo);
 9 }
10  
11 int main()
12 {
13     int ret;
14     struct sigaction act;
15     act.sa_handler = docatch;
16     sigemptyset(&act.sa_mask);
17     sigaddset(&act.sa_mask, SIGQUIT);
18     act.sa_flags = 0;  //默認屬性:信號捕捉函數執行期間,自動屏蔽本信號
19     ret = sigaction(SIGINT, &act, NULL);
20     if(ret < 0) 
21     {
22         perror("sigaction error");
23         exit(1);
24     }
25     while(1)
26       sleep(1);
27     return 0;
28 }

輸出結果:

 

 2. 測試代碼:

 1 #include<stdio.h>
 2 #include<signal.h>
 3 #include<stdlib.h>
 4 #include<unistd.h>
 5  
 6 void docatch(int signo)
 7 {
 8     printf("%d signal is catch\n", signo);
 9     sleep(10);
10     printf("--------------finish-\n");
11 }
12  
13 int main()
14 {
15     int ret;
16     struct sigaction act;
17     act.sa_handler = docatch;
18     sigemptyset(&act.sa_mask);
19     sigaddset(&act.sa_mask, SIGQUIT);
20     act.sa_flags = 0;  
21     ret = sigaction(SIGINT, &act, NULL);
22     if (ret < 0) 
23     {
24         perror("sigaction error");
25         exit(1);
26     }
27     while (1)
28         sleep(1);
29     return 0;
30 }

輸出結果:

 

3. 測試代碼:

 1 #include <unistd.h>
 2 #include <signal.h>
 3 #include <stdio.h>
 4 
 5 void printsigset(const sigset_t *set)
 6 {
 7     for (int i = 1; i <= 64; i++)
 8     {
 9         if (i == 33) putchar(' ');
10         if (sigismember(set, i) == 1)
11             putchar('1');
12         else
13             putchar('0');
14     }
15     puts("");
16 }
17 
18 void handler(int sig)
19 {
20     if (sig == SIGTSTP) 
21         printf("hello SIGTSTP\n");
22     if (sig == SIGINT) 
23         printf("hello SIGINT\n");
24     sleep(5);
25     sigset_t st;
26     sigpending(&st);
27     printsigset(&st);
28 }
29 
30 int main()
31 {
32     printf("I'm %d\n", getpid());
33     struct sigaction act, oldact;
34     act.sa_handler = handler;   // 設置普通信號處理函數                     
35     sigemptyset(&act.sa_mask);  // 向 sa_mask 中添加 SIGINT
36     sigaddset(&act.sa_mask, SIGINT);
37     act.sa_flags = 0; // 先置 0
38 
39     sigaction(SIGTSTP, &act, &oldact);
40     sigaction(SIGINT, &act, &oldact);
41 
42     while (1) 
43     {
44         write(STDOUT_FILENO, ".", 1);
45         pause();
46     }
47     return 0;
48 }

輸出結果:

分析:

  • 當程序運行的時候,Ctrl C 進入 handler,然后立即 Ctrl Z 發現 handler 還未執行完就被 SIGTSTP 打斷.
  • 當程序運行的時候,Ctrl Z 進入 handler,然后立即 Ctrl C 發現並不會被 SIGINT 打斷,這是因為該 handler 注冊的時候被設置了 SA_MASK = SIGINT。最后 handler 結束的時候打印了未決信號集,發現里頭有 SIGINT。所以 handler 結束后,又去繼續對 SIGINT 進行處理。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM