gpt4 book ai didi

c - 为什么这个进程不再处理 S​​IGUSR1?

转载 作者:行者123 更新时间:2023-11-30 14:57:20 27 4
gpt4 key购买 nike

我必须解决两个进程之间的同步问题,并且我必须使用信号来完成它。

两个进程应该完成给定量的工作,然后向另一个进程发出信号。这将无限期地发生。

我的代码发生的情况是:

我向父进程发送信号,父进程向子进程发送信号,子进程再次向父进程发送信号,子进程被停止并且不再执行。

理想情况下, parent 和 child 应该无限期地互相发出信号。

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)

根据一些评论,我诉诸使用 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 .

最佳答案

当调用 SIGUSR1 信号处理程序 parent_work 时,SIGUSR1 信号会映射到 SIG_DFL(默认信号处理)或忽略父进程(引用 signal ):

When a signal occurs, and func points to a function, it is implementation-defined whether the equivalent of a:

signal(sig, SIG_DFL);

is executed or the implementation prevents some implementation-defined set of signals (at least including sig) from occurring until the current signal handling has completed.

当子进程再次为父进程生成 SIGUSR1 信号时,它不会因此再次调用 parent_work 信号处理程序。

因此,在信号处理程序中,如果您希望后续信号也由信号处理程序处理,则需要再次重新注册信号:

void parent_work(int signo) {
/* your handler code */
signal(signo, parent_work);
}

请注意,这仍然为竞争条件留下了空间 - 即。如果第二个 SIGUSR1 在信号处理程序重新注册之前到达。但实际上,这是您设计的本质。

当然有更好的选择和一般建议。其中一些已经在评论中提到过,所以如果您有兴趣,我将引用这些内容。

关于c - 为什么这个进程不再处理 S​​IGUSR1?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43981759/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com