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

如何实现fork创建的父子进程同步?满足交替顺序输出需求

问题拆解与解决方案

嘿,我发现你这里有个关键的混淆点:你用fork()创建的是完全独立的进程,不是线程!而普通的std::mutex是给同一进程内的线程用的——父子进程有各自独立的地址空间,各自的mutex是完全不同的内存对象,根本没法互相感知,这就是你死锁的根源:两个进程各自锁自己的mutex,永远等不到对方释放。

要实现父子进程交替输出,你得用进程间同步(IPC)机制,下面给你两种最实用的实现方式:

方式一:POSIX信号量(最直观的同步工具)

信号量就是专门用来做进程/线程同步的,我们可以用两个信号量分别控制父、子进程的执行顺序:

  • 初始化时让父进程的信号量处于“可执行”状态(值为1),子进程的信号量处于“阻塞”状态(值为0)
  • 父进程输出完,就释放子进程的信号量,然后自己等待
  • 子进程输出完,再释放父进程的信号量,自己等待

代码示例:

#include <iostream>
#include <unistd.h>
#include <semaphore.h>
#include <fcntl.h>

// 信号量要放在共享命名空间,父子进程才能共享
sem_t *parent_sem;
sem_t *child_sem;

void parent_task() {
    while (true) {
        sem_wait(parent_sem); // 等允许执行的信号
        std::cout << "IN PARENT PROCESS (Class1)\n\n";
        sleep(2);
        sem_post(child_sem); // 通知子进程可以跑了
    }
}

void child_task() {
    while (true) {
        sem_wait(child_sem); // 等父进程的通知
        std::cout << "IN CHILD PROCESS (Class2)\n\n";
        sleep(2);
        sem_post(parent_sem); // 通知父进程继续
    }
}

int main() {
    std::cout << "In Main\n\n";

    // 创建命名信号量,确保父子进程能共享
    parent_sem = sem_open("/my_parent_sem", O_CREAT | O_EXCL, 0644, 1);
    child_sem = sem_open("/my_child_sem", O_CREAT | O_EXCL, 0644, 0);

    pid_t pid = fork();
    if (pid > 0) {
        // 父进程逻辑
        parent_task();
        // 实际循环不会到这里,这里是清理示例
        sem_close(parent_sem);
        sem_close(child_sem);
        sem_unlink("/my_parent_sem");
        sem_unlink("/my_child_sem");
    } else if (pid == 0) {
        // 子进程逻辑
        child_task();
        sem_close(parent_sem);
        sem_close(child_sem);
    } else {
        perror("fork failed");
        return 1;
    }

    return 0;
}

方式二:管道(轻量级IPC方案)

管道是最简单的进程间通信方式之一,我们可以用两个管道实现双向通知:

  • 父进程先输出,然后通过管道给子进程发一个“信号”
  • 子进程收到信号后输出,再通过另一个管道给父进程发信号
  • 循环往复,实现交替执行

代码示例:

#include <iostream>
#include <unistd.h>
#include <cstring>

int parent_to_child[2]; // 父→子的通知管道
int child_to_parent[2]; // 子→父的通知管道

void parent_task() {
    char dummy[1];
    // 初始没有子进程的通知,父进程直接执行
    while (true) {
        std::cout << "IN PARENT PROCESS (Class1)\n\n";
        sleep(2);
        write(parent_to_child[1], "x", 1); // 给子进程发信号
        read(child_to_parent[0], dummy, 1); // 等子进程的信号
    }
}

void child_task() {
    char dummy[1];
    read(parent_to_child[0], dummy, 1); // 先等父进程的信号
    while (true) {
        std::cout << "IN CHILD PROCESS (Class2)\n\n";
        sleep(2);
        write(child_to_parent[1], "x", 1); // 给父进程发信号
        read(parent_to_child[0], dummy, 1); // 等父进程的信号
    }
}

int main() {
    std::cout << "In Main\n\n";

    // 创建两个管道
    if (pipe(parent_to_child) == -1 || pipe(child_to_parent) == -1) {
        perror("pipe creation failed");
        return 1;
    }

    pid_t pid = fork();
    if (pid > 0) {
        // 父进程关闭不需要的管道端
        close(parent_to_child[0]);
        close(child_to_parent[1]);
        parent_task();
    } else if (pid == 0) {
        // 子进程关闭不需要的管道端
        close(parent_to_child[1]);
        close(child_to_parent[0]);
        child_task();
    } else {
        perror("fork failed");
        return 1;
    }

    return 0;
}
额外提醒

看你原来的代码,在fork后的进程里还创建了线程,其实完全没必要——如果你的需求只是父子进程交替输出,直接在父/子进程的主逻辑里做同步就够了。如果实际场景中进程内还有线程要同步,那再结合std::mutex这类线程同步工具,但跨进程的同步必须用IPC机制哦。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:48:41