【Linux系统编程十一】:(进程控制1)--进程终止与进程等待

一.进程终止

进程退出有三种情况:

1.进程代码运行完毕,结果正确。
2.进程代码运行完毕,结果不正确。
3.代码异常终止。

那么进程退出的结果是如何知道的呢?

一般统一采用进程的退出码来进行判定。

1.退出码和错误码

什么是退出码呢?我们写main函数时,是不是最后都要return 0呢。
而这里的返回0,就是返回码。
在这里插入图片描述
而且每个返回码都有自己代表的描述信息,不同的返回码有不同的错误信息。0表示成功。
可以用strerror()函数来输出错误描述字符:
在这里插入图片描述
为什么要有退出码呢?
因为退出码可以来描述一个进程的结束状况。而这个进程肯定是有父进程的,父进程需要关心子进程的退出码!
为什么父进程需要关心子进程的退出码呢?
因为用户需要知道自己创建的进程如何,需要从父进程那获取退出码!
在这里插入图片描述
如果进程退出是因为异常呢?
在这里插入图片描述
在这里插入图片描述

2.终止实现

以上就是对进程退出会出现三种情况的分析,接下来我们就来分析进程退出是如何实现的。

进程退出,利用exit(status)函数来实现。

在这里插入图片描述
要注意一个点,就是return 和exit()的区别,exit表示当前进程退出,程序直接就挂了,而return是将返回值返回给上一曾调用函数。
如果在调用函数中exit(status),最终该进程的返回码就是status。而可能不是return返回的值。
在这里插入图片描述

进程退出有两个函数exit和_exit它们有什么区别呢?

在这里插入图片描述

二.进程等待

1.为什么进程需要等待?

1.首先,僵尸进程是无法被杀死的,而解决僵尸进程只有通过回收等待的方法,而且僵尸进程是必须要解决的。
2.我们创建的子进程,子进程办的事办的如何了?成功了还是失败了?我们需要知道,如何知道呢?利用进程等待,在父进程那获取子进程的退出情况。

在这里插入图片描述

2.进程等待是干什么的?

进程等待就是通过系统调用wait或waitpid,来进行对子进程状态检测和回收的功能

在这里插入图片描述

①.单进程等待

在当前函数里利用fork创建子进程,子进程打印自己的pid和ppid。打印5次完结束进程。而父进程则也打印自己的pid和ppid,打印10次。
打印完后就等待子进程。
在这里插入图片描述

程序运行时,在前5秒内,父子进程都在运行,都在打印各自的pid和ppid,而5秒过后,子进程就结束了。但父进程还在运行,这时的子进程就处于一种僵尸状态。当10秒之后,父进程打印结束,开始等待子进程,这时就会等待成功,将子进程回收。
在这里插入图片描述

1.所以说,到现在来说,进程等待是必须的,因为可以回收僵尸进程!。
2.wait函数返回的是等子待进程的pid。然后父进程就可以根据fork返回的id和wait函数返回的pid来判断是否是自己的子进程。
3.wait()函数等待的是任意一个子进程,只要有进程处于退出状态,那么wait函数就会回收它。

那么如果是多进程呢?多进程退出,就需要多个进程等待了。

②.多进程等待

多进程等待,首先需要创建多进程,如何创建多进程呢?
调用一个循环,循环10次,在循环里,使用fork()函数创建子进程,在子进程程序跑完之后就退出。这样就可以利用父进程创建10个子进程了。
在这里插入图片描述
创建完多个子进程后,就需要父进程等待子进程了。
而我们还是可以使用wait函数等待子进程,因为wait可以等待任意进程,只要有进程退出了,那么wait()函数就可以回收它。
在这里插入图片描述

③.阻塞状态

不过当子进程一直在运行,假设子进程里有个死循环,而父进程一直在wait等待时,父进程调用的系统调用就会不返回,就会一直在那里等着,这种状态叫做阻塞等待。
在这里插入图片描述

3.获取子进程退出结果

①.status参数

进程等待其实除了wait函数之外还有一个waitpid函数。

1.wait系统调用和waitpid的功能都是等待回收资源。
2.waitpid的第一个参数表示要等待的进程的pid,也就是说,waitpid系统调用可以指定等待一个进程,而wait系统调用是等待任意一个进程的。
3.wait和waitpid都有一个参数 叫做status。它是什么呢?前面我们在调用wait时直接赋值成NULL。是为什么呢?
4.status其实就是用来获取子进程的退出结果。它是作为一直输出型参数,定义的目的就是将函数的结果给带出来。这里可以置NULL,是因为父进程没有必须要关心子进程的结果,是可以选择关心还是不关心的。
5.但是进程的退出结果通常有多种情况,比如退出正常还是不正常,是否出现异常等等,只定义一个变量可以吗?可以的,因为这个变量是被分成好几个部分使用的。

在这里插入图片描述
在这里插入图片描述

所以说status需要完成多个功能,而一个进程首先需要判断是否出现异常,如果没有出现异常再判断返回码。

status是如何设计的呢???
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
【思考问题】
在这里插入图片描述

所以进程等待过程中,发生了什么呢?
1.wait读取子进程的PCB内核数据结构。
2.将子进程的Z状态改成X状态。
子进程在退出后,会将自己的代码和数据先释放掉,但内核数据结构PCB并不会释放掉。而在内核数据结构PCB中就存着该进程的退出信息。

在这里插入图片描述

获取status的信息可以利用一些宏来实现:

1.WIFEXITED(status) :如果是正常终止子进程返回,则为真,如果出现异常则为假。‘检测子进程是否正常运行完毕。
2.WEXITSTATUS(status):可以提取子进程的退出码。
在这里插入图片描述

②.轮询等待

我们已经知道什么是阻塞等待了,就是子进程一直不退出,而父进程却在那里等待子进程退出,这时父进程就会一直阻塞在等待,后面的代码都运行不了。
在这里插入图片描述
那有没有什么办法可以让父进程不一直在等待嘛,让它后面的代码也运行起来呢?当然有!这个方法叫做轮询等待。

waitpid的第三个参数 pid_t waitpid(pid_t id, int *status,int options)
就是用来处理这个问题的。

什么叫轮询等待呢?

等待确实需要等待,但不是一直在等待,阻塞等待导致的主要原因就是因为没有等待到子进程,然后wait就不返回。而轮询等待是如果没有等待到子进程,也返回,只不过不是返回子进程的pid而是返回0,下次还需要再回来判断检测。如果等待到子进程那么就返回子进程的pid。并且跳出循环判断的语句。这样就可以做到,非阻塞,并且父进程还可以做自己的事了。
在这里插入图片描述

当三个参数options为0时,便是阻塞等待,当是WHNOHANG时,便是轮询等待。
在这里插入图片描述
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小陶来咯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值