信号的部分会在后面仔细讲,本文不涉及
目录
1.进程终止以及退出码的理解
2.进程退出
3.进程等待
1.进程终止以及退出码的理解
1.情况分类
(1)正常执行完
a.结果正确
b.结果不正确 反思为什么?
(2)运行中崩溃(进程异常)崩溃的本质:因为某些原因进程收到了来自操作系统的信号(比如kill-9)
之前我们写的main函数都会配return 0;这个数字0就是main函数进程的退出码
进程退出码:表征进程执行完结果是否正确,一般0表示成功,非零表示失败
因此退出码可供用户进行进程退出健康状态的判定
怎么提取退出码?
用这条指令
那么退出码是什么我还不是很了解,但是我知道退出码是包含一定信息的,这个信息会具体告诉我们进程的退出状态,现在只知道0表示进程成功退出,其他的退出码怎么看?
首先我们要知道获取错误信息的函数
把错误码输入进去会获得错误信息字符串,其实我们在linux中经常看到函数调用的返回值都有一句话,错误代码存放在errno中(对应上面strerror函数的as if set to errno),那么退出码也是一种错误代码,可以用它读取错误信息,所以我们用这样的函数查看系统中的退出码
结果是
...
到134基本上就没有错误信息了,也就是系统的退出码其实也就133个
具体看一下 0 对应的是成功(正常退出),2对应的是没有当前你说的这个文件/目录
这个报错好熟悉的感觉诶~~~~~
演示一下(当前目录并没有tmp这个文件)
!!!为什么感觉我没写代码,但是也能查到退出码?
因为你的指令ll就是一个进程,之前我们不是自己写过ll的,进程,指令,程序,这三个没什么区别的,所以只要是进程就有退出码,那么指令也有退出码
说到这我, 就可以先简单写一个程序看看退出码的获取
exit肯定大家都不陌生,之前在写程序需要异常退出的时候经常写 exit(-1)
发现确实获取到,但是再echo $? 怎么都是0
因为刚才说了,指令也有退出码,echo $?查的是最近一个程序的退出码,那第二次查的就是第一条echo $?的退出码,由于这条指令成功,所以退出码是0
既然系统有退出码,我们就可以自定义退出码
方式:写一张充满报错信息的表,然后给表中的字符串赋值
2.进程退出
- 如何理解进程退出?
进程=内核数据结构+代码和数据
OS少了一个进程,就要释放进程对应的代码和数据(如果有独立的)
- 都有哪些退出方式
1.main函数return 那其他函数return呢?仅代表该函数返回,进程执行的本质是main执行流执行
2.exit退出
可以用man查三号手册看到exit
还有一个函数_exit 可以在2号手册查到
这时候已经感觉到一点不对了
man 1:用户指令
man 2:系统调用
man 3: C库调用
我们更推荐的是exit,原因来看下面的代码
这段代码使用了_exit但是没有我们手动刷新缓存区,但是一直到最后都没有刷新(因为运行之后的结果什么都没看到)
换成exit()
看到hello了
所以_exit和exit的区别自然体现
那么我们猜测一下缓冲区在哪?
肯定不在操作系统内部,要是在的话,_exit也调用了系统接口,那么也能刷新缓冲区,这与事实不符,那就只剩用户层和C库了(以后我们会专门谈)
可以猜测exit()其实是对_exit的封装
这就回答了进程是如何退出的问题(即如何删除进程)
删除进程一定由操作系统完成,所以操作系统把接口提供给用户,exit调用这个接口完成删除
3.进程等待
1.为什么要等待?
a.避免内存泄漏(目前一定要做)
b.获取子进程执行结果(如果必要)
这就引出了新的思考为什么要创建子进程?
因为有时候父进程想把一些任务分给别人做,同时自己可以做点别的事情,或者自己什么都不干(扣题 进程等待),所以我把任务交出去就需要知道我的子进程把事情办得好不好——获取子进程执行结果
执行结果有如下几种:
1.代码跑完结果对——>退出码
2.代码跑完结果不对--->退出码
3.代码运行异常——--->信号
所以这个过程中 退出码+信号 是最重要的
2.什么是等待?
通过系统调用获取子进程退出码或者退出信号的方式顺便释放内存问题(因为之前讲过退出码/信号中包含很多信息,获取他我们就能知道子进程完成的如何)
谁等?父进程
等谁?子进程
3.如何进程等待?
用wait/waitpid
man 2 wait 查到(2号手册是系统调用接口手册)
看这两个函数,参数是int *status——>输出型参数
也就是在wait/waitpid函数内部会获取到status的值最后函数调用结束得到status
那么以waitpid举例(他的参数更多,看懂他wait自己可看懂了)
明确我们想通过status获得什么?
子进程的退出码+信号
那么信号怎么查看?kill -l
发现信号也是整数
那么位图是什么?
举个例子:假设四个人吃饭,屋子里有八个椅子(有序),我们用1表示这个椅子上有人,那么八个椅子可以表示成 0111 0100 —— 这就可以成为位图
同样的权限也是一种位图(权限的八进制表示)
也就是status的32位如下
其中core dump暂时不讲
那么怎么分别获取退出状态和信号?位运算
获取信号——status & 0x7F
获取退出码——(status>>8) & 0xFF
- 父进程如何获取子进程信息?
- 父进程在wait时若子进程没退出,父进程在干什么?
- 如果我们不想阻塞等待呢?也就是不想在waitpid卡住怎么办?
小故事:
你给一个人打电话他说他有事,你说让他先忙但是别挂电话
打电话就对应着系统调用waitpid,此时他没挂电话——阻塞式调用——结果有两个:好了/出错
第二天你还是找他有事,但是这次他说完有事就挂了,你一次一次打过去,他一次一次说还没好就挂——做了很多次状态检测——非阻塞式轮询 结果:好了/还没好/出错
- 如何设置非阻塞轮询?
再加上return 0;
当然其实我们可以用宏判断进程是否退出正常还有查看进程的退出码
记忆方法都在图中加粗
当然父进程在非阻塞轮询的时候还可以干点别的(可以自己写写代码)
还有后续:进程替换哦,关注不迷路