在本篇博客,会了解到什么是进程,什么是进程pcb。
在很多的教材里边啊,一个运行起来的程序,我们那么叫做我们可以称之为一个进程啊,换句话说呢,程序运行起来程序,必须先加载到内存。什么叫做运行起来呢?那么给运行起来下个定义啊,那么就叫做加载到内存。加载到内存之后变成了进程。
那么还有的教材说在内存中的程序就称之为进程啊。
下面这两个是一样的概念。
进程和程序相比,进程具有动态属性,为什么经常要具有动态属性,那么和普通程序比又有什么区别呢?
通过画图理解,我们只考虑磁盘内存,cpu。
你自己写好的C程序,编译好形成了一个可执行程序,写好编译好之后,那么此时这个程序本质是什么东西呢?这个程序我们编好了,它是二进制可以运行的,那这个程序是什么呢?那么程序的本质?就是文件啊,这个文件在哪儿呢?那么在磁盘上。放着呢啊,大家都知道磁盘是个外设。
程序的本质是就是文件
下面hello.exe刚刚编译好的可执行文件,就存放在c盘
根据冯诺依曼,我要把这个软件运行起来,那么必须得先把该软件从磁盘加载到内存当中。所以呢,这个软件就被放在了我们所谓的内存里面,那么这个软件里面包含了它里面的各种二进制成员。代码了和数据了,就在内存里了。
然后CPU是不是就可以去读取它了 ?没有那么简单。
请问你自己的软件在磁盘里那么编译好运行起来的时候?有没有可能系统磁盘上也有其他十几20个30个那么100个?无数个对应的程序也要在计算机里跑。
当我们有无数个软件都要同时在内存里加载被CPU执行的时候。那么,其中我们是不是就首先要想到一个东西什么东西呢?有如此之多的被加载进来的程序,每一个程序内存给你分配多少?在哪里给你分配?你的代码现在执行到哪里了?有没有被调度过?先执行哪一个?后执行哪一个?那么请。其中我们的有些程序执行完了怎么办?有的程序呢?其中它天然的可能调度的次数被CPU执行的次数太少了,然后我们现在要增加。对它的调度,那又怎么办?那么有的程序已经跑完了,我们要释放它的空间,那么怎么办?
上面的所有的问题。本质就是我们有太多加载进来的程序,那么操作系统。要不要?管理这些。操作系统既然是软硬件资源的管理者,那么内存也是你的资源。那么你也要管理内存,有这么多程序跑过来抢你内存的位置,那么你操作系统要不要管呢?包括这些被加载进来的程序,它在内存的什么位置放啊?那么什么时候该调度这个程序了?什么时候该执行这个程序了?有这么多,你先执行哪一个呢?假设你只有一个CPU。所以此时操作系统要不要管理这些加载进来的程序呢?
那它是怎么管理的呢?那么我总不能拿着一个个进程的二进制程序在那来回哪去的。
操作系统怎么管理的,感兴趣的可以看一下,我的这篇文章。
管理的方式就是:先描述后组织
我要管理这些进程,操作系统内首先要做的是把所有的进程。先描述起来,所以为了先描述每一个进程,所以我们的计算机操作系统内部为了描述进程,就有了一个叫做pcb的概念啊。
很多的操作系统教材里直接告诉你,有一个PCB。不过我想告诉大家聊我学到的pcb,在系统层面上先描述这个进程。怎么去描述呢?那么我们在Linux内核当中是用结构体struct task_struct{},那么这个结构我们被称之为叫做进程控制块。这个pcb不是硬件的pcb
操作系统为了管理进程呢,就需要给这里面填上,这里面包含了该进程的。好一个进程的所有属性 。
比如说这个进程,那么系统里有十几个进程。那么或者几百个进程。那么你怎么去标识某一个进程的唯一性呢?就好比在学校里面,校长为了管理在座的同学,每一名同学身上都有学号一样。那么,操作系统怎么管理这个进程呢?所以给每个进程都要有对应的进程的ID,那么包括呢?一个进程被运行,它要不要优先级呢啊?包括呢?一个进程在运行,要不要状态呢?包括一个进程要运行,要不要被调度?它的调度信息怎么办?一个进程在运行的时候,那么它对应的代码和数据在哪里。
所以呢,我们进程控制块儿里面保存的是我们进程被创建时的所有的属性。我虽然现在还没有给说讲任何一种属性,但是我心里要非常清楚了。
那么这里面它包含的这些进程属性,在你的曾经的可执行程序里有没有啊?答案是没有这个可乘程序里只有你的代码和数据逻辑。它没有任何的其他进程相关的属性,当加载进来之后,这是操作系统帮你做的。
好那么对我们来讲呢,我们就有一个叫做把进程要先描述再组织描述的话,每一个进程都是一个task_struct{}.
实际上它可以给我们创建一个PCB对象好,然后呢?那么紧接着有了之后呢完成初始化这里面的各种属性啊,进程的各种属性,把它填进来,那么包括呢?那么p1那么所指向的那么addr包括,比如说这个代码的地址。你自己的可执行程序加载到内存之后,代码和地址。我们就初始化完了一个叫做task结结构体,其中每一个进程都要做这个工作,
所以在系统里面。除了当你加载进程到内存里,操作系统给每一个可执行程序匹配一个进程控制块。说白了就是一哥task struct所对应的一个我们对应的结构体啊,而这个结构体对象或者结构体变量。然后呢,他们每一个呢,都指向自己的代码啊,都指向自己的代码来。所以每一个对应的进程都有一个竞争块儿,
拿着这个头,然后接下来呢,操作系统那么对于CPU来说。我要调度某一个进程,我要执行某个进程的代码,因为这里每一个PCB里面那么对应的是是每一个进程的所有的属性,所以呢,我要调度一个进程,意味着我要把比如说啊,我要找到优先级最高的进程。比如说优先级那么,假如说那么就是有三类优先级ABC a表示优先级最高的b表示次之c表示最低。所以呢,那么CPU它在那么要调动某个进程时就给操作系统说操作系统啊,能不能给我个进程?操作系统好。
所以呢,操作系统干什么呢?它就遍历所有的这个进程的PCB,注意便利,右边这里的可执行程序没有任何意义,它是遍历对应的进程的PCB。然后呢,找到优先级最高的某一个进程,把它的代码呢交到CPU里面。CPU就可以执行对应这个进程的代码了。
那么以后有一个进程,它想退出了怎么办呢?那么我们只需要去。确定这个PCB属性里面有没有一个进行的状态是死亡的,死亡了怎么办呢?操作系统遍历链表,把状态是死亡的这个节点找到。然后把它对应的这个代码数据释放掉,然后把PCB释放掉,此时这个进程也就被释放了。
所以我们有了这样的结构体,有了先描述再组织的理念。最后,我们得出一个结论,对进程进行管理就变成。对我们的进程那么对应的PCB进行相关的管理,不是对可执行程序做管理那么以后有一个进程,他想退出了怎么办呢?那么我们只需要去。确定这个PCB属性里面有没有一个进行的状态是死亡的,死亡了怎么办呢?操作系统遍历链表,把状态是死亡的这个节点找到。然后把它对应的这个代码数据释放掉,然后把PCB释放掉,此时这个进程也就被释放了,所以同学们,我们有了这样的结构体,有了先描述再组织的理念。最后,我们得出一个结论,所谓。好对进程进行管理就变成。对我们的进程那么对应的PCB进行相关的管理。
你系统里新增了个进程,对不对?加载到内存,加载进来新增一个竞争,把你的代码放进来,操作系统,同时也要给你这个竞争创建PCB。把属性往里面一填,填完之后把这个进程链入到链表里,此时我们就有个新进程了。
总结:进程 = 内核数据结构(task_struct)+ 进程对应的磁盘代码
所以你现在脑子里面瞬间就想起来了,操作系统是个软件,它早就加载到内存,就一直在运行着。当我们启动一个程序,把所谓的叫做磁盘上的程序加载到内存的时候。那么看起来好像就是这一个程序,到了内存里,但实际上操作系统为了管理这个进程,那么它要为该进程创建对应的PCB。也叫做进程控制块。
说白了就是先描述你,描述完之后再把所有的对应的创建完的结构体对象组织起来。所以对于进程的所有的管理,变成了对数据结构的增删查改,我觉得,这才是一个理解操作系统。最重要的理解理念。
也就是说我为什么描述一个管理一个进程的时候呢?我们总是会采用。PCB的方式来管理呢,为什么会存在这样的结构体呢啊?因为管理的核心理念是管理的核心思路。管理的管理的核心思路是对数据做管理,对数据做管理呢。
那么他必须得先拿到数据。可是拿到的数据没有规律,而且杂乱无章,另外数据量可能很大,所以我们需要对数据做归类,按照我们对应的那么面向对象的思路,把对应的被管理对象需要的属性值抽象出来。
然后呢?那么当我们加载到内存之后,操作系统为其创建对应的PCB的本质就是因为管理的理念叫做先描述再组织。操作系统对进程要素的管理,它就必须遵守曾经自己设计的那么管理的理念,先描述再组织,所以那么我们必须得有PCB啊。
程啊?那么,进程等于内核数据结构加进程?那么,对应的磁盘代码说白了就是把我的代码加载到内存,可不仅仅是只是把磁盘的代码拷贝到内存。操作系统为了管理这个进程,也要创建对应的管理数据结构,比如说PCB。
难道我说有就有了吗,一起看一下linux源代码。
我们搞清楚了,我们有了自己的一套理解,不仅仅有了一个对进程的概念的理解。你有了一套操,如何站在操作系统的视角去看待很多被管理对象?