You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

父进程等待后向子进程发送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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 22:05:11