【发布时间】:2017-05-15 14:14:19
【问题描述】:
我必须解决两个进程之间的同步问题,我必须使用信号来解决。
两个进程应该做一定数量的工作,然后向另一个进程发出信号。这将无限期地发生。
我的代码会发生什么:
我向父进程发送信号,父进程向子进程发送信号,子进程再次向父进程发送信号,父进程停止,不再行动。
理想情况下,父母和孩子应该无限期地互相发信号。
int main () {
parent_pid = getpid();
pid_t pid = fork();
if (pid < 0) {
syserr_quit("fork error");
} else if (pid == 0) {
signal(SIGUSR2, child_work);
while (1) {}
} else {
child_pid = pid;
signal(SIGUSR1, parent_work);
while (1) {}
}
}
void child_work (int signo) {
sleep(1); // fake child work
if (kill(parent_pid, SIGUSR1) < 0) syserr_quit("kill error");
// wait for parent signal
pause();
}
void parent_work (int signo) {
sleep(1); // fake parent work
if (kill(child_pid, SIGUSR2) < 0) syserr_quit("kill error");
// wait for child signal
pause();
}
无法弄清楚出了什么问题,因为它的代码量非常少,而且对我来说一切似乎都已经到位。
如果有人想在他们的机器上启动它,这里是 a full demo,它在复制/粘贴后工作。
更新:sigaction(3) 代替 signal(2)
根据一些 cmets,我使用 sigaction 来避免竞争条件,并在演示中停止使用 sleep。
文档指出,为了避免信号接收在处理程序执行期间被阻塞,必须设置 SA_NODEFER 标志。
代码仍然有问题,只是这一次是孩子停止接收信号。
除了signal 被交换 - 两次 - 与
struct sigaction action;
action.sa_handler = parent/child_work;
action.sa_flags = SA_NODEFER;
sigaction(signo, &action, NULL);
完整代码
要启动信号,请从控制台检查并发送信号(即kill -SIGUSR1 <parentid>)
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
void parent_work(int signo);
void child_work(int signo);
void syserr_quit(char *msg);
pid_t parent_pid;
pid_t child_pid;
int main () {
parent_pid = getpid();
printf("parent pid: %d\n", parent_pid);
pid_t pid = fork();
if (pid < 0) {
syserr_quit("fork error");
} else if (pid == 0) {
struct sigaction action;
action.sa_handler = child_work;
action.sa_flags = SA_NODEFER;
sigaction(SIGUSR2, &action, NULL);
while (1) {}
} else {
child_pid = pid;
printf("child pid: %d\n", pid);
struct sigaction action;
action.sa_handler = parent_work;
action.sa_flags = SA_NODEFER;
sigaction(SIGUSR1, &action, NULL);
while (1) {}
}
}
void child_work (int signo) {
for (int i = 0; i < 100000000; ++i); // fake child work
// signal parent that a write is now possible
printf("send signal to %d\n", parent_pid); fflush(stdout);
if (kill(parent_pid, SIGUSR1) < 0) syserr_quit("kill error");
printf("signal sent\n"); fflush(stdout);
// wait for parent signal
pause();
}
void parent_work (int signo) {
for (int i = 0; i < 100000000; ++i); // fake child work
// signal child that a read is possible
printf("send signal to %d\n", child_pid); fflush(stdout);
if (kill(child_pid, SIGUSR2) < 0) syserr_quit("kill error");
printf("signal sent\n"); fflush(stdout);
// wait for child signal
pause();
}
void syserr_quit(char *msg) {
perror(msg);
exit(EXIT_FAILURE);
}
鳍
好吧,伙计们,似乎更新的代码不起作用只是因为我没有正确初始化sigaction 掩码。必须用sigemptyset完成,你可以找出原因right here。
更多详情请见the answer。
【问题讨论】:
-
如前所述,您的代码甚至无法编译。信号处理程序引用未声明的变量,您的所有函数都调用未声明的函数
syserr_quit()。这是minimal reproducible example 的良好开端,但还没有。 -
@JohnBollinger 让我读一下。与此同时,我在问题的最后一行提供了一个完整的 60 行工作演示。
-
不确定这是否与您的问题有关(因为您的代码无法编译),但请引用 Linux
signal(2)手册页:“避免使用它:使用 sigaction(2) ”。 man7.org/linux/man-pages/man2/signal.2.html -
顺便说一句。永远不要在信号处理程序中执行复杂的工作,而只设置标志等。
-
"如果处置被设置为一个函数,那么首先处置被重置为 SIG_DFL,或者信号被阻塞(参见下面的可移植性),并且然后使用参数 signum 调用处理程序。“首先使用
sigaction并将您的处理程序减少为之前建议的标志增量。
标签: c signals fork signal-processing