1.进程控制
1.1fork
具体的我们前面已经讲过了
1.2写时拷贝
我们在进行fork之后两者会共享代码,本来父进程对代码和数据的权限是读和写,fork之后会变成只读状态,两者都是这样的(页表来控制的)
如果有一方尝试想要更改的化,就会使用写时拷贝的方式,直接在物理内存中申请一块空间,虚拟地址不变,和父进程是一样的
2.进程终止
我们开启一个进程CPU会做一些列动作,开pid等等
那么一个进程终止了,内核都在干什么?
先是释放pcd,然后释放内核,和数据代码
进程终止不外乎就三种情况
代码跑完,结果正确
我们在main中我们一般在后面写一个return 0;
代码跑完,结果错误
这两种情况可以一起说的,我们在进程当中,可能遇到return,就是一个函数结束了,此时会有一个返回值,我们可以通过观察者个返回值,来判断我们的进程有没有执行成功,一旦有了返回值,我们都说代码跑完了,系统当中,有一套固定的错误码,就是看一个返回值,对照这个码,来找为什么错误,但是在实践过程中我们往往,自己来定义不同的数字,来表示什么,从而找到原因
代码没有跑完,进程异常
为什么异常?往往是被信号给终止了
此时是没有return的,因为代码都没执行完毕,退出码无意义
所以上面在种情况,我们可以进行总结
1.代码跑完
signums:0;退出码:0/其他数字(就是结果错误)
signums:!0,说明代码没有顺利执行完毕
我们以后可以用这两个来观察进程情况
这两个数字需我们来进程维护吗?
不需要!
进程结束之后,os会把进程的这两个数据,交给结构体,所以我们再推迟一个进程的时候会先进入僵尸状态(z)之后在全部消除
3.如何让进程退出?
1.就是main当中的return,就可以让进程结束
2.exit在main函数当中,这两个是一样的

也是有一个返回值,和return一样
可以使用 echo $?进行查看一个最近进程的退出码
那这两个有什么区别呢?
这两个的区别主要体现在函数中,假如说我们在main之外写一个函数,

我们在main中调用这个函数,如果我们这个函数是return,那么这个函数运行结束之后,就回到main继续运行,如果是exit那么整个进程就会结束,main也直接停止了
总结:return,结束函数,exit结束进程
3._exit
exit在一个代码结束之后我们会进行刷新,也就是我们前面所说的,如果打印printf后面不写\r\n
这个就会存在缓存区当中,如果不进行刷新就不会显示内容,我们之前学的return是会自动刷新一下,exit也会
但是_exit不会,也就是说我们要是使用_exit来结束进程的化,不会自动刷新缓存区,咱们上面讲的例子就是不正确的,也就是永远不会刷新,用用于不会显示!!!
补充:_exit是系统调用,更加底层,我们使用的exit是库函数,也就是基于_exit创建的
4.进程等待
必要性:
第一个好处(必须):我们在父进程当中fork一下,创建子进程,如果我们此时需要子进程的数据,此时父进程就会进入等待,也就是阻塞状态,等到子进程将数据返回,之后在进行下一步的回收,假如子进程没有退出,那么父进程一直在wait中
如果不进行等待,那么子进程执行完毕之后,就没人会回收它,就导致内存泄漏!!!!

第二个好处是:父进程可以获取子进程的退出信息
通过wait的函数返回值

或者waitpid的返回值

我们来解释wtitpid
第一个pid==-1或者生成子进程的pid
如果直接是子进程的pid就肯定可以获取数据
但是如果是-1呢,父进程当中有一个列表里面存了它的所有子进程,他就会检索,找到第一个状态为z的子进程,来作为子进程返回的数据
status是用来接收子进程退出信息的,本质就是得到子进程退出时返回的两个数据,经过位运算,
以32位后16位是用来记录,后8位是信号,前八位是退出码,会转成二级制组合到一起,就过这样的计算就可以算出这个二级制码,来接受子进程执行情况。