前言:Linux进程控制是指在Linux操作系统中,对进程的创建、运行、管理和终止等方面进行控制的一系列机制和技术。Linux作为一个多任务操作系统,能够同时运行多个进程任务的执行,继前面我们对Linux进程创建的学习之后,今天我们来深入了解Linux的进程控制。
目录
1.进程创建&fork函数
2.写时拷贝
操作系统如何辨别进程要采取写时拷贝?
既然需要修改,为什么还要进行拷贝操作?
3.进程终止
进程正常退出
错误码vs退出码
C语言中的退出码
C语言中的错误码
进程异常终止
进程退出总结
1.进程创建&fork函数
fork函数我们在很早之前就已经提到,它从已存在进程中创建一个新进程。新进程为子进程,而原进程为父进程。进程调用fork,当控制转移到Linux内核中的fork代码后,内核做:
分配新的内存块和内核数据结构给子进程
将父进程部分数据结构内容拷贝至子进程
添加子进程到系统进程列表当中
fork返回,开始调度器调度
fork之前父进程独立执行,fork之后,父子两个执行流分别执行。注意,fork之后,谁先执行完全由调度器决定,并不是一定要子进程或者父进程先执行。
2.写时拷贝
通常,fork函数之后,父子代码共享,父子在不写入时,数据也是共享的,当任意一方试图写入,便以写时拷贝的方式各自一份副本。
操作系统如何辨别进程要采取写时拷贝?
当父子进程任意一方想要进行修改的时候,操作系统必然需要为这个进程重新申请物理内存空间,然后将原来的数据拷贝一份到新申请的空间中,并且还需要修改页表的映射关系,所以,操作系统需要对我们想要写入父进程或者子进程的数据的行为进行识别,以采取相应的措施。
结合上面的写时拷贝示意图,当用户需要对父进程或者子进程进行写入操作时,此时,由于父子进程的页表项的虚拟地址都是只读状态,用户的写入操作会和页表项的访问权限冲突,此时操作系统就可以识别这个行为,并将该行为识别为需要进行写时拷贝的信号......
等一下,你这说的云里雾里的,能不能说明白点?
那,我们来整一个图解释一下,这样应该更好理解了,
既然需要修改,为什么还要进行拷贝操作?
当我们需要写入的时候,不论父子进程,最终的目的都是需要修改该进程中的值,但是,为什么一定要将原进程的数据拷贝一份到需要修改的进程的新的物理内存处呢?按我们的想法,直接开辟一份大小和原进程一模一样的数据块,直接等待数据写入不就行了?为何要多此一举呢?
事实上,进行写时拷贝的内存往往不止一个变量,而是一个数据块,里面往往可能包含多个数据成员或者一个数据整体,比如结构体,链表等,一般情况下,我们不会修改全部的数据,只是修改一小部分,在写入之前拷贝,可以尽可能的保存原始数据,无需进行全部写入的操作。
3.进程终止
进程常见的退出场景一般有如下三种:
代码运行完毕,结果正确
代码运行完毕,结果不正确
代码异常终止
我们需要将其分为两个方面进行讨论,我们将前两种情况,也就是代码能够正常退出归为一种,代码异常终止归为一种。
进程正常退出
错误码vs退出码
我们在写main函数时,最后都要返回一个0,一般的,我们都能了解到main函数的返回值为0,表示成功,非零表示的是失败。我们知道,一个进程,最终运行成功了(返回了0),我们一般不会在对该进程的执行情况做过多的探究,但是,一旦进程最终运行异常退出了(返回类非0值),我们就想想方设法的搞清楚这个进程为什么会异常退出,是哪里的原因导致异常退出,这也就导致了进程异常退出会被分为多种情况类型,每种情况类型的异常状态都不同,借此来反应异常的原因。我们main函数的返回值,都叫做退出码。退出码,就是一个进程退出时返回的退出结果。而错误码的范围就会更小一些,是用来衡量一个函数或者是一个系统调用一个函数的调用情况,如果失败了,则会返回函数或者进程失败的具体原因。
我们可以通过 echo $? 命令来查看最近的一个子进程的退出码。
C语言中的退出码
C语言中内置了一些退出码,用不同的数字表示不同的退出码的解释,其包含在头文件string.h里面的strerror函数中,我们可以试着将其打印出来:
C语言中的错误码
C语言中有一个内置的全局变量errno,该变量专门用来保存函数或者进程出错返回的错误码,这个错误码,和我们的退出码是相同的,只是用专门的变量来保存,当然也可以用strerrno函数来打印出这个错误。但是需要注意,errno的使用,需要包含errno.h头文件。由于和退出码相似,这里就不在演示。
进程异常终止
进程出异常,本质上是收到了信号,自己终止了进程,此时虽然也有退出码,但是此时的退出码已经没有意义。比如我们熟知的杀死进程的指令: kill -9, 该命令其实就是一个信号,当进程收到这样的一个信号,就会自己停止并退出进程。我们常见的一些信号如下:
上面的这些信号,每一种信号都有对应的数字,当我们的代码出现了问题导致无法正常执行,操作系统就会给我们的进程发送指定的信号,进程收到指定的信号之后,就会对应的停止我们进程并返回错误原因,既然是这样的话,也就是说,一个正常的代码,在运行过程中,只要收到了信号,该进程就会立即响应并退出,我们来验证一下,
进程退出总结
未完待续~~~