信号实现父子进程间同步

APUE第十章用信号实现了父子进程间的同步,关键点是sigsuspend函数,这里仔细分析一下实现机制.

 

<tellwait.c>:
#include <signal.h>
#include "ourhdr.h"

/*
数据类型sig_atomic_t由ANSI C定义,在写时不会被中断。它意味着这种变量在具有虚存的系统上不会跨越页边界,可以用一条机器指令对其存取。这种类型的变量总是与ANSI类型修饰符volatile一并出现,防止编译器优化带来的不确定状态。
*/
static volatile sig_atomic_t sigflag;


/* set nonzero by signal handler */
static sigset_t   newmask, oldmask, zeromask;

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

 

/*
父子进程共享正文段,所以,子进程继承信号处理函数;
另外,子进程复制父进程数据空间以及堆栈,所以前面的静态变量在子进程中仍然可以使用.
*/
void
TELL_WAIT()
{
 if (signal(SIGUSR1, sig_usr) == SIG_ERR)
  err_sys("signal(SIGINT) error");
 if (signal(SIGUSR2, sig_usr) == SIG_ERR)
  err_sys("signal(SIGQUIT) 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 */
}

 

/*
sigsuspend相当于sigprocmask + pause,但是它保证这两个操作是原子的,也就是说,在两者之间不会有信号过来.这就保证了信号肯定会被pause截住.这一点是非常重要的,因为如果在pause之前收到信号,信号处理函数被调用,此后如果不再有信号过来,pause将永远阻塞.
*/
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 */
}

 

/*
WAIT_CHILD与WAIT_PARENT完全一样
*/
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");
}

 

测试代码:
#include <sys/types.h>
#include "ourhdr.h"
int
main(void)
{
 pid_t pid;

 TELL_WAIT();

 if ( (pid = fork()) < 0)
  err_sys("fork error");
 else if (pid == 0) {
  WAIT_PARENT();  /* parent goes first */
  printf("output from child\n");
 } else {
  printf("output from parent\n");
  TELL_CHILD(pid);
 }
 exit(0);
}
这样,无论进程如何调度,子进程都将在父进程之后打印信息,达到同步效果.

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值