操作系统-进程

1 进程的概念

一个进程就是一个正在运行的程序。一个进程应该包含以下内容:
(1) 程序的代码,既然进程是一个正在运行的程序,自然需要程序的代码
(2) 程序的数据
(3) CPU寄存器的值,包括通用寄存器,程序计数器
(4) 堆(heap)是用来保存进程运行时动态分配的内存空间
(5) 栈(stack)有两个用途,1保存运行的上下文信息。2在函数调用时保存被调用函数的形参或者局部变量

(6) 进程所占用的一组系统资源,如打开的文件


假设有位科学家在女儿生日当天想做一个蛋糕送给女儿。他找了一本有关做蛋糕的食谱,按照上面的要求买了一些原料鸡蛋、面粉、糖等,然后边看食谱边做。科学家相当于CPU,做蛋糕犹如执行程序。食谱相当于代码,详细描述了做蛋糕整个过程。原料相当于输入数据。进程就是做蛋糕的整个过程。


在做蛋糕过程中食谱(代码)不会发生变化,但原料(数据)会发生变化。而程序=算法+数据,即食谱+原料。程序本身是没有意义的,即只有原来+食谱是不能吃的,程序要运行起来才有意义。

当这位科学家正忙活做蛋糕时,小儿子跑了进来说小手被蜜蜂叮了一口,科学家只能将做蛋糕的事情先放在一边,先去处理儿子的受伤。他做事有条有理,现在食谱上做了一些标记,把当前的状态信息记录下来,如看到食谱多少页,已经放了多少面粉、多少糖记录。这里所说的状态信息,其实就是刚才说的程序的运行上下文。他又去找了一个医疗手册,按照上面的步骤给儿子处理伤口,处理完伤口后又去厨房做蛋糕。科学家这个CPU从一个进程(做蛋糕)切换到另一个进程(医疗救护),每个进程执行的程序是不一样的,一个是食谱,一个是医疗手册。


2 进程的特性

动态性、独立性、并发性是进程的三大特性。

A 动态性

在程序运行的过程中,它的状态是在不断变化的。例如一个程序在运行过程中,它是一条指令接着一条指令执行,而每执行一条指令,CPU中那些通用寄存器的值也会发生变化,程序计数器(Program Counter)的值也在变化,每次都指向下一条即将执行的指令。另外堆和栈的内容也在不断变化,数据在不断进栈出栈,堆空间在不断分配和释放。总之变化无时无刻不在进行。

B 独立性

一个进程是一个独立的实体,是计算机系统资源的使用单位。每个进程都有"自己"的寄存器和内部状态,在它运行的时候独立于其他的进程。当然这个"自己"是带引号的,也就是说:在物理上,CPU中只存在一套寄存器,如PC寄存器只有一个,但是没有进程都有属于自己的逻辑上的PC。物理上的寄存器是真正的硬件寄存器。

C 并发性

对于单CPU的情况,从宏观上来看,每个进程是同时在系统中运行的,而实际上从微观上来看,在某一特定时刻,只有一个程序运行,换言之各个进程之间实际上是一个接一个顺序运行的。因为CPU是有一个,那么某一个时刻只能有一个进程去使用它。



3 进程的创建和终止

以下几类操作可以创建和终止线程。

A 创建进程

(1) 系统初始化会创建新的进程

(2) 当一个正在运行的进程中,若执行了创建进程的系统调用,那么也会创建新的进程

(3) 用户发出请求,创建一个进程

(4) 初始化一个批处理作业时,也会创建新的线程

从本质上来说在技术上只有一种创建新进程的方法,即在一个已经存在的进程中,通过系统调用来创建一个新的进程。如Linux中可以使用fork函数来创建新进程。windows中可以用createProcess函数来创建新进程。

B 进程终止

(1) 正常退出

(2) 错误退出

(3) 致命错误

(4) 被其他进程kill



4 进程的状态

一个进程并不是总是占用着CPU的,那么如何描述一个进程的当前状态呢?一般来说一个进程被创建开始,一直到它的生命结束为止,它只可能存在三个阶段:运行、就绪、阻塞。当然在具体实现中有的操作系统的状态个数可能不是三个。如可能把就绪和阻塞统称为暂停状态,或者是新增两个状态:创建和结束。但最核心的还是运行、就绪、阻塞。

A 运行状态

进程占用着CPU,并且在CPU上运行。显然处于这种状态的进程数量<=CPU的数目。若只有一个CPU那么任何时刻最多只能有一个进程处于运行状态。

B 就绪状态

进程已经具备了运行的条件,但由于CPU正忙着运行其他的进程,所以暂时不能运行。不过只要把CPU分给它,它就立刻可以运行。正所谓万事俱备只欠东风。

C 阻塞状态

进程因为某种事件的发生暂时不能运行的状态。例如它正等待某个输入输出的操作完成,或者它与其他线程之间存在同步关系,需要等待其他进程给它输入数据。这种情况下即使CPU已经空闲下来,这个进程还是不能运行。

D 状态切换

运行可转化为阻塞、就绪。

阻塞可转化为就绪。

就绪可转化为运行。


你的自行车坏了,需要推到修车师傅那里去修理。运行状态:若师傅很空闲立即给你修车。就绪状态:若师傅忙着修别的自行车,让你的自行车在旁边等待,师傅一有空就帮你修忙。阻塞状态:若你的自行车需要一个新坐垫,但是师傅没有这个坐垫,即使师傅空闲下来,也不能帮你修车。



5 进程控制块

上节中说是基本概念,那么在实际操作系统中,如何设计和实现进程的机制呢?首先就是要设计一个合理的数据结构用来描述进程的概念。这种结构就是进程控制块(Process Control Block,PCB)。系统为每个进程维护了一个PCB,用来保存与该进程有关的各种状态信息。PCB只是基本原理中的说法,对于一个真实的操作系统可能不叫PCB,比如Linux中叫做任务结构体(task struct)。示例如下
struct task_struct 
{
volatile long state;
pid_t pid;
unsigned long timestamp;
unsigned long rt_priority;
struct mm_struct *mm, *active_mm
}

前面讲过逻辑寄存器和物理寄存器的概念,物理寄存器只能有一份,但逻辑寄存器则是每个进程都有一份,逻辑寄存器是通过内存变量来实现的,那么这些存储的变量就对应着PCB的相应字段。


PCB是进程的唯一标识。每生成一个新的进程,就要为它创造一个PCB然后对其进行初始化。若要撤销一个进程时只要回收PCB即可。进程切换就可以通过操作PCB进行。



6 状态队列

对于一个分时操作系统而言,假设时间片是20ms这意味着1s内需要进行50次进程切换。另外有些进程处于就绪状态,有些进程处于阻塞状态,它们的阻塞原因又不尽相同。那么对于一个操作系统而言,采用什么样的方式把所有的进程的PCB组织起来,将会直接影响到对进程的管理效率。

操作系统采用的方法是维护一组状态队列。处于运行状态的进程构成运行队列,处于就绪状态的进程构成就绪队列,处于阻塞状态的队列处于阻塞队列。若一个进程从运行状态变为就绪状态,或者从阻塞状态变为就绪状态,就把它的PCB从一个状态队列脱离出来,加入到另外一个队列中。

本文内容摘录自清华大学出版社《操作系统》第二章节。


发布了535 篇原创文章 · 获赞 1162 · 访问量 450万+

猜你喜欢

转载自blog.csdn.net/woshixuye/article/details/53931303