日期:2014-05-16  浏览次数:20762 次

linux进程间同步
在stevens大师的书中看到如下代码:
#include "apue.h"

static void charatatime(char *);

int main()
{
  pid_t pid;
  
  TELL_WAIT();
  
  if((pid = fork()) < 0)
  {
  err_sys("fork error");
  }
  else if(pid == 0)
  {
  WAIT_PARENT();
  charatatime("output from child\n");
  }
  else
  {
  charatatime("output from parent\n");
  TELL_CHILD(pid);
  }
  exit(0);
}

static void charatatime(char *str)
{
  char *ptr;
  int c;
  setbuf(stdout, NULL);
  for(ptr = str; (c = *ptr++) != 0;)
  putc(c, stdout);

其中TELL_WAIT、WAIT_PARENT、TELL_CHILD在另外一个文件tellwait.c中,被编译成lib文件,如下:
#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");
}
我想问的是,tellwait.c中的sigflag是父子进程共享的吗?链接库难道父子进程共享吗?链接库不是采用写时复制机制吗?求高手指点迷津啊。。。。

------解决方案--------------------
信号啊,共享个屁啊。

父进程kill信号给子进程,子进程信号函数标记变量,sigsuspend被唤醒检查变量满足,于是子进程开始执行。

父进程在kill信号之后开始等待子进程给它kill信号,同样是sigprocmask +sigsuspend的等待,子进程kill信号给父进程,父进程sigsuspend被唤醒检查变量被设置于是程序结束。

这个编程方法和条件变量+互斥量是完全一样的:

pthread_mutex_lock == sigprocmask
pthread_cond_wait == sigsuspend
pthread_cond_signal == kill
pthread_mutex_unlock == sigprocmask

加锁/阻塞信号 是为了在检查变量时是线程安全的, 而sigsuspend/cond_wait是保证解锁/解信号阻塞与挂起等待是原子的, 这样才能保证不漏掉信号/条件的唤醒.