使用sigsuspend后无法触发子进程继续执行的信号问题
用信号实现父子进程打印顺序同步(父先子后)
我来帮你搞定这个信号同步的问题!核心思路就是让子进程先阻塞等待父进程的信号,父进程完成打印后再给子进程发信号“放行”,这样就能严格保证父进程先输出。下面我会一步步拆解实现方案,还会帮你排查你遇到的sigsuspend后无法发信号的问题。
核心实现思路
- 选用用户自定义信号(比如
SIGUSR1),避免干扰系统默认信号的行为 - 子进程创建后先进入阻塞等待状态,直到收到父进程的信号再执行打印
- 父进程优先完成自身打印,再主动给子进程发送信号唤醒它
- 用
sigsuspend实现安全的信号等待,避免竞态条件
完整代码示例
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <signal.h> #include <sys/wait.h> // 信号处理函数:仅用于打断sigsuspend,无需额外逻辑 void sig_handler(int sig) { // 可添加调试打印:printf("Child received signal %d\n", sig); } int main() { pid_t pid; struct sigaction sa; sigset_t mask, old_mask; // 注册SIGUSR1的信号处理函数 sa.sa_handler = sig_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; if (sigaction(SIGUSR1, &sa, NULL) == -1) { perror("sigaction failed"); exit(EXIT_FAILURE); } // 提前屏蔽SIGUSR1:避免子进程未进入等待时收到信号导致丢失 sigemptyset(&mask); sigaddset(&mask, SIGUSR1); if (sigprocmask(SIG_BLOCK, &mask, &old_mask) == -1) { perror("sigprocmask failed"); exit(EXIT_FAILURE); } pid = fork(); if (pid == -1) { perror("fork failed"); exit(EXIT_FAILURE); } else if (pid == 0) { // 子进程逻辑:等待父进程信号 printf("Child: Waiting for parent to finish printing...\n"); // sigsuspend临时解除SIGUSR1屏蔽,直到收到信号才返回 if (sigsuspend(&old_mask) == -1) { // 被信号打断时errno为EINTR,属于正常情况 perror("sigsuspend failed"); } // 收到信号后执行打印 printf("Child: Hello from child process!\n"); exit(EXIT_SUCCESS); } else { // 父进程逻辑:先打印,再发信号唤醒子进程 printf("Parent: Hello from parent process!\n"); // 给子进程发送SIGUSR1信号 if (kill(pid, SIGUSR1) == -1) { perror("kill failed"); exit(EXIT_FAILURE); } // 等待子进程结束,避免僵尸进程 waitpid(pid, NULL, 0); printf("Parent: Child process completed.\n"); } return 0; }
关键细节解释
信号掩码的作用:
- 在fork前用
sigprocmask屏蔽SIGUSR1,子进程会继承这个掩码。即使父进程意外提前发信号,信号会被挂起(pending),直到子进程用sigsuspend解除屏蔽后才会被处理,避免信号丢失。 sigsuspend会临时替换当前信号掩码为old_mask(即不屏蔽SIGUSR1),等待信号到来;收到信号后自动恢复原掩码,然后返回。
- 在fork前用
解决你遇到的
sigsuspend后无法发信号的问题:- 如果你之前的代码没有提前屏蔽目标信号,可能出现父进程在子进程进入
sigsuspend前就发了信号,导致信号被直接处理(比如默认终止子进程),子进程根本没机会进入等待状态。 - 另外要确保信号处理函数正确注册,如果没有处理函数,收到
SIGUSR1会默认终止子进程,自然无法继续执行打印。
- 如果你之前的代码没有提前屏蔽目标信号,可能出现父进程在子进程进入
运行效果
编译运行后,输出顺序严格保证父进程先打印:
Parent: Hello from parent process! Child: Waiting for parent to finish printing... Child: Hello from child process! Parent: Child process completed.
内容的提问来源于stack exchange,提问作者Gamma
相关产品推荐
相关产品推荐

