Linux下fork、semaphore与pipe的C语言同步问题咨询
Troubleshooting Semaphore + Pipe Sync Issues in Forked Processes
Hey there! It sounds like you're hitting a classic synchronization snag with forked processes, pipes, and semaphores—let's break down the most common pitfalls and fix this step by step.
Why Your Loop + Semaphore Setup Might Be Failing
First, let's cover the top issues that cause unexpected behavior here:
- Semaphore isn't shared between parent/child: If you declared a semaphore as a regular global or local variable, the child process gets a copy of it after
fork(). That means parent and child are modifying separate semaphores—no synchronization actually happens! - Incorrect semaphore initialization: If you set the wrong initial values or forgot to mark the semaphore as process-shared, it won't work across fork boundaries.
- Unclosed pipe ends: Leaving unused pipe file descriptors open can cause processes to block indefinitely (the OS thinks more data might come through the pipe).
- Misordered
sem_wait/sem_postcalls: If you don't signal the other process after read/write, you'll end up in a deadlock where one process waits forever for a signal that never comes.
Working Example Code
Here's a corrected implementation that fixes these issues, using shared memory for semaphores to ensure parent and child access the same sync objects:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <semaphore.h> #include <sys/mman.h> #include <sys/wait.h> #define NUM_TRANSFERS 4 // Match your 4x integer transfer requirement int main() { int pipe_fd[2]; // Create pipe if (pipe(pipe_fd) == -1) { perror("pipe failed"); exit(EXIT_FAILURE); } // Create anonymous shared memory for semaphores (so parent/child share the same instances) sem_t *sem_write = mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); sem_t *sem_read = mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); if (sem_write == MAP_FAILED || sem_read == MAP_FAILED) { perror("mmap failed"); exit(EXIT_FAILURE); } // Initialize semaphores: // - sem_write starts at 1 (child can write first) // - sem_read starts at 0 (parent can't read until child writes) if (sem_init(sem_write, 1, 1) == -1 || sem_init(sem_read, 1, 0) == -1) { perror("sem_init failed"); exit(EXIT_FAILURE); } pid_t pid = fork(); if (pid == -1) { perror("fork failed"); exit(EXIT_FAILURE); } else if (pid == 0) { // Child process: close unused read end of pipe close(pipe_fd[0]); int data; for (int i = 0; i < NUM_TRANSFERS; i++) { data = i + 1; // Send integers 1-4 sem_wait(sem_write); // Wait for permission to write printf("Child writing: %d\n", data); if (write(pipe_fd[1], &data, sizeof(data)) != sizeof(data)) { perror("write failed"); exit(EXIT_FAILURE); } sem_post(sem_read); // Signal parent it can read now } // Cleanup child resources close(pipe_fd[1]); sem_destroy(sem_write); sem_destroy(sem_read); munmap(sem_write, sizeof(sem_t)); munmap(sem_read, sizeof(sem_t)); exit(EXIT_SUCCESS); } else { // Parent process: close unused write end of pipe close(pipe_fd[1]); int received; for (int i = 0; i < NUM_TRANSFERS; i++) { sem_wait(sem_read); // Wait for child to write if (read(pipe_fd[0], &received, sizeof(received)) != sizeof(received)) { perror("read failed"); exit(EXIT_FAILURE); } printf("Parent received: %d\n", received); sem_post(sem_write); // Signal child it can write again } // Cleanup parent resources close(pipe_fd[0]); wait(NULL); // Wait for child to exit sem_destroy(sem_write); sem_destroy(sem_read); munmap(sem_write, sizeof(sem_t)); munmap(sem_read, sizeof(sem_t)); exit(EXIT_SUCCESS); } }
Key Fixes Explained
Let's highlight the critical parts that solve your problem:
- Shared semaphores: Using
mmapwithMAP_SHAREDensures both processes access the same semaphore objects—no more separate copies! - Process-shared semaphore flag: The second argument to
sem_initis1, which tells the system this semaphore is meant to be shared across processes (not just threads). - Proper pipe cleanup: Each process closes the pipe end it doesn't use, preventing indefinite blocking.
- Strict sync order:
sem_waitbefore operation,sem_postafter—this enforces the write → read → write → read alternation you need. - Return value checks: Verifying
read/writereturn values ensures you catch partial data transfers or errors early.
How to Adapt This to Your Code
- Replace your semaphore declarations with shared memory-backed semaphores (like the
mmapexample above). - Double-check your semaphore initial values: make sure the writer starts with permission (
1) and the reader starts blocked (0). - Ensure you close unused pipe ends immediately after
fork(). - Add checks for
read/writereturn values to debug any data transfer issues.
If you're still hitting specific errors (like EDEADLK or unexpected blocking), feel free to share your code snippets and error messages for more targeted help!
内容的提问来源于stack exchange,提问作者Zhawn
相关产品推荐
相关产品推荐

