sigaction()

原型:

#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.
View Code

头文件里的(看头文件的定义设置的参数是互斥的吧不对,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
View Code

有人翻译的

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)情况下,我们是设置了在执行信号处理函数过程中,我们将屏蔽该信号,当屏蔽该信号的处理函数执行完毕后才会进行处理该信号。

参考引用:

sigaction 用法实例

sigaction

自己写了一段代码

#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;
}
View Code

 试了下不管怎么样都能接收到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++;
    }
}
View Code

如果不加则是在handler结束后才会再次触发handler,6666。

而且这种设置只对本信号有效,就是说如果发出一个SIGINT,不管有没有SA_NODEFER都不会block掉SIGINT信号。

少壮不识cpp,老大方知cpp可怕
原文地址:https://www.cnblogs.com/Jacket-K/p/8364874.html