目录
初识进程
一个程序要被执行,首先从磁盘预加载到内存,再由内存和CPU进行交互,之后再由内存缓存起来,由操作系统在合适的时间刷新到输出设备上。
程序要被执行就需要按照冯诺依曼体系结构和操作系统的规则去执行。
我们可以同时启动多个程序,那么每个程序一定会被预先加载到内存中,操作系统要对这些即将要被执行的可执行程序做管理,应当如何管理呢?----- 先描述,再组织
大致过程
首先,先将磁盘中的各个可执行程序预先加载到内存中,然后,操作系统要对这么多可执行程序做管理,用"先描述,再组织"方法,创建管理可执行程序的节点,每个节点指向自己对应的可执行程序,操作系统就可以通过节点去访问对应的可执行程序,假设使用链表这样的数据结构进行节点连接。此后,操作系统对这些可执行程序的管理就转化成了对这个链表的增删查改的管理工作。
PCB
我们将这个节点叫做进程控制块(PCB)。
每个可执行程序加载到内存中,内存无法识别这些可执行程序且要对其进行管理。所以操作系统都要为其创建一个PCB对象,将其连接在对应的数据结构中,从此以后,对可执行程序的管理就转化为了对PCB节点的数据结构的增删改查的工作。
进程
我们将内核的PCB对象和可执行程序整体称为进程。
进程=内核PCB对象+可执行程序
之后会了解到内核PCB对象其实是内核数据结构,本文先理解为PCB对象即可。
PCB对象属于操作系统内部的数据,PCB本来就是操作系统为了管理而创建出来的资源,本该就属于操作系统内部资源,用户也无法访问到PCB的信息,操作系统也不允许用户这样做。
但如果用户想要获取PCB中的信息,就要通过操作系统提供的系统调用接口。
从此之后,所有对进程的控制和操作,都只和进程的PCB有关,和进程的可执行程序无关(内存也不认识这)。之后操作系统可以将进程PCB放在特定的数据结构中去管理。
举个例子
比如,CPU现在要运行这些可执行程序了,就要管理对应的PCB对象,利用先描述再组织,形成一个管理PCB指针的节点,通过PCB指针找到PCB对象,再通过PCB对象找到对应的可执行程序,然后将其放到适合的数据结构中去,接着,让CPU按照管理好的内部含有PCB指针的节点的数据结构去依次运行调度即可。
几乎所有的指令/程序,运行起来都要变成进程。
PCB这个叫法是操作系统学科的叫法,Linux中,我们将PCB称为task_struct。
PCB内部属性
接下来我们来聊一聊PCB内部的属性
PCB内部大致了解一下
1.标识符
描述本进程的唯一标记,用来区别其他进程和使CPU知道此进程的功能。
2.状态
标记此进程,来判断此进程是执行状态、退出状态还是未开始状态。
3.优先级
给进程设置编号,按照编号的顺序被CPU调度执行
4.程序计数器
本质是PC指针或eip寄存器(在x86下),用来存储程序中即将被执行的下一条指令的地址
CPU的工作原理是
1、取指令
2、分析指令
3、执行指令
执行指令完成之后再去取指令,以此循环。
由于我们所编写的代码中的各种变量最终都会被计算机视为虚拟地址,再将虚拟地址通过映射的方式转化为物理地址。
PC指针/eip寄存器记录当前正在执行的指令的下一条指令的地址,来确定下一步该执行那一句指令。
程序设计语言中的选择、循环、判断、函数跳转等操作,本质都是修改了PC指针。
5.内存指针
就是PCB中指向对应可执行程序的指针。
6.上下文数据
进程执行时处理器的寄存器中的数据
7.I/O状态信息
I表示输入(对应读取权限),O表示输出(对应写入权限)。
即操作系统将对应文件的读/写权限暂时的交给特定指令。
比如,我们使用printf这个函数的时候,操作系统就赋予了这个指令在显示器文件上去写的权限,暂时的将显示器文件的写权限交给了printf指令。
8.记账信息
CPU在执行每个进程时,会对每个进程的执行时间进行记录,如果这个进程执行时间超过规定时间时,那么这个进程在下次应当被CPU执行调度的时候,操作系统就会跳过这个进程(不让CPU执行这个进程,即使这个进程的优先级高),优先先让CPU执行后面的执行时间短的进程,从而提高CPU工作效率。
所以,记账信息可以用历史的执行数据来决策后续的动作。