让进程退出的方案::在main函数退出
在其他函数中return,表示的是函数调用结束
exit(参数):让进程退出
参数是进程退出码,可以自己设置进程退出码
参数是进程退出吗类似(等价)于main中的 return n
exit在子函数中的话,在main中就不会执行子函数下面的代码(下面直接ech&?是21)
任意地点调用exit,表示进程退出,不进行后序执行
_exit:终止调用进程
也是终止进程,(2)号手册,exit 是3号手册
函数调用完成,main函数也调用了
直接在fun里面退出了,也没有执行下面main下面的代码跟exit一样,那到底区别是什么?
区别:
1.exit三号手册
带\n 的 exit sleep之前就显示打印信息了
去掉\n 三秒后才打印信息
原因区别:
(没有\n)就没有立即刷新(如果想让他立即刷新用ffushn),三秒后才打印,因为没有碰到刷新条件(\n),一直到退出(退出也算刷新条件)main函数中的return也能达到这个效果
但是此时(没有\n)如果是_exit的话不会打印printf中的内容(不会自动华鑫缓冲区就退出了)
_exit时三秒后进程终止,但是字符串没有打印(刷新)
原因:_exit终止进程不会自动刷新缓冲区
_exit是系统调用的接口 forlk也是
结论:缓冲区,绝对不在操作系统内容部
exit底层是_exit理论上是都要刷新缓冲区,但是因为exit是c标准库函数(有自己的缓冲区)所以他会写在系统内部,exit先把数据从c标注库写到os再刷新,但是直接调用_exit时os里面并没有数据,不然的话双方都应该刷新
进程等待
进程等待的重要性
僵尸进程kill也杀不掉
1.什么是进程等待
2.为什么要进行等待
父进程要知道子进程执行的结果,父进程再返给用户,也有父进程给子进程不在乎子进程执行的结果,要就有退出信息,不要就没有
3.如何进行等待
只不过wait是吧z改成x状态了
监视代码:while :; do ps ajx | head -1 && ps ajx |grep myprocess | grep -v grep; sleep 1; echo "---------------------------"; done
wait
等待进程改变state,两个头文件 参数*status
作用:
一次 等待父进程任意一个子进程的退出
代码
此时还注释掉sleep(10),这里wait是等待任意一个子进程返回
成功就返回子进程(终止的子进程)的id,否则就返回-1
五秒后子进程跑完了进入僵尸进程
再过5秒后子进程消失了(被wait拿走了)只剩下父进程了,再过5秒父进程也退出消失了
- 在父进程中,
fork()
返回子进程的pid(正数)。- 在子进程中,
fork()
返回0。- 如果出错,
fork()
返回一个负值问:
当注释掉sleep在子进程运行期间父进程有没有调用wait呢?再干什么呢?
看before是立马出来,after还是等了很久才出来
子进程执行后再执行wait的(回收的)右边监视里面从两个s+变成一个,没有出现过z
没看过子进程僵尸了
阻塞等待
所以执行等待时候,子进程根本没有退出,父进程必须在wait上进行阻塞等待,知道子进程僵尸,wait自动回收(pcb回收?释放资源)
进程不仅等待硬件(键盘等待输入文字)也可以等待软件(挂起)
所以一般子父谁先运行不知道,但是一般是父进程后(通过阻塞等待)退出(等子进程死掉)
waitpid作用
wait不能指定等待进程,但是waitpid可以等待指定进程,wait不行,pid可以直接设置成-1(此时和wait相同等待任意一个进程)成功返回>0,或返回等待子进程的pid,当返回<0返回失败,option设置默认为0默认阻塞等待(暂时不管)
代码
等子进程执行完父先sleep10秒
取消注释s10
更wait一样等子进程结束后after才出来
status
整形指针类型,输出型参数status把地址给os,os把值给status
os把结果以参数的形式带回来给status(例如把子进程退出码返回出来)但是他没有返回10,返回的是2560,例如
为什么不是10而是2560呢?2560是什么?(10跑到了低八位)
status构成:
status是一个int的整数,32bit,低16位(低16位划分成三部分)
1010 0000 0000 转成二进制是2560,所以如果想从子进程获取退出结果(有没有出问题),要分析statue的二进制
正常终止时低16为退出状态 如果是被信号所杀(异常状态时的低16位)后面是终止信号
exit code
8-15
就是 退出状态(退出码)
exit sig
0-7
就是终止信号(低七位)
所以我们不能对status直接进行使用,需要对status进行位操作
拿到退出码如果子进程是esit(0)就是正常退出代码跑完结果正确
位操作提取信息,sig(就是终止信号(低七位按位与(保留后七位吗,后期为是终止 信号)))
信号列表没有0号新号,0,0是代表代码跑完了没问题,01是代码跑完了有问题 10是中间有异常了,sig为几就是发生了几号异常
退出信号是0说明跑完了退出代码是1说明代码可以自定义
手动让代码异常
得到8号信息了(得到原因)
1.当一个进程异常了,exitcod还有意义 么?没有
2.有没有收到信号怎么判断?
信号列表没有0号新号,0,0是代表代码跑完了没问题,01是代码跑完了有问题 10是中间有异常了,sig为几就是发生了几号异常
3.手动杀掉这个子进程?
子进程一直进行
杀掉子进程后父进程立马返回了(变成僵尸父进程立马回收他(wait))返回信号sig是9(9号原因是手动杀死 )
问:
父进程如得知子进程的退哦出信息呢?是wait和waitpid(系统调用接口),os是怎么调用这两个接口的?
子进程也有自己的进程控制块,有自己的代码和数据
子进程退出后子进程的pcb一定包含它的退出码和退出状态 , wait和waitpid把这两个更改,然后组合成status返回
提取进程的退出码
WIFEXITED
就是说 sig没问题就往下走
WEXITSTATUS
直接提取退出吗
多个进程退出
-1是任意一个子进程
每个子进程的退出码
终止的时候也没有规律
我们为什么不用全局变量 获取子进程的退出信息?
因为全局变了是父进程开始有的,当子进程退出时,如果子进程把状态写进这个全局变量里,此时父进程是读不到这个全局变量的,因为在多进程中对同一个变量写入是会发生写实拷贝,当对子进程因为进程具有独立性,父子虽然在一分代码里,父进程没办法调用子进程的数据
进程具有独立性,父进程无法直接获取子进程的退出信息,所以操作系统需要进程来调用WEXITSTATUS
options
0是阻塞状态
wnohang:
等待的时候,以非阻塞的方式等待
故事1好处:你可以干自己的事情(顺便玩手机,看视频)比如调用别的进程
故事2好处:父进程什么都干不了,等子进程
代码:
此时并没有轮询检测(只检查了子进程一次 )
加上循环,基于非阻塞轮询检测方式
rid > 0:等待成功 可以break
rid ==0:等待是成功的,但是对方还没有退出
此时子进程没有退出,但是waitpid立马返回==0,父进程可以干自己的事情(非阻塞循环等待)
当rid<0 可以break
等待失败,子进程无法获取 等待失败比如说,输入子进程代码错了
非阻塞状态的用处
以前我们的父进程一直等待子进程结束,现在以非阻塞状态进行,父进程就可以干自己的事情了