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

SIGUSR1父子进程通信问题:信号处理函数消息无法打印排查

问题分析与修复方案

核心问题点

  1. 信号处理注册时机错误
    父进程先执行wait(NULL),再注册SIGUSR1的处理函数。第一个子进程会立即发送信号,此时父进程还没完成信号处理函数的注册,信号会触发默认行为(SIGUSR1默认会终止进程),后续逻辑根本无法执行;就算父进程没被终止,提前发送的信号也会直接丢失。

  2. 错误使用signal()函数
    代码里用if(signal(SIGUSR1, handle_sigusr1))来判断是否收到信号,这是完全错误的用法。signal()的作用是设置信号处理函数,返回值是之前的处理函数指针,它不能检测信号是否到达。这段代码只会重复设置一次信号处理函数,不会在收到信号时执行里面的计数和打印逻辑。

  3. 信号处理函数的描述逻辑错误
    处理函数里的printf("Sending ready command...\n")描述反了,这个函数是父进程收到子进程信号时执行的,应该体现“收到就绪指令”的语义。

  4. 未等待所有子进程退出
    父进程只调用了一次wait(NULL),会导致其中一个子进程变成僵尸进程,需要调用两次或者用循环等待来回收所有子进程。


修正后的代码

#include<stdio.h>
#include<unistd.h>
#include<signal.h>
#include<stdlib.h>
#include<sys/wait.h>

int x = 0;

void handle_sigusr1(int sig){
    x++;
    printf("Controller: Received ready command. Total %d\n", x);
}

int main(int args, char* argv[]){
    int player0, player1;

    // 先注册信号处理函数,再创建子进程
    struct sigaction sa = { 0 };
    sa.sa_flags = SA_RESTART;
    sa.sa_handler = &handle_sigusr1;
    sigaction(SIGUSR1, &sa, NULL);

    player0 = fork();
    if(player0 != 0){
        player1 = fork();
    }

    if(player0 == 0){
        kill(getppid(), SIGUSR1);
        sleep(2);
        exit(0);
    } else if(player1 == 0){
        sleep(3);
        kill(getppid(), SIGUSR1);
        sleep(2);
        exit(0);
    } else {
        // 等待两个子进程退出
        wait(NULL);
        wait(NULL);
        printf("All children have exited.\n");
    }

    return 0;
}

修正说明

  • 把信号处理函数的注册逻辑移到创建子进程之前,确保父进程在子进程发送信号前已经准备好处理信号。
  • 把计数和打印逻辑移到信号处理函数里,这样每次收到SIGUSR1时都会执行计数和输出。
  • 修正了处理函数里的输出文本,符合实际语义。
  • 父进程调用两次wait(NULL),确保两个子进程都被回收,避免僵尸进程。

内容的提问来源于stack exchange,提问作者Phillips

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 14:50:36