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

C语言无需全局变量通过Ctrl+C/Ctrl+\等信号杀死子进程的实现方法

方案1:拆分信号处理函数+函数内静态变量存储上下文

这个方案不需要修改原有逻辑结构,完全规避全局变量:

  1. 将信号注册逻辑移到fork之后,父子进程分别注册属于自己的信号处理函数,不需要再用变量判断当前是父/子进程
  2. 父进程的信号处理函数内部用静态volatile类型存储子PID,仅在父进程处理函数范围内可见,不属于全局变量

修改后的完整代码如下:

#include <signal.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>

// 父进程专用信号处理函数
void parent_signal_handler(int sig) {
    // 函数内部静态变量,仅本函数可访问,不属于全局变量
    static volatile pid_t child_pid = 0;
    // 用信号0作为特殊指令传递子PID,不会触发实际信号逻辑
    if (sig == 0) {
        child_pid = (pid_t)sig;
        return;
    }
    signal(sig, parent_signal_handler);
    if (sig == SIGINT) {
        const char str[] = "this is ctrl + c in the parent process, killing child\n";
        write(STDOUT_FILENO, str, sizeof(str) - 1);
        // 直接用存储的子PID杀死子进程
        kill(child_pid, SIGTERM);
        exit(EXIT_SUCCESS);
    } else if (sig == SIGQUIT) {
        const char str[] = "this is ctrl + \\ in the parent process\n";
        write(STDOUT_FILENO, str, sizeof(str) - 1);
    }
}

// 子进程专用信号处理函数
void child_signal_handler(int sig) {
    signal(sig, child_signal_handler);
    if (sig == SIGINT) {
        const char str[] = "this is ctrl + c in the child process\n";
        write(STDOUT_FILENO, str, sizeof(str) - 1);
        exit(EXIT_SUCCESS);
    } else if (sig == SIGQUIT) {
        const char str[] = "this is ctrl + \\ in the child process\n";
        write(STDOUT_FILENO, str, sizeof(str) - 1);
    }
}

int main(int argc, char **argv) {
    pid_t pid;
    (void)argv;

    pid = fork();
    assert(pid != -1);
    if (pid == 0) {
        // 子进程注册自己的处理函数
        signal(SIGINT, child_signal_handler);
        signal(SIGQUIT, child_signal_handler);
        printf("child pid, pgid = %ju, %ju\n", (uintmax_t)getpid(), (uintmax_t)getpgid(0));
        while (1);
        exit(EXIT_SUCCESS);
    }
    // 父进程注册自己的处理函数,并存入子PID
    signal(SIGINT, parent_signal_handler);
    signal(SIGQUIT, parent_signal_handler);
    parent_signal_handler((int)pid);

    printf("parent pid, pgid = %ju, %ju\n", (uintmax_t)getpid(), (uintmax_t)getpgid(0));
    while (1);
    return 0;
}

方案2:使用signalfd事件化处理信号(更推荐)

如果运行环境支持POSIX标准的signalfd,可以完全弃用信号处理函数,把信号转换成文件描述符的可读事件,在主循环中处理,完全不需要任何全局/静态变量,所有上下文都可以用主函数的局部变量传递,也不存在异步信号安全的限制:

  1. 先阻塞要处理的信号,避免触发默认处理逻辑
  2. 创建signalfd关联要监听的信号
  3. 主循环用read读取signalfd的事件,拿到信号类型后直接调用kill处理子进程即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.19 07:36:03