朋友们、伙计们,我们又见面了,本期来给大家解读一下有关Linux程序地址空间的相关知识点,如果看完之后对你有一定的启发,那么请留下你的三连,祝大家心想事成!
C 语 言 专 栏:C语言:从入门到精通
数据结构专栏:数据结构
个 人 主 页 :stackY、
C + + 专 栏 :C++
Linux 专 栏 :Linux
目录
1. 进程创建
1.1 fork返回值
1.2 fork调用失败的原因
2. 进程终止
2.1 进程退出的场景
2.2 退出码
2.3 进程常见的退出方式
2.4 退出码和错误码
2.5 进程异常
1. 进程创建
进程创建在之前的进程创建与fork本质这一章节已经详细介绍过,这里就简单回顾一下。
创建进程我们通常使用fork函数,在linux中fork函数时非常重要的函数,它从已存在进程中创建一个新进程。新进程为子进程,而原进程为父进程。
#include <unistd.h> pid_t fork(void); // 返回值:子进程中返回0,父进程返回子进程id,出错返回-1
进程调用fork,当控制转移到内核中的fork代码后,内核做:
- 分配新的内存块和内核数据结构给子进程
- 将父进程部分数据结构内容拷贝至子进程
- 添加子进程到系统进程列表当中
- fork返回,开始调度器调度
fork之前父进程独立执行,fork之后,父子两个执行流分别执行。注意,fork之后,谁先执行完全由调度器决定。
1.1 fork返回值
- 子进程返回0
- 父进程返回子进程的pid
1.2 fork调用失败的原因
- 系统中有太多的进程
- 实际用户的进程数超过了限制
2. 进程终止
2.1 进程退出的场景
每一个进程退出场景无非就这三种情况:
- 代码运行完毕,结果正确
- 代码运行完毕,结果不正确
- 代码异常终止
在多进程环境中,我们创建子进程的目的就是为了让子进程帮助我们完成一些任务,那么我们怎么知道子进程把任务完成的怎么样呢?所以就需要知道子进程在退出时带给我们的反馈信息--退出码
2.2 退出码
退出码表示的是我们运行完毕,结果是否正确合理。
Linux查看退出码:echo $?
main函数也是个函数,我们一直都在写的main函数中的return 0表示的是什么意思呢?
main函数的返回值,就叫做进程的退出码。
退出码为0表示进程运行成功;
退出码为非0表示进程是因为什么原因失败的。
通过上面的图片可以发现,为什么我们第一次查看退出码是10,表示main函数的退出码,但是为什么第二次再查就变成了0呢?
echo $?:保存的是最近一个子进程执行完毕时的退出码。
我们在命令行输入的指令也是一个程序,先运行我们自己写的main函数,查看的时候就是main函数的返回值10,再次查看的时候,最近一次运行的进程就变成了我们上一次查看退出码的指令,这个指令运行成功了,所以第二个才看到0。
2.3 进程常见的退出方式
正常终止
1. 通过main函数的返回;
2. 调用exit / _exit函数;
exit函数
#include <unistd.h> void exit(int status); // status退出码
_exit函数
#include <unistd.h> void _exit(int status);
细节问题:
1. 其它函数中进行return,表示的是函数调用结束。
2. 任意地点调用exit/_exit,表示进程结束,不会执行后续代码。
exit与_exit区别
1. exit()是库函数,_exit()是系统调用。
2. exit()终止进程时会刷新缓冲区,_exit()终止进程时不会刷新缓冲区。
退出码都是数字,不便于我们查看,所以也提供了转化为字符串形式的退出码。
在C语言中有一个函数可以打印错误信息:strerror
接下来我们就将系统默认的退出码打印出来看看分别都对应哪些信息:
#include <stdio.h> #include <string.h> #include <errno.h> int main() { for (int i = 0; i < 200; i++) { printf("%d: %s\n", i, strerror(i)); } return 0; }
在0~200之间系统默认的只有0~133表示退出信息。
使用退出码时我们不仅可以使用系统默认的,也是可以自定义的。
我们需要知道的是:main函数的退出码可以被父进程获取,用来判断子进程的运行结果的!
2.4 退出码和错误码
错误码是C语言中一个变量errno,当我们调用库函数失败时,错误码就会被设置。
退出码:一个进程退出时,它的退出结果。
错误码:衡量一个库函数或是一个系统调用的调用情况。
2.5 进程异常
当一个进程异常终止了,此时的退出码已经不重要,我们需要知道的是它因何种原因异常终止。
就比如语言级别的除0错误、对空指针的解引用以及越界访问。
当我们有这样的程序运行起来之后,就会变成OS内的一个进程,此时OS检测到了进程出现异常,那么就会给该进程发送指定的信号来终止进程。
当我们程序运行起来之后,我们也可以给它发送信号让它异常终止:
所以,一个进程是否异常,看我们是否收到信号,一个进程运行结果如何,通过退出码判断。他们两个都是数字,父进程可以接收到这两个数字,然后判断程序的合理性即可。
朋友们、伙计们,美好的时光总是短暂的,我们本期的的分享就到此结束,欲知后事如何,请听下回分解~,最后看完别忘了留下你们弥足珍贵的三连喔,感谢大家的支持!