如何用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替代signal:signal函数的行为在不同Linux发行版可能存在差异,sigaction是POSIX标准推荐的信号处理注册方式,行为更稳定可预测。 - 加入
pause()循环:pause()会让进程进入休眠状态,直到收到信号才唤醒,这样进程不会无意义地空转,同时保持运行状态等待信号。 - 实现双向信号交互:形成「父进程Ping → 发信号给子进程 → 子进程pong → 发信号给父进程」的循环,完美实现Ping-pong交替打印的效果。
- 更友好的错误处理:用
perror替代简单的printf,会自动输出系统调用失败的具体原因,方便调试。
使用说明:
编译运行后,你会看到终端交替输出:
Ping pong Ping pong Ping pong ...
想要停止程序,直接按Ctrl+C发送SIGINT信号即可。
内容的提问来源于stack exchange,提问作者Dmitry




