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

函数原型:

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

作用:

  用于在接收到某个信号之前,临时用mask替换进程的信号掩码,并暂停进程执行,直到收到信号为止。
  Thesigsuspend()function replaces the current signal mask of the calling thread with the set of signals pointed to bysigmaskand then suspends the thread until delivery of a signal whose action is either to execute a signal-catching function or to terminate the process. This will not cause any other signals that may have been pending on the process to become pending on the thread.
  If the action is to terminate the process thensigsuspend()will never return. If the action is to execute a signal-catching function, thensigsuspend()will return after the signal-catching function returns, with the signal mask restored to the set that existed prior to thesigsuspend()call.
  It is not possible to block signals that cannot be ignored. This is enforced by the system without causing an error to be indicated.
  也就是说,sigsuspend后,进程就挂在那里,等待着开放的信号的唤醒。系统在接收到信号后,马上就把现在的信号集还原为原来的,然后调用处理函数。

返回值:
  sigsuspend返回后将恢复调用之前的的信号掩码。信号处理函数完成后,进程将继续执行。该系统调用始终返回-1,并将errno设置为EINTR.
  Sincesigsuspend()suspends process execution indefinitely, there is no successful completion return value. If a return occurs, -1 is returned anderrnois set to indicate the error.
  Thesigsuspend()function will fail if:
  [EINTR]
  A signal is caught by the calling process and control is returned from the signal-catching function.<wbr style="line-height:25px; color:rgb(85,73,15); font-family:Arial,Helvetica,simsun,u5b8bu4f53"></wbr>

也就是说,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再返回。

int main(void) {  
   sigset_t   newmask, oldmask, zeromask;  
  
   if (signal(SIGINT, sig_int) == SIG_ERR)  
      err_sys("signal(SIGINT) error");  
  
   sigemptyset(&zeromask);  
  
   sigemptyset(&newmask);  
   sigaddset(&newmask, SIGINT);  
   /* block SIGINT and save current signal mask */  
   if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)  
      err_sys("SIG_BLOCK error");  
  
   /* critical region of code */  
   pr_mask("in critical region: ");  
  
   /* allow all signals and pause */  
   if (sigsuspend(&zeromask) != -1)  
      err_sys("sigsuspend error");  
   pr_mask("after return from sigsuspend: ");  
  
   /* reset signal mask which unblocks SIGINT */  
   if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)  
      err_sys("SIG_SETMASK error");  
  
   /* and continue processing ... */  
   exit(0);  
}  
  
static void sig_int(int signo) {  
   pr_mask("\nin sig_int: ");  
   return;  
}  
结果:

$a.out  
in critical region: SIGINT  
^C  
in sig_int: SIGINT  
after return from sigsuspend: SIGINT  

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


#include <stdio.h>  
#include <signal.h>  
  
void checkset();  
void func();  
void main()  
{  
     sigset_tblockset,oldblockset,zeroset,pendmask;  
     printf("pid:%ld\n",(long)getpid());  
     signal(SIGINT,func);  
  
     sigemptyset(&blockset);  
     sigemptyset(&zeroset);  
     sigaddset(&blockset,SIGINT);  
  
     sigprocmask(SIG_SETMASK,&blockset,&oldblockset);  
     checkset();  
     sigpending(&pendmask);  
  
     if(sigismember(&pendmask,SIGINT))  
         printf("SIGINTpending\n");  
  
     if(sigsuspend(&zeroset)!= -1)  
     {  
     printf("sigsuspenderror\n");  
     exit(0);  
     }  
  
     printf("afterreturn\n");  
     sigprocmask(SIG_SETMASK,&oldblockset,NULL);  
  
     printf("SIGINTunblocked\n");  
}  
  
void checkset()  
{    sigset_tset;  
     printf("checksetstart:\n");  
     if(sigprocmask(0,NULL,&set)<0)  
     {  
     printf("checksetsigprocmask error!!\n");  
     exit(0);  
     }  
  
     if(sigismember(&set,SIGINT))  
     printf("sigint\n");  
  
     if(sigismember(&set,SIGTSTP))  
     printf("sigtstp\n");  
  
     if(sigismember(&set,SIGTERM))  
     printf("sigterm\n");  
     printf("checksetend\n");  
}  
  
void func()  
{  
     printf("hellofunc\n");  
}  



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

#include "apue.h"

static volatile sig_atomic_t sigflag; /* set nonzero by sig handler */
static sigset_t newmask, oldmask, zeromask;

static void
sig_usr(int signo)	/* one signal handler for SIGUSR1 and SIGUSR2 */
{
	sigflag = 1;
}

void
TELL_WAIT(void)
{
	if (signal(SIGUSR1, sig_usr) == SIG_ERR)
		err_sys("signal(SIGUSR1) error");
	if (signal(SIGUSR2, sig_usr) == SIG_ERR)
		err_sys("signal(SIGUSR2) error");
	sigemptyset(&zeromask);
	sigemptyset(&newmask);
	sigaddset(&newmask, SIGUSR1);
	sigaddset(&newmask, SIGUSR2);

	/*
	 * Block SIGUSR1 and SIGUSR2, and save current signal mask.
	 */
	if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)
		err_sys("SIG_BLOCK error");
}

void
TELL_PARENT(pid_t pid)
{
	kill(pid, SIGUSR2);		/* tell parent we're done */
}

void
WAIT_PARENT(void)
{
	while (sigflag == 0)
		sigsuspend(&zeromask);	/* and wait for parent */
	sigflag = 0;

	/*
	 * Reset signal mask to original value.
	 */
	if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
		err_sys("SIG_SETMASK error");
}

void
TELL_CHILD(pid_t pid)
{
	kill(pid, SIGUSR1);			/* tell child we're done */
}

void
WAIT_CHILD(void)
{
	while (sigflag == 0)
		sigsuspend(&zeromask);	/* and wait for child */
	sigflag = 0;

	/*
	 * Reset signal mask to original value.
	 */
	if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
		err_sys("SIG_SETMASK error");
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值