如何实现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
相关产品推荐
相关产品推荐

