在含fork的C代码中如何放置perror("wait")并处理wait错误?
First, let's tackle your core questions about wait() error handling, then we'll fix the runaway process issue in your original code (right now it spawns an infinite number of processes that'll quickly drain system resources—definitely not ideal!).
Using int status Instead of NULL
wait(NULL) works if you don't care about a child's exit status, but to properly handle errors, you need to:
- Declare an
intvariable to store the child's exit status - Pass a pointer to this variable to
wait() - Check
wait()'s return value—it returns-1on failure, which is when you’ll useperror().
Where to Place perror("wait")
Call perror("wait") immediately after a failed wait() call (i.e., when wait() returns -1). This ensures perror() uses the correct errno value set by the failed wait() operation, giving you an accurate, context-rich error message.
Fixed Code with Proper Error Handling
Here’s a revised version of your code that includes robust wait() error handling, plus fixes to prevent infinite process spawning (I added limits to inner loops so things don’t spiral out of control):
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/wait.h> #include <unistd.h> #include <errno.h> // Required for errno constants like ECHILD int main(int argc, char **argv) { // Spawn 10 initial child processes for(int i = 0; i < 10; i++) { pid_t pid = fork(); if(pid == -1) { // Don't skip fork() error checks! perror("fork"); exit(EXIT_FAILURE); } if(pid == 0) { // Limit inner loop to avoid infinite grandchild processes for(int j = 0; j < 3; j++) { pid_t pid2 = fork(); if(pid2 == -1) { perror("fork (inner)"); exit(EXIT_FAILURE); } if(pid2 == 0) { // Grandchild exits immediately printf("Grandchild %d exiting\n", getpid()); exit(EXIT_SUCCESS); } // Wait for the grandchild with error handling int status; pid_t wait_result = wait(&status); if(wait_result == -1) { perror("wait"); // Exit gracefully if no more children to wait for if(errno == ECHILD) { exit(EXIT_SUCCESS); } else { exit(EXIT_FAILURE); } } printf("Waited for grandchild %d, exit status: %d\n", wait_result, WEXITSTATUS(status)); } // Exit child process after inner loop finishes exit(EXIT_SUCCESS); } } // Parent waits for all initial child processes while(1) { int status; pid_t wait_result = wait(&status); if(wait_result == -1) { if(errno == ECHILD) { // No more children left—exit cleanly printf("All children exited\n"); break; } else { perror("wait (parent)"); exit(EXIT_FAILURE); } } printf("Waited for child %d, exit status: %d\n", wait_result, WEXITSTATUS(status)); } return EXIT_SUCCESS; }
Key Details:
- We added checks for
fork()errors too—forking can fail if the system runs out of process slots, so this is critical for robustness. - The inner child loop is limited to 3 iterations to prevent infinite process creation.
- The parent uses a
while(1)loop to wait for all 10 child processes (sincewait()only waits for one child at a time). - When
wait()returns-1witherrno == ECHILD, that’s a normal exit condition (no more children to wait for), not a fatal error.
内容的提问来源于stack exchange,提问作者user9314692

