原型:
#include <signal.h> int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
struct sigaction { void (*sa_handler)(int); //默認信號處理函數 void (*sa_sigaction)(int, siginfo_t *, void *); //可以發送附加信息的信號處理函數,sa_flag設置了SA_SIGINFO使用其處理 sigset_t sa_mask;//在此信號集中的信號在信號處理函數運行中會被屏蔽,函數處理完后才處理該信號 int sa_flags;//可設參數很多 void (*sa_restorer)(void);//在man手冊里才發現有這玩意,還不知道啥用 };
sa_flag的參數
man手冊里的

SA_NOCLDSTOP If signum is SIGCHLD, do not receive notification when child processes stop (i.e., when they receive one of SIGSTOP, SIGTSTP, SIGTTIN, or SIGTTOU) or resume (i.e., they receive SIGCONT) (see wait(2)). This flag is meaningful only when establishing a handler for SIGCHLD. SA_NOCLDWAIT (since Linux 2.6) If signum is SIGCHLD, do not transform children into zombies when they terminate. See also waitpid(2). This flag is meaningful only when establishing a handler for SIGCHLD, or when setting that signal's disposition to SIG_DFL. If the SA_NOCLDWAIT flag is set when establishing a handler for SIGCHLD, POSIX.1 leaves it unspecified whether a SIGCHLD signal is generated when a child process terminates. On Linux, a SIGCHLD signal is generated in this case; on some other implementations, it is not. SA_NODEFER Do not prevent the signal from being received from within its own signal handler. This flag is meaningful only when establishing a signal handler. SA_NOMASK is an obsolete, nonstandard synonym for this flag. SA_ONSTACK Call the signal handler on an alternate signal stack pro‐ vided by sigaltstack(2). If an alternate stack is not available, the default stack will be used. This flag is meaningful only when establishing a signal handler. SA_RESETHAND Restore the signal action to the default upon entry to the signal handler. This flag is meaningful only when estab‐ lishing a signal handler. SA_ONESHOT is an obsolete, non‐ standard synonym for this flag. SA_RESTART Provide behavior compatible with BSD signal semantics by making certain system calls restartable across signals. This flag is meaningful only when establishing a signal han‐ dler. See signal(7) for a discussion of system call restarting. SA_RESTORER Not intended for application use. This flag is used by C libraries to indicate that the sa_restorer field contains the address of a "signal trampoline". See sigreturn(2) for more details. SA_SIGINFO (since Linux 2.2) The signal handler takes three arguments, not one. In this case, sa_sigaction should be set instead of sa_handler. This flag is meaningful only when establishing a signal han‐ dler.
頭文件里的(看頭文件的定義設置的參數是互斥的吧)不對,1248剛好位錯開,應該可以使用|

/* Bits in `sa_flags'. */ #define SA_NOCLDSTOP 1 /* Don't send SIGCHLD when children stop. */ #define SA_NOCLDWAIT 2 /* Don't create zombie on child death. */ #define SA_SIGINFO 4 /* Invoke signal-catching function with three arguments instead of one. */ #if defined __USE_UNIX98 || defined __USE_MISC # define SA_ONSTACK 0x08000000 /* Use signal stack by using `sa_restorer'. */ #endif #if defined __USE_UNIX98 || defined __USE_XOPEN2K8 # define SA_RESTART 0x10000000 /* Restart syscall on signal return. */ # define SA_NODEFER 0x40000000 /* Don't automatically block the signal when its handler is being executed. */ # define SA_RESETHAND 0x80000000 /* Reset to SIG_DFL on entry to handler. */ #endif #ifdef __USE_MISC # define SA_INTERRUPT 0x20000000 /* Historical no-op. */ /* Some aliases for the SA_ constants. */ # define SA_NOMASK SA_NODEFER # define SA_ONESHOT SA_RESETHAND # define SA_STACK SA_ONSTACK #endif
有人翻譯的
SA_NODEFER: 當信號處理函數正在進行時,不堵塞對於信號處理函數自身信號功能。
SA_RESETHAND:當用戶注冊的信號處理函數被執行過一次后,該信號的處理函數被設為系統默認的處理函數。
SA_SIGINFO 提供附加信息,一個指向siginfo結構的指針以及一個指向進程上下文標識符的指針
實例程序
Webbench中SIGALRM信號的使用
struct sigaction sa; /* setup alarm signal handler */ sa.sa_handler = alarm_handler; sa.sa_flags = 0; if (sigaction(SIGALRM, &sa, NULL)) exit(3); alarm(benchtime);
博文中的詳細解釋
#include <stdio.h> #include <signal.h> void WrkProcess(int nsig) { printf("WrkProcess .I get signal.%d threadid:%d/n",nsig,pthread_self()); int i=0; while(i<5){ printf("%d/n",i); sleep(1); i++; } } int main() { struct sigaction act,oldact; act.sa_handler = WrkProcess; // sigaddset(&act.sa_mask,SIGQUIT); // sigaddset(&act.sa_mask,SIGTERM) act.sa_flags = SA_NODEFER | SA_RESETHAND; // act.sa_flags = 0; sigaction(SIGINT,&act,&oldact); printf("main threadid:%d/n",pthread_self()); while(1)sleep(5); return 0; }
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)情況下,我們是設置了在執行信號處理函數過程中,我們將屏蔽該信號,當屏蔽該信號的處理函數執行完畢后才會進行處理該信號。
參考引用:
自己寫了一段代碼
#define MySig 64 void sig_handler(int sig) { // printf("receive : %d,thread id :%d", sig, pthread_self()); fprintf(stdout,"receive : %d,thread id :%d\n", sig, pthread_self()); int i = 0; while (i < 5) { fprintf(stdout,"%d\n", i); sleep(1); i++; } } int main(int argc, char **argv) { struct sigaction sa; sa.sa_handler = sig_handler; sa.sa_flags = SA_NODEFER ; sigaction(MySig, &sa, NULL); printf("current thread:%d\n",pthread_self()); while (1){ sleep(1); raise(MySig); } return 0; }
發現信號可以自己定義,但是如果自己沒有接收的話程序會退出。
而且根據打印顯示信號處理是同一個線程,所以我有點不理解 “SA_NODEFER: 當信號處理函數正在進行時,不堵塞對於信號處理函數自身信號功能。”這句話了?
是指收到幾個信號就給出幾個反應嗎?不加在處理期間發出的就直接忽略了?試試。
1.首先要新建線程,試了下才反應過來發送信號和信號處理函數在一個線程。

