信号实现父子进程之间的同步--sigsuspend的作用

函数原型:

  #include <signal.h>
  int sigsuspend(const sigset_t *mask);

作用:

  用于在接收到某个信号之前,临时用mask替换进程的信号掩码,并暂停进程执行,直到收到信号为止。

  也就是说,sigsuspend后,进程就挂在那里,等待着开放的信号的唤醒系统在接收到信号后,马上就把现在的信号集还原为原来的,然后调用处理函数

返回值:
  sigsuspend返回后将恢复调用之前的的信号掩码。信号处理函数完成后,进程将继续执行。该系统调用始终返回-1,并将errno设置为EINTR.
  Since sigsuspend() suspends process execution indefinitely, there is no successful completion return value. If a return occurs, -1 is returned and errno is set to indicate the error.
  The sigsuspend() function will fail if:
  [EINTR]
  A signal is caught by the calling process and control is returned from the signal-catching function.

也就是说,sigsuspend后,进程就挂在那里,等待着开放的信号的唤醒。系统在接受到信号后,马上就把现在的信号集还原为原来的,然后调用处理函数。


Stevens在《Unix环境高级编程》一书中是如是回答的“If a signal is caught and if the signal handler returns, then sigsuspend returns and the signal mask of the process is set to its value before the call to sigsuspend.”,由于sigsuspend是原子操作,所以这句给人的感觉就是先调用signal handler先返回,然后sigsuspend再返回。

[cpp]  view plain copy print ?
  1. int main(void) {    
  2.    sigset_t   newmask, oldmask, zeromask;    
  3.     
  4.    if (signal(SIGINT, sig_int) == SIG_ERR)    
  5.       err_sys("signal(SIGINT) error");    
  6.     
  7.    sigemptyset(&zeromask);    
  8.     
  9.    sigemptyset(&newmask);    
  10.    sigaddset(&newmask, SIGINT);    
  11.    /* block SIGINT and save current signal mask */    
  12.    if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)    
  13.       err_sys("SIG_BLOCK error");    
  14.     
  15.    /* critical region of code */    
  16.    pr_mask("in critical region: ");    
  17.     
  18.    /* allow all signals and pause */    
  19.    if (sigsuspend(&zeromask) != -1)    
  20.       err_sys("sigsuspend error");    
  21.    pr_mask("after return from sigsuspend: ");    
  22.     
  23.    /* reset signal mask which unblocks SIGINT */    
  24.    if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)    
  25.       err_sys("SIG_SETMASK error");    
  26.     
  27.    /* and continue processing ... */    
  28.    exit(0);    
  29. }    
  30.     
  31. static void sig_int(int signo) {    
  32.    pr_mask("\nin sig_int: ");    
  33.    return;    
  34. }    
结果:

[cpp]  view plain copy print ?
  1. $a.out    
  2. in critical region: SIGINT    
  3. ^C    
  4. in sig_int: SIGINT    
  5. after return from sigsuspend: SIGINT    

如果按照sig_handler先返回,那么SIGINT是不该被打印出来的,因为那时屏蔽字还没有恢复,所有信号都是不阻塞的。那么是Stevens说错了么?当然没有,只是Stevens没有说请在sigsuspend的原子操作中到底做了什么?
sigsuspend的整个原子操作过程为:
(1) 设置新的mask阻塞当前进程;
(2) 收到信号,恢复原先mask;
(3) 调用该进程设置的信号处理函数;
(4) 待信号处理函数返回后,sigsuspend返回。


