一、什么是进程
二、进程的创建
三、进程的状态
四、僵尸进程
五、孤儿进程
六、进程的优先级 以及 并发/并行
七、进程的切换
一、什么是进程?
什么是进程呢(一)?
官方话来说:进程是一个执行实例、正在执行的程序、是系统资源分配的基本单位
按课本官方话可能有一点点的不好理解
通俗的讲:当你电脑上的程序,比如qq 你双击运行起来,此时他启动了,那么他现在就是一个进程
再深讲:当你的代码被编译链接成为一个可执行程序,这个可执行程序本质上是一个文件,是被放到磁盘里的,当双击运行,这个程序会被加载到内存,也就是大家所说的内存条,当加载到内存,
此时程序的代码会一条一条的被cpu执行,此时这个程序不再叫程序而是叫做进程了
在Linux下通过指令ps aux 可以查看当前正在运行的进程
还可以通过系统目录查看当前进程
什么是进程呢(二)?
看过我前面文章里的操作系统的话,我说到了操作系统的管理
操作系统要对进程进行管理,如何管理的呢?
进程再往深讲:进程就是一个结构体,这个结构体名字叫做PCB控制块
PCB控制块里面存放了进程属性的集合
PCB在Linux下就是 task_struct 名字的结构体
所谓的进程记载到内存,实际上就是PCB结构体加载到了内存
在这个PCB结构体内存放了进程的各种属性,比如进程状态、优先级、标识符、父进程标识符、
程序计数器、内存指针、上下文数据、其他信息等
这些PCB结构体会被以双向链表的形式被操作系统进行管理
通过这样,操作系统可以访问所有的PCB,也就等于访问到了所有的进程,对进程的管理也就转换为了对PCB结构体的管理
当一个程序被启动变为进程,进程的代码和数据会加载到内存,然后操作系统会形成相应的PCB,
并把PCB放入链表中,而一个进程的退出,也就是从链表中删除这个节点,然后对代码和数据进行释放
总结就是:操作系统对进程的管理实际上就变成了对链表的增删改查、不管是对进程的管理,还是文件内存等,本质都是对一种数据结构的增删改查
二、进程的创建
通过系统调用可以在一个进程中再创建一个子进程
fork函数创建子进程
运行结果是每次循环会打印两行数据,第一行是该进程的Pid和PPid
第二行是子进程的Pid和PPid
我们可以发现这两个进程是父子关系,子进程的PPid=该进程的Pid
每次出现一个进程,操作系统就会为其创建一个PCB,fork函数创建的进程也不例外
为什么子进程也执行跟父进程相同的代码呢?
原因解释:子进程被创建后会共享父进程的代码和数据,但是采用的是写时拷贝
什么意思呢?子进程会执行和父进程相同的代码,但是如果修改父进程的数据,他就不会共享该数据的地址了,而是为自己开辟一个空间放这个数据,这样的设计减少来了内存的浪费,只有在需要的时候才分配内存
注意点⚠️:fork函数是返回两个返回值的,因为在fork函数内部就已经创建了子进程,已经分配了PCB,并且放入了cpu的调度队列,在fork函数内的return返回值前已经是两个进程在跑了,所以父子进程的执行顺序是不确定的,取决于操作系统的调度方式
如何让子进程执行自己的代码呢?
使用if进行分流即可,因为有两个返回值,而两个返回值明确区分了,=0代表是子进程,>0代表是父进程,通过if区别返回值,即可让父子进程执行不同的代码
如果返回值<0 代表创建进程失败了,可能是因为没有内存了,也可能进程创建数量达到了上限
三、进程的状态
一个进程从创建到销毁,会经历很多不同的状态
我这里直接总结了一下:
创建/新建状态:
如果一个进程在被创建的时候,比如分配PCB,比如fork函数内,那么这个进程就处于新建状态
什么是新建状态呢?就是还没有被执行
就绪状态:
当分配完PCB并且放到了cpu的调度队列,等待被cpu执行自己的代码,此时就进入了就绪状态
也就是等待被执行
运行状态:
当真正被cpu调度的时候,开始执行自己的代码,就进入了运行状态
阻塞状态:
当在程序运行中,因为某种原因阻塞,比如等待键盘输入数据,此时操作系统识别到后,会把进程放入该等待外设设备的等待队列中,然后进程进入阻塞状态,直到键盘输入数据,操作系统才会重新将进程重新放入运行队列里去等待执行
阻塞挂起状态:
什么是阻塞挂起状态呢?当内存中由于进程数量过多,内存不够的时候,操作系统会选择将一部分进程的代码和数据放入磁盘中,只在内存中保留PCB控制块,这些代码和数据会被放到磁盘中的swap分区中,这个分区的大小一般是内存的1.5倍或者2倍,当需要的时候就把代码和数据再交换会内存进行调度,这就是阻塞挂起状态
个人超详细总结:
四、僵尸进程
还有一种状态叫做僵尸状态 - Z
当一个进程变成僵尸进程就陷入了僵尸状态
僵尸进程:父子进程中,子进程退出,但是父进程没有回收子进程的资源,导致子进程的PCB控制块一直保留在内存,虽然子进程的代码和数据已经释放,但是PCB控制块没有释放,导致内存泄露的问题,此时子进程变成僵尸进程,使用kill命令也无法杀死
为什么会有僵尸进程呢?
因为子进程的PCB控制块内有返回值信息和状态信息,还有自己的pid
这些信息可能对于父进程是有效的,所以系统不会主动释放,而是等待父进程来回收这些资源才会
释放
僵尸进程的危害?
如果一个父进程创建了很多子进程都不回收,造成严重的内存泄露问题,可用资源越来越少
如何解决僵尸进程呢?
父进程调用系统调用来进行回收,或者通过捕捉信号的方式(涉及到信号的知识)
如果已经发生僵尸进程,需要杀死父进程来让僵尸进程变为孤儿进程被系统自动领养回收
五、孤儿进程
前面提到了僵尸进程,那什么是孤儿进程呢?跟僵尸进程相反
如果父进程早于子进程退出了,此时子进程没有父亲了,就变成了孤儿进程
孤儿进程会被1号进程也就是系统领养,由系统管理回收
孤儿进程最终会被释放,而僵尸进程危害较大
六、进程的优先级 以及 并发/并行
简短总结:
七、进程的切换
简短总结: