Linux 系统下使用 waitpid 函数回收子进程
waitpid 函数是 Linux 系统中用于进程间通信和同步的一个重要函数,它允许父进程等待并获取子进程的终止状态。与 wait 函数类似,waitpid 提供了更精细的控制,允许指定等待哪个子进程以及以何种方式等待。
可以通过在 Linux 终端输入命令 man 2 waitpid 来查看 waitpid 函数的详细描述:
#include <sys/types.h>
#include <sys/wait.h>
pid_t waitpid(pid_t pid, int *wstatus, int options);
函数作用
waitpid 函数用于回收指定进程 ID 的子进程,并可以设置等待方式为阻塞或非阻塞。
参数详解
pid_t pid: 指定要等待的子进程的 ID。< -1: 等待任何一个进程组 ID 等于pid绝对值的子进程。-1: 等待任何一个子进程,等同于wait()函数。这是最常用的选项。0: 等待当前进程组内的任何一个子进程。> 0: 等待指定进程 ID (pid) 的子进程。
int *wstatus: 一个指向整型变量的指针,用于存储子进程退出时的状态信息。这是一个传出参数。- 返回值 (成功时): 返回被回收的子进程的 ID。
- 返回值 (失败时): 返回 -1,表示调用失败,或者所有子进程都已被回收。
int options: 设置等待方式。0: 阻塞等待,直到有子进程退出。WNOHANG: 非阻塞等待,如果当前没有子进程退出,则立即返回。
返回值
> 0: 返回被回收子进程的 ID。= 0: 当options设置为WNOHANG时,表示还有子进程存在但未退出。-1: 表示发生错误,或者没有可回收的子进程。
状态宏
WIFEXITED(wstatus): 如果子进程正常退出(例如调用exit()或_exit(),或者从main函数返回),则返回真。WEXITSTATUS(wstatus): 返回子进程的退出状态码。这仅在WIFEXITED返回真时才有效。WIFSIGNALED(wstatus): 如果子进程被信号终止,则返回真。WTERMSIG(wstatus): 返回导致子进程终止的信号编号。这仅在WIFSIGNALED返回真时才有效。
示例代码
下面的代码演示了父进程如何创建多个子进程,并使用 waitpid 函数以非阻塞方式回收它们。
#include <sys/types.h>
#include <sys/wait.h>
#include <iostream>
#include <unistd.h>
#include <stdlib.h>
// 使用 std 命名空间
using std::cout;
using std::endl;
namespace waitpid_example {
void run_test() {
pid_t child_pid;
const int num_children = 5;
// 父进程创建 num_children 个子进程
for (int i = 0; i < num_children; ++i) {
child_pid = fork();
if (child_pid == 0) {
// 子进程逻辑
cout << "Child process (PID: " << getpid() <<) started." << endl;
sleep(2); // 模拟子进程工作
cout << "Child process (PID: " << getpid() <<) exiting." << endl;
exit(i + 1); // 以不同的状态码退出
} else if (child_pid < 0) {
perror("fork failed");
return; // 退出函数
}
}
// 父进程逻辑
if (child_pid > 0) {
cout << "Parent process (PID: " << getpid() <<) waiting for children..." << endl;
int child_status;
int exited_children = 0;
// 使用非阻塞方式等待子进程
while (exited_children < num_children) {
pid_t terminated_pid = waitpid(-1, &child_status, WNOHANG);
if (terminated_pid == -1) {
// 发生错误或所有子进程已回收
perror("waitpid error");
break;
} else if (terminated_pid == 0) {
// 没有子进程退出,继续循环
// cout << "Parent: No child has exited yet." << endl;
sleep(1); // 短暂休眠,避免 CPU 占用过高
} else {
// 某个子进程已退出
exited_children++;
cout << "Parent: Child process (PID: " << terminated_pid <<) terminated." << endl;
if (WIFEXITED(child_status)) {
cout << " Normal exit with status: " << WEXITSTATUS(child_status) << endl;
} else if (WIFSIGNALED(child_status)) {
cout << " Killed by signal: " << WTERMSIG(child_status) << endl;
}
}
}
cout << "Parent process finished waiting." << endl;
}
// else if (child_pid == 0) {
// // 子进程逻辑已在上面 fork 循环中处理
// }
}
}
int main() {
waitpid_example::run_test();
return 0;
}