上一篇介绍了进程的创建和退出,以及相关的系统函数。
Linux编程入门(15)-进程(三)编程
这篇主要讲讲,子进程退出后,父进程如何获取其退出状态。
有的应用程序,需要父进程知道子进程何时终止或退出,以及其返回给父进程的状态值信息。
那么,父进程在创建完成子进程后,有没有办法获知子进程的退出状态?答案是肯定的。
Linux 提供了系统函数 wait()
,用于检测子进程的终止情况。
系统函数 wait()
系统函数 wait()
主要做两件事:
- 暂停调用它的进程,直到有子进程退出。
- 获取子进程结束时传递给
exit()
的值。
文章图片
wait()
等待调用进程的任意一个子进程终止,其函数原型为:#include
#include pid_t wait(int *wstatus);
参数 wstatus 指向的整型变量用于接收子进程的终止状态。
函数执行成功,返回终止的子进程 ID。 失败,则返回 -1。
wait()
详细的执行步骤为:- 如果调用进程没有子进程,那么
wai()
会出错,返回 -1。 - 调用此函数的进程,如果有子进程终止,
wait()
立即返回。否则,调用进程一直阻塞。 - 如果 wstatus 非空,则关于子进程终止的信息会通过 wstatus 指向的整型变量返回。
- 将终止进程的 PID 作为
wait()
返回值,并返回。
wait()
就立即返回。因为
wait()
的返回值是终止进程的 PID,所以父进程能够知晓是哪一个进程终止了。若某个子进程用来完成某项任务,当任务处理完毕后退出,父进程可以通过 wait()
了解到该任务完成了,可以继续其他处理了。关于进程的结束状态
一个进程的结束,有三种方式:
- 正常结束。成功调用
exit(0)
或者return 0
。 - 进程出错退出。例如,由于内存耗尽而提前退出程序。程序遇到问题要退出时,可以调用
exit()
函数时传递一个非零值。 - 被一个信号 kill 掉。信号可能来自键盘、定时器、内核或者其他进程。
wait()
返回的退出状态来进行判断。在调用
wait()
函数时,给其传递一个整型变量的地址。Linux 内核会将子进程的退出状态存储在这个变量中:- 子进程调用
exit()
退出,内核会把 exit 的参数值存放到整数变量中。 - 子进程被 kill 掉,内核将信号序号存放在这个变量中。
进程退出返回的整型状态值,实际上仅用了最低的 16 位,由 3 部分构成:
- 8 位记录退出的值(正常退出)。
- 1 位指明是否发生错误并产生了 core 文件(core dump)
- 7 位记录信号编号(被信号 kill 掉,异常返回)
文章图片
终止状态可以用
中的宏来检测。其中,有 4 个宏可用来取得进程终止的原因:- WIFEXITED(status) , 进程正常结束,则为真。
- WIFSIGNALED(status), 子进程被信号终止,则为真。
- WIFSTOPPED (status) , 子进程因信号而停止,则为真。
- WIFCONTINUED (status) , 进程收到 SIGCONT 而恢复执行 , 则为真。
编程示例-1
编程实验,实际验证一下,子进程调用 exit() 是如何触发 wait() 返回的处理流程:
#include
#include
#include
#include
#include
#include
#include /* 子进程执行函数 */
void child_code(int delay)
{
printf("child %d here. will sleep %d seconds\n", getpid(), delay);
sleep(delay);
printf("child done. exit\n");
exit(17);
}
/* 父进程执行函数 */
void parent_code(int childpid)
{
int wait_ret;
wait_ret = wait(NULL);
printf("done waiting for %d. Wait returned: %d\n", childpid, wait_ret);
}int main()
{
int newpid;
printf("before: mypid is %d\n", getpid());
/* 创建新进程,并判断返回值 */
if((newpid = fork()) == -1)
{
perror("fork");
}
else if(newpid == 0)
{
/* 子进程执行感函数 */
child_code(2);
}
else
{
/* 父进程执行感函数 */
parent_code(newpid);
}
}
在父进程中,控制流始于程序的开始,在
wait()
的地方阻塞。在子进程中,控制流始于 main 函数的中部(fork 之后),然后运行
child_code()
函数,最后调用 exit()
结束。编译,运行结果如下:
$ gcc waitdemo.c -o waitdemo
$ ./waitdemobefore: mypid is 2844
child 2845 here. will sleep 2 seconds
child done. exit
done waiting for 2845. Wait returned: 2845
由程序的执行结果来看,这段程序验证了
wait()
的函数的两个特征:wait()
函数会阻塞调用它的程序,直到子进程结束。wait()
函数会返回结束进程的 PID。
通过编程来显示子进程的退出状态,代码 waitdemo2.c 如下:
#include
#include
#include
#include
#include
#include
#include /* 子进程执行函数 */
void child_code(int delay)
{
printf("child %d here. will sleep %d seconds\n", getpid(), delay);
/* 子进程执行函数 */
sleep(delay);
printf("child done. exit\n");
/* 子进程退出 */
exit(17);
}void parent_code(int childpid)
{
int wait_ret;
int child_status;
int high_8, low_7, bit_7;
wait_ret = wait(&child_status);
printf("done waiting for %d. Wait returned: %d\n", childpid, wait_ret);
/* 解析子进程退出状态信息 */
high_8 = child_status >> 8;
low_7 = child_status & 0x7F;
bit_7 = child_status & 0x80;
printf("status: exit = %d, sig = %d, core %d\n", high_8, low_7, bit_7);
}int main()
{
int newpid;
printf("before: mypid is %d\n", getpid());
if((newpid = fork()) == -1)
{
perror("fork");
}
else if(newpid == 0)
{
child_code(5);
}
else
{
parent_code(newpid);
}
}
【Linux编程|Linux编程入门(16)-进程(四)等待子进程】编译、运行。先看看正常运行情况,退出状态从子进程中获取(
exit()
的参数):$ gcc waitdemo2.c -o waitdemo2
$ ./waitdemo2before: mypid is 5506
child 5507 here. will sleep 5 seconds
child done. exit
done waiting for 5507. Wait returned: 5507
status: exit = 17, sig = 0, core 0
然后再看看异常结束情况。后台运行 waitdemo2,使用 kill 指令给子进程发送 SIGTERM 信号,内核将该信号编号填充到状态字中:
$ ./waitdemo2 &/* 后台运行程序 */
before: mypid is 5592
child 5593 here. will sleep 5 secondskill 5593/* 给子进程发送信号 */done waiting for 5593. Wait returned: 5593
status: exit = 0, sig = 15, core 0/* 显示状态信息 */
扩展
假如一个进程有多个子进程,只要有一个子进程退出,
wait()
就返回。那么要等待一个指定的进程终止(需要直到该进程的 PID),该如何处理?一种方式是,根据
wait()
返回的进程 ID 与期望的进程 ID 比较。如果终止进程不是所期望的,则再次调用 wait()
函数。还有一种方式,使用专门的系统函数。Linux 系统提供了一个系统调用,可以用来等待特定的子进程。
该系统函数为
waitpid()
, 其原型为:#include
#include pid_t waitpid(pid_t pid, int *wstatus, int options);
参数 pid,表示需要等待的具体子进程,具体含义如下:
- pid > 0,表示等待进程 ID 为 pid 的子进程。
- pid = 0,等待与调用进程(父进程)同一个进程组的所有子进程。
- pid = -1,等待任意进程。
- pid < -1,等待进程组标识符与 pid 绝对值相等的所有子进程。
wait(&status)
等价于 waitpid(-1, &status, 0)
。参数 options,是一个位掩码,可以包含如下标志位:
- WUNTRACED 返回终止子进程的信息和因信号终止的子进程信息。
- WCONTINUED 返回因收到 SIGCONT 信号而恢复执行的子进程状态信息。
- WNOHANG 无子进程退出,立即返回,不阻塞父进程。
本文主要介绍了父进程如何等待子进程退出,以及获取进程退出状态相关的内容。
- 介绍了系统函数 wait() 以及其内部执行的流程。
- 进程退出状态的构成,以及进程退出状态如何检测。
- 通过实例演示如何运用 wait() 函数。
- 扩展介绍了一个可以等待指定进程的系统函数
waitpid()
公众号【一起学嵌入式】,干货资料首先送达
文章图片
推荐阅读
- 最新版勤哲Excel服务器V2016.12.0.292无限用户支持手机APP,微信,网页等功能不绑定电脑,任意安装,支持后续升级
- wget|wget linux java 32_Java 通过wget在Linux上下载Java JDK显示的是许可证页面
- python|iphone玩游戏关闭通知_如何在iPhone上关闭COVID-19曝光记录和通知
- iMX8|VisualStudioCode开发Arm嵌入式Linux应用
- natapp搭建外网服务器
- linux/嵌入式|嵌入式开发第一阶段,环境搭建
- 运维部署|Windows操作系统cmd/Dos 批处理命令手册bat
- 运维|一个程序员的水平能差到什么程度......
- 运维|ExtJS学习之路碎碎念