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

fork()实现信号通信与独立闹钟:输出异常问题咨询

信号通信问题排查(分离闹钟与父子进程信号)

问题描述

执行「分离闹钟与父子进程信号通信」任务时,使用fork()编写的代码出现两处异常:

  • 在user2函数中用getpid()获取子进程PID,预期为22732,但实际输出22731;
  • 输出末尾出现未编写打印逻辑的「User defined signal 2」消息,来源不明。

原代码

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

void child_handler (int signum){
        printf("Child  (PID=%d) alarm went off\n", getpid());
        // send signal to parent
        kill( getppid(), SIGUSR1 ); 
        exit(EXIT_SUCCESS);
    }
    
void parent_handler (int signum){
        printf("Parent (PID=%d) received SIGUSR1 from child after child's alarm\n", getppid());
    }
    
void user2 (int signum){
        printf("Parent (PID=%d) alarm went off\n", getppid());
        printf("Parent (PID=%d) sending SIGUSR2 to my child %d\n", getppid(), getpid());
        kill( getpid(), SIGUSR2 );
        exit(EXIT_SUCCESS);
    }
    
int main(){
        int pid;
        int status;
        
        // 1.The parent process forks a child process.
        pid = fork();
        
        if (pid == 0){
            // child process
            printf("Child  (PID=%d) setting my alarm to 3 and then wait via pause()\n", getpid());
            signal(SIGALRM, child_handler);
            alarm(3);
            pause();
            // 2. The child process sets an alarm for 3 seconds and waits for the SIGALRM signal.
        } else if (pid > 0){
            // parent process
            printf("Parent (PID=%d) preparing waiting for SIGUSR1 via pause()\n", getppid());
            
            signal(SIGUSR1, parent_handler);
            pause();     
        
            // 5.The parent process sets an alarm for 5 seconds and waits for its SIGALRM signal.
            printf("Parent (PID=%d) Setting alarm for 5 seconds and wait via pause()\n", getppid());
            signal(SIGALRM, user2);
            alarm(5);
            pause();
    
            //waitpid(pid, &status, 0);
                
            
        } else {
            // error 
            perror("Failed to fork child process.\n");
            exit(EXIT_FAILURE);
        }
        return 0;
}

原运行输出

Parent (PID=15925) preparing waiting for SIGUSR1 via pause()
Child  (PID=22732) setting my alarm to 3 and then wait via pause()
Child  (PID=22732) alarm went off
Parent (PID=15925) received SIGUSR1 from child after child's alarm
Parent (PID=15925) Setting alarm for 5 seconds and wait via pause()
Parent (PID=15925) alarm went off
Parent (PID=15925) sending SIGUSR2 to my child 22731
User defined signal 2

问题分析与修复

1. 子进程PID获取错误

  • 原因:user2是父进程的信号处理函数,在父进程中调用getpid()返回的是父进程自身的PID,而非子进程PID。子进程PID存储在main函数的局部变量pid中,user2无法访问该变量,导致输出错误;此外原代码中父进程打印自身PID时误用getppid()(返回父进程的父进程,即Shell进程的PID),应改为getpid()。
  • 修复:将子进程PID存储为全局变量,让user2能直接获取;同时修正父进程打印自身PID的调用。

2. 「User defined signal 2」消息来源

  • 原因:user2函数中kill(getpid(), SIGUSR2)是给父进程自身发送SIGUSR2信号,但未给父进程设置该信号的自定义处理函数,系统触发默认逻辑,打印该消息并终止进程。另外子进程在3秒后已退出,即使正确发送信号也会报错,但当前核心错误是信号发送对象错误。
  • 修复:将kill(getpid(), SIGUSR2)改为kill(child_pid, SIGUSR2),给子进程发送信号;同时添加错误处理,避免子进程已退出时的报错。

修复后代码

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

// 全局变量存储子进程PID,供user2函数访问
pid_t child_pid;

void child_handler (int signum){
    printf("Child  (PID=%d) alarm went off\n", getpid());
    // 向父进程发送SIGUSR1
    kill(getppid(), SIGUSR1); 
    exit(EXIT_SUCCESS);
}

void parent_handler (int signum){
    printf("Parent (PID=%d) received SIGUSR1 from child after child's alarm\n", getpid());
}

void user2 (int signum){
    printf("Parent (PID=%d) alarm went off\n", getpid());
    printf("Parent (PID=%d) sending SIGUSR2 to my child %d\n", getpid(), child_pid);
    // 向子进程发送SIGUSR2,添加错误处理
    if (kill(child_pid, SIGUSR2) == -1) {
        perror("Failed to send SIGUSR2 to child");
    }
    exit(EXIT_SUCCESS);
}

int main(){
    int status;
    
    // 父进程创建子进程
    child_pid = fork();
    
    if (child_pid == 0){
        // 子进程逻辑
        printf("Child  (PID=%d) setting my alarm to 3 and then wait via pause()\n", getpid());
        signal(SIGALRM, child_handler);
        alarm(3);
        pause();
    } else if (child_pid > 0){
        // 父进程逻辑
        printf("Parent (PID=%d) preparing waiting for SIGUSR1 via pause()\n", getpid());
        
        signal(SIGUSR1, parent_handler);
        pause();     
    
        // 设置5秒闹钟并等待
        printf("Parent (PID=%d) Setting alarm for 5 seconds and wait via pause()\n", getpid());
        signal(SIGALRM, user2);
        alarm(5);
        pause();

        // 等待子进程退出,避免僵尸进程
        waitpid(child_pid, &status, 0);
            
    } else {
        // fork失败处理
        perror("Failed to fork child process.\n");
        exit(EXIT_FAILURE);
    }
    return 0;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 20:15:20