父进程等待后向子进程发送SIGUSR1信号无响应问题
问题:父进程wait后发送SIGUSR1给子进程child_b,信号处理函数未执行
父进程在执行waitpid操作后,向子进程child_b发送SIGUSR1信号,但对应的信号处理函数未触发,无法输出预期的"pong quitting"信息。尝试过添加sleep调整时序、调换wait与kill顺序,问题仍未解决。
相关代码
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/wait.h> #include <signal.h> int fd[2][2]; void sig_handler(int signum) { if (signum == SIGUSR1) { printf("pong quitting\n"); exit(1); } } void f1() { int x = 0; close(fd[0][0]); close(fd[1][1]); while (x <= 100) { printf("ping: %d\n", x); x++; if (write(fd[0][1], &x, sizeof(int)) < 0) { printf("Error writing f1\n"); } if (read(fd[1][0], &x, sizeof(int)) < 0) { printf("Error reading f1\n"); } } close(fd[0][1]); close(fd[1][0]); } void f2() { int x = 0; close(fd[0][1]); close(fd[1][0]); while (x <= 100) { if (read(fd[0][0], &x, sizeof(int)) < 0) { printf("Error reading f2\n"); } if (x <= 100) printf("pong: %d\n", x); x++; if (write(fd[1][1], &x, sizeof(int)) < 0) { printf("Error writing f2\n"); } } close(fd[0][0]); close(fd[1][1]); } int main(void) { for (int i = 0; i < 2; i++) { if (pipe(fd[i]) < 0) { printf("Error opening pipe.\n"); return 1; } } pid_t child_a = fork(); if (child_a < 0) { printf("Error forking child_a.\n"); return 2; } if (child_a == 0) { f1(); } else { pid_t child_b = fork(); if (child_b < 0) { printf("Error forking child_b.\n"); return 3; } if (child_b == 0) { signal(SIGUSR1, sig_handler); f2(); } else { waitpid(child_a, NULL, 0); waitpid(child_b, NULL, 0); kill(child_b, SIGUSR1); } } return 0; }
问题原因
核心逻辑错误:父进程中先调用了waitpid(child_b, NULL, 0),这个调用会一直阻塞到child_b进程完全终止,之后再执行kill(child_b, SIGUSR1)时,child_b已经不存在了,信号无法送达目标进程,自然不会触发信号处理函数。
解决方法
1. 调整父进程的wait与kill顺序
将kill操作移到waitpid(child_b, ...)之前,先发送信号终止child_b,再等待它退出:
else { waitpid(child_a, NULL, 0); // 先发送SIGUSR1终止child_b,再等待其退出 kill(child_b, SIGUSR1); waitpid(child_b, NULL, 0); }
2. 修复child_b的管道读取逻辑
当child_a执行完毕关闭管道写端后,child_b的read会返回0(表示管道已无数据且写端关闭),原代码未处理这种情况,会导致x被设为0,进入无限循环。需要补充read返回值的判断:
void f2() { int x = 0; close(fd[0][1]); close(fd[1][0]); while (x <= 100) { ssize_t n = read(fd[0][0], &x, sizeof(int)); if (n < 0) { printf("Error reading f2\n"); break; } else if (n == 0) { // 管道写端关闭,退出循环 break; } if (x <= 100) printf("pong: %d\n", x); x++; if (write(fd[1][1], &x, sizeof(int)) < 0) { printf("Error writing f2\n"); } } close(fd[0][0]); close(fd[1][1]); }
3. 替换signal为sigaction(可选但推荐)
signal函数的行为在不同系统中存在兼容性问题,建议使用标准的sigaction来注册信号处理函数,同时避免在信号处理中使用异步不安全的printf:
void sig_handler(int signum) { if (signum == SIGUSR1) { const char msg[] = "pong quitting\n"; write(STDOUT_FILENO, msg, sizeof(msg) - 1); exit(1); } } // 在child_b的代码中替换signal调用: struct sigaction sa; sa.sa_handler = sig_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sigaction(SIGUSR1, &sa, NULL);
内容的提问来源于stack exchange,提问作者bscottunit
相关产品推荐
相关产品推荐

