目录
什么是进程?
程序
如果要了解进程是什么,我们得从程序开始说起!
- 程序就是我们写的源代码进行编译和链接后形成的可执行程序,在Windows下就是以.exe为后缀的文件
程序与文件(硬件)
首先,从硬件的角度,也就是冯诺依曼体系结构我们可以了解到,一个数据从输入设备进入被运到CPU再到输出设备,在这个中间为了效率考虑所以才会有了一个设备,叫做内存,这些我在往期博客进行详细说过,感兴趣的可以看看: 冯诺依曼体系结构
冯诺依曼体系结构设计了一个中间件叫做内存,CPU不直接与外设打交道,而是与内存打交道,外设也不直接与CPU打交道,而是直接与内存打交道,而程序是一个文件,那么接下来的问题就是,文件放在哪?
文件肯定是放在硬盘上的,而硬盘是一个外设。
程序文件中是包含的一条条二进制的指令,这个是一个常识,那么既然是指令,所以这个指令需要经过CPU的运算吗?
答案也是肯定的
所以程序需要用到CPU所以它在运行的时候一定会被放在内存上,这是由冯诺依曼体系结构决定的
接下来的问题是:一个程序被运行放到内存上,难道内存上只放一个程序吗?换句话来说,难道同一个时间只能运行一个程序吗?
显然不是,依据我们的常识可以知道,可以有多个程序被放在内存,如果内存中只能放一个程序的话,那么当我们在运行QQ的时候,就不能同时运行音乐软件,但实际当中我们是可以的
而我们的操作系统的功能是要对下管理好软硬件资源,既然现在有多个程序可以同时在一片内存当中运行,所以现在操作系统肯定要对这些程序进行管理:什么是管理
PCB与task_struct
而操作系统怎么管理这些程序呢?
答案是:先描述、再组织
以Linux操作系统为例,Linux是用C语言写的,那么C语言当中我们如何描述一个对象呢?
实际上,如果我们学过C语言就会了解,struct也就是结构体类型可以对一个事物进行描述
就好比如果我们要用C语言进行描述一个人这种类型,我们可以用结构体包含它的各种各样的属性
(比如姓名、性别、年龄、身高、体重等等。。)
struct Person
{
const char* _name;
const char* _sex;
int _age;
//....
}
那么如果我们的Linux操作系统需要管理好这些程序,肯定要描述这些程序,Linux是用C语言写的,所以描述我们可以用到结构体类型,而描述在内存中的程序的结构体类型我们称为PCB
PCB(process-control-blco = 进程控制块)
PCB当中放着在内存中的程序的各种属性,我们现在可以粗力度的理解为PCB就是描述程序的
当然,PCB当中也一定会有可以找到对应程序的属性,这个属性字段我们称为内存指针字段,这个内存指针是指向PCB所对应的在内存中的程序的
当有了PCB以后,操作系统只需要查看PCB的属性字段就可以知道你这个PCB所对应的程序的属性,而不需要跑去看程序本身
所谓的PCB其实是放之四海而皆准,也就是Windows当中的描述在内存中的程序的结构体我们可以称为PCB,Linux的也可以
但如果具体到Linux操作系统,它的PCB具体实现命名为task_struct
现在,我们已经可以描述一个程序了,接下来我们需要聊聊如何组织的问题
所谓的组织,也就是当我们有了很多很多程序的PCB之后,如何管理好它们,换句话来说就是如果PCB需要删除,PCB需要增加、需要查找某个PCB,我们如何更方便的实现
其实也就是所谓的数据结构。
在Linux当中,我们把一个一个的task_struct看成是一个结点,task_struct中包含一个next指针,指向下一个task_struct,形成一个task_struct的链表,此时,当我们程序运行结束之后,从内存中放回硬盘,那么我们只需要对这个链表结点进行删除结点即可,如果我们有一个新的程序来到内存,创建好task_struct之后,我们把这个task_struct插入链表即可
此时操作系统就把对程序的管理变成了对程序所对应PCB对象的管理
进程
到这,我们也终于可以聊聊这个标题,即什么是进程?
所谓的进程,不是指的运行期间被放在内存的程序,也不是指的PCB(Linux:task_struct)
而是运行期间被放在内存的程序及其所对应的PCB所组成的一个整体我们称之为进程
当然,由于操作系统对PCB的管理是对数据结构的管理,所以我们可以更进一步得出如下结论:
进程 = 内核数据结构 + 可执行程序
在上述中,我们谈到了task_struct是描述程序的属性,这其实是比较粗浅的理解,其实它不仅仅包含程序的属性,其实它包含了进程的几乎所有属性
浅谈进程排队
在上述的内容中,我们了解到了,进程到底是什么,并且也了解到了PCB的概念以及操作系统如何管理PCB,接下来我们谈一谈所谓的进程排队
一个进程,如果需要调度CPU,那么CPU肯定只能被一个进程调度,因为CPU只有一个,哪怕它再快,也不能同时处理多个进程,所以操作系统会在内存中添加一个运行队列的概念
当一个进程需要调度CPU的时候,操作系统会把它所对应的PCB添加到运行队列中,我们就假设它是拷贝
若此时再有进程需要调度CPU,那么就需要在运行队列中排队,所以所谓的进程排队指的是进程的PCB去排队,而不是进程的可执行程序去排队
所以,我们也能看出,所有的对进程的控制和操作,都只和进程的PCB有关,和进程的可执行程序无关
现在,我们已经对进程有了一定的了解了,接下来我们将分两部分进行学习
- PCB内部中的属性信息
- PCB作为一个整体,如何被我们使用
简述进程属性
注意:进程属性非常非常多,我们无法全部学习,只能挑一部分比较重要的内容
在我们详细学习进程属性的之前,我们先要知道进程属性到底有哪些,做到心中有数
进程属性主要内容:
- 标识符:描述本进程的唯一标识符,用来区分其他进程
- 状态:任务状态,退出代码,退出信号等
- 优先级:相对于其他进程的优先级
优先级 :在之前的学习中,我们了解过进程排队,所谓的优先级就是进程排队时的前后顺序
- 程序计数器:程序中即将被执行的下一条指令的地址
程序计数器
关于程序计数器,我可以现在粗力度解释一下,接下来我要问一个问题
当你写了一个C代码之后,为什么计算机会知道你执行到第几行了呢?
实际上,在CPU内部存在着一个寄存器eip,这个寄存器也叫做pc指针或程序计数器或指令寄存器
当我们写代码的时候一行一行的语句,每一个语句都有它所对应的地址
而CPU能完成的工作主要是三个,首先取指令,取到指令以后分析指令,分析完指令之后执行指令,而当执行完指令之后就再去取指令,循环往复
但此时问题就来了,CPU去哪去取指令呢?
我们说过,cpu内部有一个pc指针,这个pc指针实际上存储的就是当前进程正在执行的指令的下一条指令的地址,当CPU需要取指令的时候就会从pc指针中取,并且更新pc指针,使它指向下一条语句
所以此时我们就了解到,所谓的循环、判断、函数跳转本质是修改pc指针
- 内存指针:包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针
对于内存指针,其实我们之前聊到过,当操作系统对进程进行管理的时候,管理的其实是进程的PCB,但PCB并不是我们需要执行的程序,为了帮助我们拿到进程所对应的可执行程序,所以才有了这个内存指针
- 上下文数据:进程执行时处理器的寄存器中的数据
- I /O状态信息:包含显示I/O请求,分配给进程的I/O设备和被进程使用的文件列表
- 记账信息:可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。
进程属性之进程标识符
所谓的进程标识符,其实正如它的名字一样,是用来标识一个进程的,并且这个进程标识符在操作系统中具有唯一性,也就是每一个