在C语言中,wait
函数主要用于进程管理,它是一个系统调用,定义在 <sys/wait.h>
头文件中,用于让父进程等待其子进程结束,并获取子进程的终止状态。下面为你详细介绍其概念和使用方法。
概念
wait
函数的原型如下:
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *wstatus);
- 参数:
wstatus
:这是一个指向整数的指针,用于存储子进程的终止状态信息。如果不关心子进程的终止状态,可以将其设置为NULL
。
- 返回值:
- 若调用成功,
wait
函数会返回终止子进程的进程ID(PID)。 - 若调用失败,返回 -1,并设置
errno
来指示具体的错误类型。常见的错误情况包括没有子进程、调用被信号中断等。
- 若调用成功,
使用方法
基本使用
以下示例展示了如何使用 wait
函数让父进程等待子进程结束:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main() {
pid_t pid;
int status;
// 创建子进程
pid = fork();
if (pid < 0) {
// 处理 fork 失败的情况
perror("fork");
exit(EXIT_FAILURE);
} else if (pid == 0) {
// 子进程代码
printf("子进程开始执行,进程ID: %d\n", getpid());
sleep(2); // 模拟子进程执行一些任务
printf("子进程执行完毕\n");
exit(EXIT_SUCCESS);
} else {
// 父进程代码
printf("父进程等待子进程结束,子进程ID: %d\n", pid);
// 调用 wait 函数等待子进程结束
pid_t terminated_pid = wait(&status);
if (terminated_pid == -1) {
perror("wait");
exit(EXIT_FAILURE);
}
printf("子进程 %d 已结束,退出状态: %d\n", terminated_pid, WEXITSTATUS(status));
}
return 0;
}
在这个例子中:
- 首先使用
fork
函数创建一个子进程。 - 子进程执行一些任务(这里通过
sleep
函数模拟),然后调用exit
函数退出。 - 父进程调用
wait
函数等待子进程结束,并通过WEXITSTATUS
宏来获取子进程的退出状态。
检查子进程的终止状态
wait
函数的 wstatus
参数可以用来获取子进程的终止状态信息,通过一些宏可以对这些信息进行解析:
WIFEXITED(status)
:若子进程正常退出(通过exit
或return
),该宏返回非零值。WEXITSTATUS(status)
:当WIFEXITED
为真时,该宏返回子进程的退出状态码。WIFSIGNALED(status)
:若子进程因接收到信号而终止,该宏返回非零值。WTERMSIG(status)
:当WIFSIGNALED
为真时,该宏返回导致子进程终止的信号编号。
以下是一个示例,展示如何使用这些宏来检查子进程的终止状态:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main() {
pid_t pid;
int status;
pid = fork();
if (pid < 0) {
perror("fork");
exit(EXIT_FAILURE);
} else if (pid == 0) {
// 子进程代码
printf("子进程开始执行,进程ID: %d\n", getpid());
sleep(2);
printf("子进程执行完毕\n");
exit(42); // 设置退出状态码为 42
} else {
// 父进程代码
printf("父进程等待子进程结束,子进程ID: %d\n", pid);
pid_t terminated_pid = wait(&status);
if (terminated_pid == -1) {
perror("wait");
exit(EXIT_FAILURE);
}
if (WIFEXITED(status)) {
printf("子进程正常退出,退出状态码: %d\n", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
printf("子进程因信号 %d 终止\n", WTERMSIG(status));
}
}
return 0;
}
注意事项
- 阻塞特性:
wait
函数是阻塞的,意味着父进程会一直等待,直到有一个子进程结束。如果没有子进程,wait
函数会立即返回 -1。 - 资源回收:使用
wait
函数可以避免产生僵尸进程。僵尸进程是指子进程已经结束,但父进程没有回收其资源的进程。通过调用wait
函数,父进程可以获取子进程的终止状态,并释放其占用的系统资源。