使用信号的进程同步如何工作?

我最近完成了“Unix环境下的高级编程”(第3版)的第10节(信号),我遇到了一段我不完全理解的代码:

#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"); } 

使用上述例程(您当然知道)使用信号同步进程。 虽然我自己理解每一行,但我无法看到(理解)大局。 代码本身用于以下场景:为了避免程序中的竞争条件,在fork()之后,我们使子进程TELL_PARENT和WAIT_PARENT,然后我们对TELL_CHILD和WAIT_CHILD的父进行同样的操作。 我的问题是:

1.)孩子如何通过变量与父母进行交流,而他们两个都使用自己的变量集(副本)? 是因为孩子不直接修改sigflag而是通过信号处理程序(父母也一样)? 2.)为什么我们需要阻止SIGUSR1和SIGUSR2然后用sigprocmask取消阻塞?

使用其中三个例程的程序可以(取自本书):

 #include "apue.h" static void charatatime(char *); 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 */ 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); /* set unbuffered */ for (ptr = str; (c = *ptr++) != 0; ) putc(c, stdout); } 

干杯,

1)他们没有通过“变量”进行通信 – 这里使用的唯一通信工具是killfunction。 我们通过调用kill “告诉”事情,我们“等待”用sigsuspend告诉sigsuspendsig_flag不是共享的,它是每个进程的本地状态,它表示该特定进程是否已被另一个“告知”。

2)如果信号在fork之前未被阻止,则父进程可以在孩子开始等待之前将信号发送给孩子。 也就是说,时间表可能是这样的:

  • 叉子
  • 父获取时间片,用kill发送信号给孩子
  • 孩子得到时间片,并等待信号

但是这个信号已经发出 ,因此无限期地等待。 因此,我们必须确保在开始等待循环之前不将信号传递给子进程。 为此,我们在fork之前阻塞它,并以primefaces方式解锁它并开始等待它。 primefaces性是关键; 由于信号可以在两者之间传递,因此无法通过作为两个独立步骤执行的此操作来实现所需的不变量。