博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

sigprocmask sigsuspend

Posted on 2016-02-19 18:10  bw_0927  阅读(205)  评论(0)    收藏  举报
  •  int sigsuspend(const sigset_t *mask);       给进程使用的
  •    //把当前进程的信号掩码位临时替换为参数mask指定的值,然后暂停当前进程。 当前进程如果收到了来自mask中的信号,进程不会做响应;收到其他信号会进行处理。

sigsuspend() temporarily replaces the signal mask of the calling process with the mask given by
mask and then suspends the process until delivery of a signal whose action is to invoke a signal
handler or to terminate a process.

 

If the signal terminates the process, then sigsuspend() does not return. If the signal is caught,
then sigsuspend() returns after the signal handler returns, and the signal mask is restored to the
state before the call to sigsuspend().

 

 

RETURN VALUE
sigsuspend() always returns -1, with errno set to indicate the error (normally, EINTR).

 

Normally, sigsuspend() is used in conjunction with sigprocmask(2) in order to prevent delivery of a
signal during the execution of a critical code section. The caller first blocks the signals with
sigprocmask(2). When the critical code has completed, the caller then waits for the signals by
calling sigsuspend() with the signal mask that was returned by sigprocmask(2) (in the oldset argu‐
ment).

 

sigprocmask(SIG_BLOCK, &new,&old);         //阻塞new信号的处理;  老的信号集返回到old中
//do critical process
sigsuspend(old)

 

 



#include <unistd.h> #include <signal.h> #include <stdio.h> void handler(intsig) //信号处理函数的实现 { printf("SIGINT sig\n"); } int main() { sigset_t new,old; struct sigaction act; act.sa_handler = handler; //信号处理函数handler sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGINT, &act, 0); //准备捕捉SIGINT信号 sigemptyset(&new); sigaddset(&new, SIGINT); sigprocmask(SIG_BLOCK, &new,&old); //将SIGINT信号阻塞,同时保存当前信号集 //此处收到的SIGINT将会被阻塞,不会触发handler,信号也不会被排队 printf("Blocked\n"); int j = 30; while(j--) { printf("%d\n", j); sleep(1); } sigprocmask(SIG_SETMASK, &old,NULL); //取消阻塞 //解除信号的阻塞后,先前收到的信号被触发handler,但只会触发一次 // printf("unBlocked\n"); j = 30; while(j--) { printf("%d\n", j); sleep(1); } pause(); return 0; }

  

 

 

 

#include <unistd.h>
#include <signal.h>
#include <stdio.h>
void handler(int sig)  //信号处理程序
{
   if(sig == SIGINT)
     printf("SIGINT sig\n");
   else if(sig == SIGQUIT)
     printf("SIGQUIT sig\n");
   else
     printf("SIGUSR1 sig\n");
}

int main()
{
   sigset_t new,old,wait;   //三个信号集
   struct sigaction act;
   act.sa_handler = handler;
   sigemptyset(&act.sa_mask);
   act.sa_flags = 0;
   //可以捕捉以下三个信号:SIGINT/SIGQUIT/SIGUSR1
   sigaction(SIGINT, &act, 0);
   sigaction(SIGQUIT, &act, 0);
   sigaction(SIGUSR1, &act, 0);

    int j = 30;
    while(j--)
    {
        printf("%d\n", j);
        sleep(1);
    }

   sigemptyset(&new);
   sigaddset(&new,SIGINT);  //SIGINT信号加入到new信号集中

   sigemptyset(&wait);
   sigaddset(&wait, SIGUSR1); //SIGUSR1信号加入wait

   sigprocmask(SIG_BLOCK, &new, &old);      //将SIGINT阻塞,SIGINT的handler将不再会被调用,保存当前信号集到old中

    j = 30;
    while(j--)
    {
        printf("%d\n", j);
        sleep(1);
    }


    //临界区代码执行
   if(sigsuspend(&wait) != -1) //程序在此处挂起;用wait信号集替换new信号集。即:过来SIGUSR1信 号,阻塞掉,程序继续挂起;过来其他信号,例如
SIGINT,则会唤醒程序。执行sigsuspend的原子操作。注意:如果“sigaddset(&wait,SIGUSR1);”这句没有,则此处不会阻塞任何信号,即过来任何信号均会>唤醒程序。
    {
       printf("sigsuspend error\n");
    }

   printf("After sigsuspend\n");
   sigprocmask(SIG_SETMASK, &old, NULL);

   return 0;
}

  

 

