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

父进程循环随机发送SIGUSR1/SIGUSR2给子进程失败问题排查

问题分析与修复方案

核心问题点

  • PID传递错误:父进程调用parent_func(0),kill(0, 信号)会向当前进程组所有进程发信号,后续循环无法精准定位子进程。应传递fork返回的子进程PID。
  • 重复设置信号处理:子进程循环内反复调用signal()重置信号处理,冗余且可能引发异常。信号处理只需初始化一次,推荐用sigaction替代signal(行为更稳定可移植)。
  • 随机数种子重复初始化:每次调用parent_func都执行srand(time(NULL)),短时间内time(NULL)返回相同值,导致随机数重复,信号选择失去随机性。
  • 未实现信号写入文件逻辑:原需求要求子进程接收信号后写入文件,但当前信号处理函数仅打印信息,未完成文件写入。

修复后的完整代码

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

// 声明日志函数
void log_signal(int sig);

void handler_sigusr1(int sig) {
    if (sig == SIGUSR1) {
        puts("child received SIGUSR1");
        log_signal(SIGUSR1);
    }
}

void handler_sigusr2(int sig) {
    if (sig == SIGUSR2) {
        puts("child received SIGUSR2");
        log_signal(SIGUSR2);
    }
}

void parent_send_signal(int child_pid) {
    int rnd = rand();
    int target_sig = (rnd & 1) ? SIGUSR2 : SIGUSR1;
    struct timeval t;
    gettimeofday(&t, NULL);
    unsigned long time = 1000000 * t.tv_sec + t.tv_usec;

    printf("signal to send: %d\n", target_sig);
    printf("current timestamp: %ld\n", time);

    kill(child_pid, target_sig);
}

void log_signal(int sig) {
    FILE *file = fopen("received_signal.txt", "a");
    if (file == NULL) {
        perror("fopen failed");
        return;
    }
    struct timeval t;
    gettimeofday(&t, NULL);
    unsigned long time = 1000000 * t.tv_sec + t.tv_usec;
    fprintf(file, "%s\t%ld\t%d\n", 
            sig == SIGUSR1 ? "SIGUSR1" : "SIGUSR2",
            time,
            getpid());
    fclose(file);
}

int main(int argc, char* argv[], char *envp[]) {
    // 初始化日志文件表头
    FILE *file = fopen("received_signal.txt", "w");
    if (file == NULL) {
        perror("fopen failed");
        exit(EXIT_FAILURE);
    }
    fprintf(file, "%s\t%s\t%s\n", "Signal Type", "Signal Time", "Process ID");
    fclose(file);

    pid_t pid = fork();
    if (pid == 0) { // 子进程:接收信号
        struct sigaction sact1, sact2;
        // 配置SIGUSR1处理
        sact1.sa_handler = handler_sigusr1;
        sigemptyset(&sact1.sa_mask);
        sact1.sa_flags = 0;
        sigaction(SIGUSR1, &sact1, NULL);
        // 配置SIGUSR2处理
        sact2.sa_handler = handler_sigusr2;
        sigemptyset(&sact2.sa_mask);
        sact2.sa_flags = 0;
        sigaction(SIGUSR2, &sact2, NULL);

        // 子进程进入休眠循环等待信号
        while (1) {
            sleep(1);
        }
    } else { // 父进程:发送信号
        srand(time(NULL)); // 仅初始化一次随机数种子
        while (1) {
            printf("parent loop running\n");
            parent_send_signal(pid);
            usleep(((rand() % 5) + 1) * 10000); // 随机延迟0.01-0.05秒
        }
    }
    return 0;
}

修复说明

  1. PID传递修正:父进程调用parent_send_signal(pid),将子进程PID传入,确保kill精准发送信号到目标进程。
  2. 信号处理优化:子进程使用sigaction一次性配置信号处理逻辑,无需循环重置,行为更稳定。
  3. 随机数种子优化:父进程在循环外仅初始化一次srand,避免短时间内重复种子导致随机数相同。
  4. 文件写入实现:补充log_signal函数,以追加模式打开日志文件,写入信号类型、时间戳和进程ID,满足需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 16:25:23