Linux信号:孩子没有收到
Posted
技术标签:
【中文标题】Linux信号:孩子没有收到【英文标题】:Linux Signal : Child not receiving 【发布时间】:2022-01-22 00:18:22 【问题描述】:我的代码是一个简单的 c 代码,其中有两个进程,第一个是父母发送信号并打印出它发送的内容,另一个是接收信号并打印它收到的内容的孩子 我的代码的输出是 家长:发送 SIGHUP 父母:发送信号 家长:发送 SIGQUIT 它应该是 家长:发送 SIGHUP 孩子收到 SIGHUP 等等……
// C program to implement sighup(), sigint()
// and sigquit() signal functions
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
// function declaration
void sighup(int);
void sigint(int);
void sigquit(int );
void sigsegv(int );
// driver code
int main()
int pid;
/* get child process */
if ((pid = fork()) < 0)
perror("fork");
exit(1);
if (pid == 0) /* child */
signal(SIGHUP, sighup);
signal(SIGINT, sigint);
signal(SIGQUIT, sigquit);
signal(SIGSEGV, sigsegv);
for (;;)
; /* loop for ever */
else /* parent */
/* pid hold id of child */
printf("\nPARENT: sending SIGHUP\n\n");
kill(pid, SIGHUP);
sleep(3); /* pause for 3 secs */
printf("\nPARENT: sending SIGINT\n\n");
kill(pid, SIGINT);
sleep(3); /* pause for 3 secs */
printf("\nPARENT: sending SIGQUIT\n\n");
kill(pid, SIGQUIT);
sleep(3);
return 0 ;
// sighup() function definition
void sighup(int signo)
signal(SIGHUP, sighup); /* reset signal */
printf("CHILD: 1 [sighub]\n");
// sigint() function definition
void sigint(int signo)
signal(SIGINT, sigint); /* reset signal */
printf("CHILD: 2 [sigint]\n");
// sigsegv() function definition
void sigsegv(int signo)
signal(SIGSEGV, sigsegv); /* reset signal */
printf("CHILD: 11 [sigsegv]\n");
// sigquit() function definition
void sigquit(int signo)
signal(SIGINT, sigquit); /* reset signal */
printf("3 [sigquit]\n");
【问题讨论】:
这段代码中的一些习语已经过时和/或危险了。请don't callprintf
in a signal handler,而只使用async-signal-safe 函数。也请use sigaction
, not signal
。至少,您不需要遵循旧的 SysV 约定重新安装信号处理程序。
【参考方案1】:
您的代码逻辑有几个“问题”(除了使用非异步信号安全函数)。
无法保证在fork()
之后哪个进程将开始工作。这取决于内核和系统。 Linux 内核允许您通过在/proc/sys/kernel/sched_child_runs_first
中设置一个值来使其具有确定性,其中如果值为 0(默认),则父级首先运行,如果值为非零,则子级首先运行。然而,依赖此开关进行同步并不是一个好习惯,因为在多处理器环境中,如果我们有可用的 CPU,两者可以同时运行。
进程可以在任何给定时刻被抢占,无论是由于系统调用的使用,还是由于 cpu 时间。因此,不能保证孩子在父母发出信号之前已经设置了所有的信号处理程序,所以一些信号丢失了(实际上在我的测试中,我遇到了所有信号丢失的情况,一旦睡眠被移除)。
和2一样,不能保证在parent发送新信号之前child得到信号。
为了解决问题并保证执行顺序,您需要创建一个同步屏障。这是基于确保同步的 IPC 管道的示例。在示例中,父母等待孩子设置信号,然后,对于它发送的每个信号,它都等待孩子确认信号已收到。
// C program to implement sighup(), sigint()
// and sigquit() signal functions
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
// function declaration
void sighup(int);
void sigint(int);
void sigquit(int );
void sigsegv(int );
int fd[2]; // communication pipe
// driver code
int main()
int pid;
if (pipe(fd)==-1)
fprintf(stderr, "Pipe Failed" );
exit(1);
/* get child process */
if ((pid = fork()) < 0)
perror("fork");
exit(1);
if (pid == 0) /* child */
close(fd[0]); // Close reading end
printf("Preparing the signals");
signal(SIGHUP, sighup);
printf(".");
signal(SIGINT, sigint);
printf(".");
signal(SIGQUIT, sigquit);
printf(".");
signal(SIGSEGV, sigsegv);
printf(".Signals ready\n");
write(fd[1],"ready\0", 6);
for (;;)
; /* loop for ever */
else /* parent */
/* pid hold id of child */
char readb[1024];
readb[1023] = 0; //Safty stop
close(fd[1]); // Close writting end
printf("Waiting for child to finish\n");
read(fd[0], readb, 1023);
printf("Child sends %s", readb);
printf("\nPARENT: sending SIGHUP\n\n");
kill(pid, SIGHUP);
read(fd[0], readb, 1023);
printf("%s\n", readb);
printf("\nPARENT: sending SIGINT\n\n");
kill(pid, SIGINT);
read(fd[0], readb, 1023);
printf("%s\n", readb);
printf("\nPARENT: sending SIGQUIT\n\n");
kill(pid, SIGQUIT);
read(fd[0], readb, 1023);
printf("%s\n", readb);
close(fd[0]);
return 0 ;
// sighup() function definition
void sighup(int signo)
signal(SIGHUP, sighup); /* reset signal */
write(fd[1],"CHILD: 1 [sighub]\0",18);
// sigint() function definition
void sigint(int signo)
signal(SIGINT, sigint); /* reset signal */
write(fd[1],"CHILD: 2 [sigint]\0",18);
// sigsegv() function definition
void sigsegv(int signo)
signal(SIGSEGV, sigsegv); /* reset signal */
write(fd[1],"CHILD: 11 [sigsegv]\0",20);
// sigquit() function definition
void sigquit(int signo)
signal(SIGINT, sigquit); /* reset signal */
write(fd[1],"CHILD: 3 [sigquit]\0",19);
【讨论】:
【参考方案2】:第一个信号可能是在孩子初始化它的信号处理之前发送的。至少我可以通过在if (pid == 0)
之后直接添加sleep(2);
来重现该行为。
在开始发送信号之前尝试在父进程中添加sleep()
【讨论】:
以上是关于Linux信号:孩子没有收到的主要内容,如果未能解决你的问题,请参考以下文章