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

使用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;
}

关键细节解释

  1. 信号掩码的作用:

    • 在fork前用sigprocmask屏蔽SIGUSR1,子进程会继承这个掩码。即使父进程意外提前发信号,信号会被挂起(pending),直到子进程用sigsuspend解除屏蔽后才会被处理,避免信号丢失。
    • sigsuspend会临时替换当前信号掩码为old_mask(即不屏蔽SIGUSR1),等待信号到来;收到信号后自动恢复原掩码,然后返回。
  2. 解决你遇到的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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 04:20:26