1. 程式人生 > >linux sigaction 函數 用法釋義

linux sigaction 函數 用法釋義

所有 unix gnu store 中斷 pid byte 聯合體 參數

使用 sigaction 函數:

signal 函數的使用方法簡單,但並不屬於 POSIX 標準,在各類 UNIX 平臺上的實現不盡相同,因此其用途受

到了一定的限制。而 POSIX 標準定義的信號處理接口是 sigaction 函數,其接口頭文件及原型如下:

#include <signal.h>

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

◆ signum:要操作的信號。

◆ act:要設置的對信號的新處理方式。

◆ oldact:原來對信號的處理方式。

◆ 返回值:0 表示成功,-1 表示有錯誤發生。

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_handler 是一個函數指針,其含義與 signal 函數中的信號處理函數類似。

成員sa_sigaction 則是另一個信號處理函數,它有三個參數,可以獲得關於信號的更詳細的信息。

當 sa_flags 成員的值包含了 SA_SIGINFO 標誌時,系統將使用 sa_sigaction 函數作為信號處理函數,否則使用 sa_handler 作為信號處理函數。

在某些系統中,成員 sa_handler 與 sa_sigaction 被放在聯合體中,因此使用時不要同時設置。 sa_mask 成員用來指定在信號處理函數執行期間需要被屏蔽的信號,特別是當某個信號被處理時,它自身會被

自動放入進程的信號掩碼,因此在信號處理函數執行期間這個信號不會再度發生。 sa_flags 成員用於指定信號處理的行為,它可以是一下值的“按位或”組合。

◆ SA_RESTART:使被信號打斷的系統調用自動重新發起。

◆ SA_NOCLDSTOP:使父進程在它的子進程暫停或繼續運行時不會收到 SIGCHLD 信號。

◆ SA_NOCLDWAIT:使父進程在它的子進程退出時不會收到 SIGCHLD 信號,這時子進程如果退出也不會成為僵屍進程。

◆ SA_NODEFER:使對信號的屏蔽無效,即在信號處理函數執行期間仍能發出這個信號。

◆ SA_RESETHAND:信號處理之後重新設置為默認的處理方式。

◆ SA_SIGINFO:使用 sa_sigaction 成員而不是 sa_handler 作為信號處理函數。

re_restorer 成員則是一個已經廢棄的數據域,不要使用。

下面用一個例程來說明 sigaction 函數的使用,代碼如下:

技術分享
 1 #include <stdio.h>
 2 #include <unistd.h>
 3 #include <signal.h>
 4 #include <errno.h>
 5 
 6 static void sig_usr(int signum)
 7 {
 8     if(signum == SIGUSR1)
 9     {
10         printf("SIGUSR1 received\n");
11     }
12     else if(signum == SIGUSR2)
13     {
14         printf("SIGUSR2 received\n");
15     }
16     else
17     {
18         printf("signal %d received\n", signum);
19     }
20 }
21 
22 int main(void)
23 {
24     char buf[512];
25     int  n;
26     struct sigaction sa_usr;
27     sa_usr.sa_flags = 0;
28     sa_usr.sa_handler = sig_usr;   //信號處理函數
29     
30     sigaction(SIGUSR1, &sa_usr, NULL);
31     sigaction(SIGUSR2, &sa_usr, NULL);
32     
33     printf("My PID is %d\n", getpid());
34     
35     while(1)
36     {
37         if((n = read(STDIN_FILENO, buf, 511)) == -1)
38         {
39             if(errno == EINTR)
40             {
41                 printf("read is interrupted by signal\n");
42             }
43         }
44         else
45         {
46             buf[n] = \0;
47             printf("%d bytes read: %s\n", n, buf);
48         }
49     }
50     
51     return 0;
52 }
技術分享

在這個例程中使用 sigaction 函數為 SIGUSR1 和 SIGUSR2 信號註冊了處理函數,然後從標準輸入讀入字符。

程序運行後首先輸出自己的 PID,如: My PID is 5904

這時如果從另外一個終端向進程發送 SIGUSR1 或 SIGUSR2 信號,用類似如下的命令: kill -USR1 5904

則程序將繼續輸出如下內容: SIGUSR1 received read is interrupted by signal

這說明用 sigaction 註冊信號處理函數時,不會自動重新發起被信號打斷的系統調用。如果需要自動重新發起,則要設置 SA_RESTART 標誌,

比如在上述例程中可以進行類似一下的設置: sa_usr.sa_flags = SA_RESTART;

註意,必須用sigemptyset函數初始化act結構的sa_mask成員。不能保證:act.sa_mask = 0;會做同樣的事情。

對除SIGALRM以外的所有信號,我們都有嘗試設置SA_RESTART標誌,於是被這些信號中斷的系統調用都能自動重啟動。不希望重啟動由SIGALRM信號中斷的系統調用的原因是:我們希望對I/O操作可以設置時間限制。

linux sigaction 函數 用法釋義