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

多子进程间基于SIGNALS的直接通信实现技术问询

问题描述

所有进程创建完成后,信号将沿红色箭头由前一个进程发送(示意图)
我需要编写一个使用fork()创建多个子进程的程序,让子进程随机向“下一个”子进程发送信号(可想象为图结构)。据我了解,父进程与子进程之间可通过kill()函数和PID实现通信,但尚未找到子进程之间直接通信的方法,这是否可行?我仅被允许使用信号进行通信。

目前我尝试的方案是:子进程向父进程发送信号,再由父进程向兄弟子进程发送信号。但当进程数量增加时,由于缺少对应PID,该方案无法正常工作。

重要说明:只能使用信号(不能使用管道、信号量及其他IPC解决方案)

解决方案

子进程之间直接用信号通信完全可行,核心是让所有子进程获取到其他兄弟进程的PID,具体实现思路如下:

  • 父进程统一分发PID列表

    1. 父进程创建子进程时,将每个子进程的PID存入数组保存。
    2. 所有子进程创建完成后,父进程通过带数据的信号(sigqueue())把PID列表传递给每个子进程;如果不能用sigqueue,也可以多次发送信号,每次传递一个PID的片段,子进程拼接后得到完整列表;另外,也可以用共享内存传递PID列表(仅用于传递PID,后续通信仍只用信号,符合限制)。
    3. 确保所有子进程都接收到PID列表后,再启动信号交互流程。
  • 子进程直接通信实现
    子进程拿到兄弟进程的PID后,直接调用kill(目标PID, 信号)或sigqueue(目标PID, 信号, 附加数据)即可向任意兄弟进程发送信号,无需父进程中转。

  • 代码示例片段

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

pid_t *pid_list;
int process_count;

// 信号处理函数,支持接收带数据的信号
void sig_handler(int signo, siginfo_t *info, void *context) {
    if (signo == SIGUSR1) {
        // 模拟已获取PID列表,随机选择目标进程发送信号
        int target_idx = rand() % process_count;
        kill(pid_list[target_idx], SIGUSR2);
        printf("进程 %d 向 %d 发送 SIGUSR2\n", getpid(), pid_list[target_idx]);
    } else if (signo == SIGUSR2) {
        printf("进程 %d 收到 SIGUSR2\n", getpid());
    }
}

int main(int argc, char *argv[]) {
    if (argc != 2) {
        fprintf(stderr, "用法:%s <进程数量>\n", argv[0]);
        exit(EXIT_FAILURE);
    }
    process_count = atoi(argv[1]);
    pid_list = malloc(process_count * sizeof(pid_t));
    if (!pid_list) {
        perror("内存分配失败");
        exit(EXIT_FAILURE);
    }

    // 配置信号处理,启用SA_SIGINFO以接收带数据的信号
    struct sigaction sa;
    sa.sa_sigaction = sig_handler;
    sa.sa_flags = SA_SIGINFO;
    sigemptyset(&sa.sa_mask);
    sigaction(SIGUSR1, &sa, NULL);
    sigaction(SIGUSR2, &sa, NULL);

    // 创建所有子进程
    for (int i = 0; i < process_count; i++) {
        pid_t pid = fork();
        if (pid == -1) {
            perror("fork失败");
            exit(EXIT_FAILURE);
        } else if (pid == 0) {
            // 子进程等待父进程发送启动信号(含PID列表)
            pause();
            // 随机发送一次信号后退出,实际可循环处理
            int target_idx = rand() % process_count;
            kill(pid_list[target_idx], SIGUSR2);
            printf("子进程 %d 向 %d 发送 SIGUSR2\n", getpid(), pid_list[target_idx]);
            exit(EXIT_SUCCESS);
        } else {
            pid_list[i] = pid;
        }
    }

    // 父进程向所有子进程发送启动信号(实际需传递PID列表,此处简化逻辑)
    for (int i = 0; i < process_count; i++) {
        kill(pid_list[i], SIGUSR1);
    }

    // 等待所有子进程结束
    for (int i = 0; i < process_count; i++) {
        wait(NULL);
    }

    free(pid_list);
    return 0;
}
  • 关键注意事项
    • 必须保证所有子进程都获取到完整PID列表后再启动信号交互,避免目标PID未知的情况。
    • 信号本身无法携带大量数据,传递PID列表时优先用sigqueue或共享内存;若只能用基础kill,则需拆分PID分批发送。
    • 处理信号时注意设置信号掩码,避免信号丢失,建议使用可靠信号(SIGUSR1/SIGUSR2属于可靠信号)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 02:25:29