[cpp]  view plain copy print ?
  1. #include <stdio.h>    
  2. #include <signal.h>    
  3.     
  4. void checkset();    
  5. void func();    
  6. void main()    
  7. {    
  8.      sigset_tblockset,oldblockset,zeroset,pendmask;    
  9.      printf("pid:%ld\n",(long)getpid());    
  10.      signal(SIGINT,func);    
  11.     
  12.      sigemptyset(&blockset);    
  13.      sigemptyset(&zeroset);    
  14.      sigaddset(&blockset,SIGINT);    
  15.     
  16.      sigprocmask(SIG_SETMASK,&blockset,&oldblockset);    
  17.      checkset();    
  18.      sigpending(&pendmask);    
  19.     
  20.      if(sigismember(&pendmask,SIGINT))    
  21.          printf("SIGINTpending\n");    
  22.     
  23.      if(sigsuspend(&zeroset)!= -1)    
  24.      {    
  25.      printf("sigsuspenderror\n");    
  26.      exit(0);    
  27.      }    
  28.     
  29.      printf("afterreturn\n");    
  30.      sigprocmask(SIG_SETMASK,&oldblockset,NULL);    
  31.     
  32.      printf("SIGINTunblocked\n");    
  33. }    
  34.     
  35. void checkset()    
  36. {    sigset_tset;    
  37.      printf("checksetstart:\n");    
  38.      if(sigprocmask(0,NULL,&set)<0)    
  39.      {    
  40.      printf("checksetsigprocmask error!!\n");    
  41.      exit(0);    
  42.      }    
  43.     
  44.      if(sigismember(&set,SIGINT))    
  45.      printf("sigint\n");    
  46.     
  47.      if(sigismember(&set,SIGTSTP))    
  48.      printf("sigtstp\n");    
  49.     
  50.      if(sigismember(&set,SIGTERM))    
  51.      printf("sigterm\n");    
  52.      printf("checksetend\n");    
  53. }    
  54.     
  55. void func()    
  56. {    
  57.      printf("hellofunc\n");    
  58. }    

信号实现父子进程之间的同步--sigsuspend的作用_第1张图片


父子进程同步到方法如下:

[cpp]  view plain copy print ?
  1. <span style="font-size:18px;"><strong>#include "apue.h"  
  2.   
  3. static volatile sig_atomic_t sigflag; /* set nonzero by sig handler */  
  4. static sigset_t newmask, oldmask, zeromask;  
  5.   
  6. static void  
  7. sig_usr(int signo)  /* one signal handler for SIGUSR1 and SIGUSR2 */  
  8. {  
  9.     sigflag = 1;  
  10. }  
  11.   
  12. void  
  13. TELL_WAIT(void)  
  14. {  
  15.     if (signal(SIGUSR1, sig_usr) == SIG_ERR)  
  16.         err_sys("signal(SIGUSR1) error");  
  17.     if (signal(SIGUSR2, sig_usr) == SIG_ERR)  
  18.         err_sys("signal(SIGUSR2) error");  
  19.     sigemptyset(&zeromask);  
  20.     sigemptyset(&newmask);  
  21.     sigaddset(&newmask, SIGUSR1);  
  22.     sigaddset(&newmask, SIGUSR2);  
  23.   
  24.     /* 
  25.      * Block SIGUSR1 and SIGUSR2, and save current signal mask. 
  26.      */  
  27.     if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)  
  28.         err_sys("SIG_BLOCK error");  
  29. }  
  30.   
  31. void  
  32. TELL_PARENT(pid_t pid)  
  33. {  
  34.     kill(pid, SIGUSR2);     /* tell parent we're done */  
  35. }  
  36.   
  37. void  
  38. WAIT_PARENT(void)  
  39. {  
  40.     while (sigflag == 0)  
  41.         sigsuspend(&zeromask);  /* and wait for parent */  
  42.     sigflag = 0;  
  43.   
  44.     /* 
  45.      * Reset signal mask to original value. 
  46.      */  
  47.     if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)  
  48.         err_sys("SIG_SETMASK error");  
  49. }  
  50.   
  51. void  
  52. TELL_CHILD(pid_t pid)  
  53. {  
  54.     kill(pid, SIGUSR1);         /* tell child we're done */  
  55. }  
  56.   
  57. void  
  58. WAIT_CHILD(void)  
  59. {  
  60.     while (sigflag == 0)  
  61.         sigsuspend(&zeromask);  /* and wait for child */  
  62.     sigflag = 0;  
  63.   
  64.     /* 
  65.      * Reset signal mask to original value. 
  66.      */  
  67.     if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)  
  68.         err_sys("SIG_SETMASK error");  
  69. }  
  70. </strong></span>  

你可能感兴趣的:(信号实现父子进程之间的同步--sigsuspend的作用)