使用信号的进程同步是如何工作的? [英] How does processes synchronization using signals work?
本文介绍了使用信号的进程同步是如何工作的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
我最近读完了"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,然后用SIGPROMASK解除屏蔽?
使用其中三个例程的程序可以是(摘自本书):
#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
");
} else {
charatatime("output from parent
");
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)它们不是通过"变量"进行通信-此处使用的唯一通信工具是kill
函数。我们通过调用kill
来"告诉"事情,我们"等待"被sigsuspend
告知。sig_flag
不是共享的,它是每个进程的本地状态,它说明此特定进程是否已被其他进程"告知"。
2)如果信号在fork
之前未被阻止,则父进程可以在子进程开始等待信号之前将其发送给子进程。也就是说,时间线可能如下所示:
- 叉子
- 父级获取时间片,用
kill
向子级发送信号 - 子级获取时间片,等待信号
但此信号已发送,因此无限期等待。因此,我们必须确保在子进程开始等待循环之前不会将信号传递给子进程。为此,我们在fork
之前挡路,原子解封开始等待。原子性是关键;此操作作为两个独立的步骤执行时无法实现所需的不变量,因为信号可以在这两个步骤之间传递。
这篇关于使用信号的进程同步是如何工作的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
查看全文