waitpid、WIFEXITED、WEXITSTATUS、WIFSIGNALED、WTERMSIG

本文深入探讨waitpid函数的使用,以及如何通过WIFEXITED、WEXITSTATUS、WIFSIGNALED和WTERMSIG获取进程退出信息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include <assert.h>

int main(void){
	pid_t pid;
	pid = fork();
	if (pid < 0) {
		perror("fork failed");
		exit(1);
	}
	if (pid == 0) {
		int i;
		for (i = 3; i > 0; i--) {
			printf("This is the child\n");
			sleep(1);
		}
		//assert(1==2);
		exit(10); // 子进程退出状态
	} 
	else {
		int stat_val; // 子进程的终止信息通过这个参数传出
		waitpid(pid, &stat_val, 0); // 参数0,使得WNOHANG 可以使父进程不阻塞而立即返回0
		if (WIFEXITED(stat_val)) // WIFEXITED 取出的字段值非零 -> 正常终止
			printf("Child exited with code%d\n", WEXITSTATUS(stat_val));
			// WEXITSTATUS 取出的字段值就是子进程的退出状态
		else if (WIFSIGNALED(stat_val)) //WIFSIGNALED 取出的字段值非零-> 异常终止
			printf("Child terminated abnormally, signal %d\n", WTERMSIG(stat_val));
			// WTERMSIG 取出的字段值就是信号的编号
	}
	return 0;
}

结果:

This is the child
This is the child
This is the child
Child exited with code3

##################################################################

#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include <assert.h>

int main(void){
	pid_t pid;
	pid = fork();
	if (pid < 0) {
		perror("fork failed");
		exit(1);
	}
	if (pid == 0) {
		int i;
		for (i = 3; i > 0; i--) {
			printf("This is the child\n");
			sleep(1);
		}
		assert(1==2);
		exit(10); // 子进程退出状态
	} 
	else {
		int stat_val; // 子进程的终止信息通过这个参数传出
		waitpid(pid, &stat_val, 0); // 参数0,使得WNOHANG 可以使父进程不阻塞而立即返回0
		if (WIFEXITED(stat_val)) // WIFEXITED 取出的字段值非零 -> 正常终止
			printf("Child exited with code%d\n", WEXITSTATUS(stat_val));
			// WEXITSTATUS 取出的字段值就是子进程的退出状态
		else if (WIFSIGNALED(stat_val)) //WIFSIGNALED 取出的字段值非零-> 异常终止
			printf("Child terminated abnormally, signal %d\n", WTERMSIG(stat_val));
			// WTERMSIG 取出的字段值就是信号的编号
	}
	return 0;
}

结果:

This is the child
This is the child
This is the child
2: main4.c:21: main: Assertion `1==2' failed.
Child terminated abnormally, signal 6
### waitpid 返回 -1 的原因及解决方案 #### 1. waitpid 返回 -1 的可能原因 `waitpid` 返回 -1 表示调用失败,通常与以下情况相关: - **没有子进程**:如果当前进程中没有任何子进程存在,则 `waitpid` 会返回 -1,并将 `errno` 设置为 `ECHILD`[^1]。 - **无效参数**:传递给 `waitpid` 的参数不合法(例如 `pid` 参数值非法或 `options` 参数包含未知选项),也会导致返回 -1[^2]。 - **信号中断**:如果在等待子进程退出时,父进程被信号中断,则 `waitpid` 可能返回 -1,并将 `errno` 设置为 `EINTR`[^3]。 #### 2. 解决方案 针对上述问题,可以采取以下措施解决 `waitpid` 返回 -1 的情况: - **检查 `errno` 值**:当 `waitpid` 返回 -1 时,必须检查全局变量 `errno` 来确定具体错误原因。例如,如果 `errno == ECHILD`,则表示没有子进程需要等待;如果 `errno == EINTR`,则可以重新调用 `waitpid`[^4]。 - **确保子进程存在**:在调用 `waitpid` 之前,确保已经通过 `fork()` 创建了子进程。如果没有子进程,则直接跳过 `waitpid` 调用[^5]。 - **正确设置参数**:验证传递给 `waitpid` 的参数是否合法。例如,`pid` 参数应根据需求设置为特定子进程的 PID 或使用特殊值(如 `-1` 表示等待任意子进程)[^6]。 #### 3. 示例代码分析 以下是一个处理 `waitpid` 返回 -1 的示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> #include <errno.h> int main() { pid_t pid = fork(); if (pid == 0) { // 子进程 printf("子进程启动\n"); exit(7); // 子进程退出状态码为7 } else if (pid > 0) { // 父进程 int status; pid_t result = waitpid(pid, &status, 0); if (result == -1) { // 检查waitpid是否失败 if (errno == ECHILD) { printf("没有子进程需要等待\n"); } else if (errno == EINTR) { printf("等待被信号中断,重新尝试...\n"); result = waitpid(pid, &status, 0); // 重新调用waitpid } else { perror("waitpid 失败"); } } else { if (WIFEXITED(status)) { printf("子进程正常退出,退出状态码: %d\n", WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) { printf("子进程因信号 %d 异常终止\n", WTERMSIG(status)); } } } else { // fork失败 perror("fork 失败"); } return 0; } ``` #### 4. WEXITSTATUS 返回 255 的关联分析 当 `WEXITSTATUS` 返回 255 时,可能与 `waitpid` 返回 -1 存在间接关联。例如: - 如果 `waitpid` 因参数错误或信号中断而失败,则可能导致后续对 `status` 的错误解释,从而误认为退出状态码为 255[^7]。 - 子进程显式调用 `exit(255)` 会导致 `WEXITSTATUS` 返回 255。此时需要结合 `WIFEXITED` 验证子进程是否正常退出[^8]。 #### 5. 总结 `waitpid` 返回 -1 的主要原因包括没有子进程、参数非法或信号中断。为避免此类问题,应在调用前确保子进程存在并正确设置参数,同时检查 `errno` 值以确定具体错误原因。此外,`WEXITSTATUS` 返回 255 可能是子进程显式退出状态或对 `status` 的错误解释所致,需结合 `WIFEXITED` 和 `WIFSIGNALED` 进行验证。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值