You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何用C语言实现Linux父子进程信号传递及Ping-Pong输出

解决父子进程Ping-Pong信号交互问题

我来帮你修正这个Ping-Pong程序的问题,你的代码目前有几个关键缺陷导致无法实现交替打印的效果:

  • 父进程调用raise(SIGUSR1)是给自己发信号,但执行完后直接退出了,没有和子进程持续交互的逻辑
  • 子进程注册了信号处理函数后直接退出,根本没机会等待父进程的信号
  • 缺少父子进程互相发送信号的核心逻辑,没法形成Ping-pong的循环

下面是修正后的完整代码,我会详细解释每个改动点:

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>

// 子进程信号处理函数:收到SIGUSR1后打印pong,再给父进程发信号
void childSignalHandler(int signal) {
    printf("pong\n");
    // 给父进程发送SIGUSR2信号,触发父进程下一次打印
    kill(getppid(), SIGUSR2);
}

// 父进程信号处理函数:收到SIGUSR2后打印Ping,再给子进程发信号
void parentSignalHandler(int signal) {
    printf("Ping ");
    // 全局变量保存子进程ID,用于发送信号
    extern pid_t child_pid;
    kill(child_pid, SIGUSR1);
}

pid_t child_pid; // 全局变量存储子进程ID,方便父进程信号处理函数调用

int main() {
    child_pid = fork();
    if (child_pid < 0) {
        perror("fork failed"); // 用perror打印更详细的错误信息
        return EXIT_FAILURE;
    }

    if (child_pid == 0) {
        // 子进程:用sigaction注册信号处理(比signal更标准可移植)
        struct sigaction sa;
        sa.sa_handler = childSignalHandler;
        sigemptyset(&sa.sa_mask); // 清空信号掩码,避免阻塞其他信号
        sa.sa_flags = 0;
        sigaction(SIGUSR1, &sa, NULL);

        // 子进程进入循环等待信号,避免直接退出
        while (1) {
            pause(); // 暂停进程,直到收到信号才继续执行
        }
    } else {
        // 父进程:同样用sigaction注册SIGUSR2的处理函数
        struct sigaction sa;
        sa.sa_handler = parentSignalHandler;
        sigemptyset(&sa.sa_mask);
        sa.sa_flags = 0;
        sigaction(SIGUSR2, &sa, NULL);

        // 父进程主动发起第一次Ping,然后给子进程发信号触发pong
        printf("Ping ");
        kill(child_pid, SIGUSR1);

        // 父进程进入循环等待子进程的信号
        while (1) {
            pause();
        }
    }

    return EXIT_SUCCESS;
}

关键改动说明:

  • 全局变量存储子进程ID:父进程的信号处理函数需要知道子进程的PID才能发送信号,所以用全局变量child_pid保存;子进程则通过getppid()直接获取父进程ID。
  • sigaction替代signalsignal函数的行为在不同Linux发行版可能存在差异,sigaction是POSIX标准推荐的信号处理注册方式,行为更稳定可预测。
  • 加入pause()循环pause()会让进程进入休眠状态,直到收到信号才唤醒,这样进程不会无意义地空转,同时保持运行状态等待信号。
  • 实现双向信号交互:形成「父进程Ping → 发信号给子进程 → 子进程pong → 发信号给父进程」的循环,完美实现Ping-pong交替打印的效果。
  • 更友好的错误处理:用perror替代简单的printf,会自动输出系统调用失败的具体原因,方便调试。

使用说明:

编译运行后,你会看到终端交替输出:

Ping pong
Ping pong
Ping pong
...

想要停止程序,直接按Ctrl+C发送SIGINT信号即可。

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

火山引擎 最新活动