在使用 `wait(NULL)` 函数等待子进程终止时,实际上并不需要指定具体哪个子进程的进程号。`wait(NULL)` 会等待任何一个子进程结束,并回收它的资源,防止产生僵尸进程。这是因为 `wait()` 函数的设计目的是让父进程等待并清理子进程的结束状态。
当一个父进程调用 `wait(NULL)` 时,它会发生以下事情:
1. **阻塞父进程**:如果没有任何子进程已经结束,`wait(NULL)` 会阻塞父进程,直到至少有一个子进程结束。
2. **回收子进程**:一旦有子进程结束,`wait(NULL)` 会回收该子进程的资源。这意味着操作系统会清理与该子进程相关的所有资源,比如内存和进程控制块。
3. **不指定子进程**:由于 `wait(NULL)` 不指定等待特定的子进程,它适用于等待任何一个子进程。如果需要等待特定的子进程,可以使用 `waitpid(pid, &status, options)` 函数,其中 `pid` 是特定子进程的进程号。
示例代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
void sigintHandler(int sig_num) {
// Do nothing - just block SIGINT
}
void sigusr1Handler(int sig_num) {
printf("Child Process %d is Killed by Parent!\n", getpid());
exit(0);
}
int main() {
pid_t pid1, pid2;
// Signal handler for SIGINT
signal(SIGINT, sigintHandler);
// Creating first child
pid1 = fork();
if (pid1 == 0) {
// Signal handler for SIGUSR1
signal(SIGUSR1, sigusr1Handler);
while(1); // Infinite loop for child
}
// Creating second child
pid2 = fork();
if (pid2 == 0) {
// Signal handler for SIGUSR1
signal(SIGUSR1, sigusr1Handler);
while(1); // Infinite loop for child
}
// Wait for a keyboard interrupt (SIGINT)
pause();
// Send SIGUSR1 to children
kill(pid1, SIGUSR1);
kill(pid2, SIGUSR1);
// Wait for children to terminate
wait(NULL);
wait(NULL);
printf("Parent Process is Killed!\n");
return 0;
}
在这个场景中,如果父进程创建了多个子进程,并且希望等待所有子进程结束,它可以重复调用 `wait(NULL)` 直到所有子进程都已结束。每次调用 `wait(NULL)` 都会等待并清理一个已结束的子进程,无论它是哪个。如果所有子进程都已结束,进一步的 `wait(NULL)` 调用将立即返回一个错误。