void
ngx_master_process_cycle(ngx_cycle_t *cycle)
{
    //...
    sigemptyset(&set);
    sigaddset(&set, SIGCHLD);
    sigaddset(&set, SIGALRM);
    sigaddset(&set, SIGIO);
    sigaddset(&set, SIGINT);
    sigaddset(&set, ngx_signal_value(NGX_RECONFIGURE_SIGNAL));
    sigaddset(&set, ngx_signal_value(NGX_REOPEN_SIGNAL));
    sigaddset(&set, ngx_signal_value(NGX_NOACCEPT_SIGNAL));
    sigaddset(&set, ngx_signal_value(NGX_TERMINATE_SIGNAL));
    sigaddset(&set, ngx_signal_value(NGX_SHUTDOWN_SIGNAL));
    sigaddset(&set, ngx_signal_value(NGX_CHANGEBIN_SIGNAL));

    if (sigprocmask(SIG_BLOCK, &set, NULL) == -1) {                //阻塞上述所有的信号,不对这些信号响应
        ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                      "sigprocmask() failed");
    }    

    sigemptyset(&set);                   //清空set,这样子进程继承到的set也是空的。  但当前进程和子进程的信号掩码位还是之前的设置值。                      

    ngx_start_worker_processes(cycle, ccf->worker_processes,                   //fork子进程
                               NGX_PROCESS_RESPAWN);
    //...
    for ( ;; ) {
        //...
        sigsuspend(&set);                                      //阻塞当前进程,并且设置其进程的阻塞信号集为清空后的set,此时进程收到任何信号将会做相应的handler响应
        //...
        if (ngx_reconfigure) {
            ngx_start_worker_processes(cycle, ccf->worker_processes,
                                           NGX_PROCESS_RESPAWN);
        }
        //...
    }
    //...
}

static void
ngx_worker_process_init(ngx_cycle_t *cycle, ngx_int_t worker)
{
    //...
    sigemptyset(&set);

    if (sigprocmask(SIG_SETMASK, &set, NULL) == -1) {
        ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                      "sigprocmask() failed");
    }
}




  

 

//用来同步


#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <errno.h> #include <signal.h> static volatile sig_atomic_t sigflag; static sigset_t newmask,oldmask,zeromask; static void printcharacter(const char* str) { const char *ptr; setbuf(stdout,NULL); for(ptr=str;*ptr!='\0';ptr++) putc(*ptr,stdout); } static void sig_usr(int signo) { sigflag = 1; } void TELL_WAIT(void) { signal(SIGUSR1,sig_usr); //设置信号 signal(SIGUSR2,sig_usr); sigemptyset(&zeromask); sigemptyset(&newmask); sigaddset(&newmask,SIGUSR1); sigaddset(&newmask,SIGUSR2); sigprocmask(SIG_BLOCK,&newmask,&oldmask); //把SIGUSR1和SIGUSR2设为阻塞 } void TELL_PARENT(pid_t pid) { kill(pid,SIGUSR2); //向子进程发送信号SIGUSR2 } void TELL_CHILD(pid_t pid) { kill(pid,SIGUSR1); //向父进程发送信号SIGUSR1 } void WAIT_PARENT(void) { while(sigflag == 0) sigsuspend(&zeromask);//将进程挂起。任意等待信号到来,信号处理程序返回 sigflag = 0; sigprocmask(SIG_SETMASK,&oldmask,NULL); } void WAIT_CHILD(void) { while(sigflag == 0) sigsuspend(&zeromask); //将进程挂起。任意等待信号到来,信号处理程序返回 sigflag = 0; sigprocmask(SIG_SETMASK,&oldmask,NULL); } int main() { pid_t pid; TELL_WAIT(); pid = fork(); switch(pid) { case -1: perror("fork() error"); exit(-1); case 0: printcharacter("output from child prcess.\n"); TELL_PARENT(getppid()); WAIT_PARENT(); printcharacter("output2 from child prcess.\n"); break; default: WAIT_CHILD(); printcharacter("output from parent prcess.\n"); TELL_CHILD(pid); } exit(0); }

  

 

父进程将等待子进程的信号,输出字串,随后发送子进程信号证明自己收到信号。

子进程输出字串,随后发送信号给父进程,然后等待父进程的信号后再次输出。

这样的同步方式使得字串永远按以下顺序输出不会乱序。

[root@localhost.localdomain ~]# ./signal_test 
output from child prcess.
output from parent prcess.
output2 from child prcess.