#define MySig 64 void sig_handler(int sig) { // printf("receive : %d,thread id :%d", sig, pthread_self()); fprintf(stdout, "receive : %d,thread id :%ld\n", sig, pthread_self()); int i = 0; while (i < 5) { fprintf(stdout, "%d\n", i); sleep(1); i++; } } void *function_pthread(void *arg) { int i = 2; while (i--) { sleep(1); fprintf(stdout, "send Sig\n"); raise(MySig); } } int main(int argc, char **argv) { struct sigaction sa; sa.sa_handler = sig_handler; sa.sa_flags = SA_NODEFER; sigaction(MySig, &sa, NULL); printf("current thread:%ld\n", pthread_self()); pthread_t pthread_id; pthread_create(&pthread_id,NULL,function_pthread,NULL); while(1) sleep(5); return 0; }
試了下不管怎么樣都能接收到2次信號。所以說???
又回去看了下sigaction 用法實例,原來是在handler內再次發出信號MySig,如果設置了SA_NODEFER將會直接的再次觸發handler,等於說出現了在信號作用下直接遞歸了,如下。

void sig_handler(int sig) { // printf("receive : %d,thread id :%d", sig, pthread_self()); fprintf(stdout, "receive : %d,thread id :%ld\n", sig, pthread_self()); int i = 0; raise(MySig); while (i < 5) { fprintf(stdout, "%d\n", i); sleep(1); i++; } }
如果不加則是在handler結束后才會再次觸發handler,6666。
而且這種設置只對本信號有效,就是說如果發出一個SIGINT,不管有沒有SA_NODEFER都不會block掉SIGINT信號。