原型:
#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 ", sig, pthread_self()); int i = 0; while (i < 5) { fprintf(stdout,"%d ", 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 ",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 ", sig, pthread_self()); int i = 0; while (i < 5) { fprintf(stdout, "%d ", i); sleep(1); i++; } } void *function_pthread(void *arg) { int i = 2; while (i--) { sleep(1); fprintf(stdout, "send Sig "); 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 ", 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 ", sig, pthread_self()); int i = 0; raise(MySig); while (i < 5) { fprintf(stdout, "%d ", i); sleep(1); i++; } }
如果不加则是在handler结束后才会再次触发handler,6666。
而且这种设置只对本信号有效,就是说如果发出一个SIGINT,不管有没有SA_NODEFER都不会block掉SIGINT信号。