代码实现
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main() {
pid_t child_pid, wpid;
int status;
// 创建子进程
child_pid = fork();
if (child_pid == -1) {
perror("fork");
return 1;
} else if (child_pid == 0) {
// 子进程
printf("子进程: 我的PID是 %d\n", getpid());
sleep(2); // 模拟子进程执行任务
printf("子进程结束\n");
exit(0);
} else {
// 父进程
// 使用waitpid等待特定子进程
wpid = waitpid(child_pid, &status, 0);
if (wpid == -1) {
perror("waitpid");
return 1;
}
if (WIFEXITED(status)) {
printf("父进程: 子进程 %d 正常结束,退出状态码: %d\n", wpid, WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
printf("父进程: 子进程 %d 被信号 %d 终止\n", wpid, WTERMSIG(status));
}
}
return 0;
}
waitpid函数相较于wait函数的优势
- 等待特定子进程:
wait
函数会等待任意一个子进程结束,而 waitpid
可以通过指定 pid
参数等待特定的子进程结束。例如,在一个程序创建了多个子进程的情况下,使用 waitpid
可以精准地等待某个子进程完成任务。
- 非阻塞等待:
waitpid
的第三个参数 options
可以设置为 WNOHANG
,这样如果指定的子进程还没有结束,waitpid
会立即返回,而不会阻塞父进程。wait
函数只能阻塞等待子进程结束。这在需要父进程同时处理其他任务,又要关注子进程状态的场景下非常有用。
- 灵活性:
waitpid
提供了更多的控制选项,例如可以设置 WUNTRACED
选项,这样不仅等待子进程正常结束,还可以等待因信号而停止的子进程,这在调试子进程等场景下很有帮助。
根据不同场景选择使用这两个函数
- 简单场景:如果程序只创建了一个子进程,并且父进程只需要等待这个子进程结束,使用
wait
函数就足够了,因为代码会更简洁。例如简单的命令行工具,在执行某个外部命令时创建一个子进程,等待子进程执行完毕后继续父进程的其他操作。
- 复杂场景:
- 多子进程管理:当程序创建了多个子进程,并且需要分别处理每个子进程的结束状态,或者需要等待特定子进程完成时,应使用
waitpid
函数。例如一个服务器程序,为每个客户端请求创建一个子进程处理任务,服务器需要对每个子进程的结束状态进行记录和处理。
- 并发处理:如果父进程需要在等待子进程的同时继续执行其他任务,应使用
waitpid
并设置 WNOHANG
选项进行非阻塞等待。例如在一个多媒体处理程序中,父进程在等待子进程完成视频编码的同时,还需要处理用户界面的交互操作。