地址空间收尾-进程控制

文章目录

    • 进程终止
      • 进程退出场景
      • 退出码
      • 错误码errno
    • 代码异常终止
    • 进程终止的操作
      • void exit(int status)
      • _exit

子进程为什么能继承父进程的环境变量呢?并且具有全局属性?
通过打印地址实验可以发现,进程的环境变量在栈区之上
父进程的环境变量也是由bash继承下来的,必定有页表帮助我们从虚拟到物理的映射,创建子进程的页表时也会将对应父进程的地址空间中环境变量的对应映射建立好,所以即便不传对应的env参数,子进程也能获得环境变量信息。

用户空间和内核空间
0G-2G是给用户使用的
3G-4G是给操作系统的
我们的PCB对象数据结构本身和进程地址空间也要在物理内存中放的哦,操作系统内核中的数据结构一定要映射到地址空间内核空间中
地址空间收尾-进程控制_第1张图片

页表级写时拷贝原理

现在再来理解为什么代码不能被修改这句话
因为页表中把代码区的映射标志位设置为只读权限,所以代码就不可写!但是父进程尝试对数据进行写入时就可能会影响到子进程,反之亦然!
无论是父还是子想对数据进行写入,谁先写,谁就要先进行写时拷贝
在这里插入图片描述
操作系统是怎么知道父子进程是共享数据块此时需要发生写时拷贝的呢?
在创建子进程前,即便数据是具有读写权限,在创建子进程后,操作系统把父子进程的数据读写权限全部改为只读,此时不管父还是子想要对数据进行写入一定会引发系统级的权限问题,不过此时不会做异常处理,而是转而帮我们做写时拷贝,并且对该数据重新建立页表映射,并且把相关标志位改为读写恢复出来,就完成了写时拷贝。
本身是后续看谁先触发写入的错误,然后再来判断谁要先写时拷贝。
地址空间收尾-进程控制_第2张图片

创建多个进程
地址空间收尾-进程控制_第3张图片

结论
地址空间收尾-进程控制_第4张图片

当子进程被创建出来时哪一个子进程先运行,或者是父进程和子进程哪一个先运行呢?
当创建出多进程时,无论是兄弟关系还是父子关系,到底哪一个进程先运行完全由调度器绝定

进程终止

问题:
为什么main函数总是会返回return 0? 1? 2?,这个东西给谁了?为什么要返回这个值?
要回答这个问题就要先讲讲一个程序退出的三种场景,也只有这三种

进程退出场景

地址空间收尾-进程控制_第5张图片
一个进程运行退出后,结果是正确的那我们就不关心了,但要是结果不对,我们就最想知道为什么不正确。

退出码

所以return 0代表进程的退出码,表征进程的运行结果是否正确.0->success
地址空间收尾-进程控制_第6张图片
系统内置了许多错误原因,进程运行正确只有一种但是错误可有很多种原因
地址空间收尾-进程控制_第7张图片

return给谁了?
给了我们进程的父进程,也就是main函数返回给bash了退出码,程序运行结果怎样bash要知道。
有时候程序运行结果只能靠退出码。

父进程为什么要关心?
父进程也是跑腿的,把结果转交给用户,最终可以让我们用户做出相应的对策,又或者父进程可以根据返回值做一些事情。
用户可以用strerror(退出码)将退出码转为字符串描述
地址空间收尾-进程控制_第8张图片

错误码errno

地址空间收尾-进程控制_第9张图片

errno是C语言提供的全局变量,他保存最近一次执行的错误码,调用库函数失败后的原因设置为对应的数字。
如果对应库函数调用失败后,可以将错误码转为退出码交给父进程
地址空间收尾-进程控制_第10张图片

代码异常终止

什么是代码异常终止?
出现除零错误,对空指针野指针的访问后程序立即终止了
地址空间收尾-进程控制_第11张图片

代码异常了,退出码还有意义吗?
代码异常了本质可能就是代码没有跑完,这样的话退出码就没有意义了
就像考试时临近最后一秒做了个弊,那你的成绩还能有效吗
所以只要代码异常了,退出码无意义,我们不关心退出码了。

结论:一个进程结束后先看进程有没有发生异常,再看进程的退出码!

进程出现异常,本质是我们的进程收到了对应的信号!!
验证一下
只需要让进程一直处于正常运行状态,之后向他发送对应的信号
地址空间收尾-进程控制_第12张图片
地址空间收尾-进程控制_第13张图片

进程终止的所有场景都说完了,下面来看看进程终止的操作

进程终止的操作

void exit(int status)

正常终止一个进程

地址空间收尾-进程控制_第14张图片
exit(int status) int status这个参数就代表进程的退出码

exit 和return 在main函数里是等价的,都表示进程退出了,那么他们有什么区别吗?
地址空间收尾-进程控制_第15张图片
return 在其他函数中代表函数结束了,在main函数中代表进程退出,exit在任意地方都代表进程退出了

地址空间收尾-进程控制_第16张图片

_exit

也能终止一个进程
地址空间收尾-进程控制_第17张图片
exit 和 _exit 有什么区别呢?
exit 是库函数,_exit是系统调用接口,exit会刷新缓冲区,但_exit没有
地址空间收尾-进程控制_第18张图片
由此引出一个问题,缓冲区绝对不在哪里?
绝对不在内核中,如果在的话,操作系统不做任何浪费时间浪费空间的事情,操作系统的系统调用_exit也绝对会刷新缓冲区,如果你都不刷新,那么你维护这个缓冲区干什莫呢?
那到底在哪里呢?现在只能说在用户空间里

你可能感兴趣的:(Linux,linux,1024程序员节)