进程概念:
1.程序在执行中
2.一个具有一定独立功能的程序在一个数据集合上的一次动态执行过程,是系统进行资源分配和调度的独立单位。
进程与程序的差别:
·进程----动态, 程序----静态
·进程----有生命周期,短暂的, 程序----相对长久的
·进程----具有并发性, 程序----没有
·进程是竞争计算机系统资源的基本单位,其并发性受到系统本身的制约
·不同进程可以包含同一程序,只要程序所对应的数据集不同
一个进程包括:
·Text section 文本段(代码段)-------程序代码
·program counter 程序计数器----------其值与处理器寄存器的内容共同表示当前活动
·Stack 栈------------------包括临时数据,如函数参数、返回地址和局部变量
·Heap 堆-------------------在进程运行期间动态分配的内存
·data section 数据段-------包括全局变量
下面是进程在内存中的状态:
进程的特征:
进程控制块(PCB),也称任务控制块:
作用:PCB用来保存程序运行期间的重要信息
·进程存在的唯一标识
·记录了OS所需的用于描述进程及控制进程所需的全部信息
·进程状态(process state):状态可包括新的(new)、就绪(ready)、运行(running)、等待(waiting)、终止(teminated)。
·程序计数器(program counter):表示进程要执行的下个指令的地址。
·CPU寄存器(CPU registers):根据计算机体系结构不同,寄存器的数量和类型也不同。
·CPU调度信息(CPU scheduling information):包括进程优先级、调度队列的指针和其他调度参数。
·内存管理信息(Memory-management information):根据操作系统所使用的内存系统,这类信息包括基址和界限寄存器的值、页表或段表。
·记账信息(Accounting information):包括CPU时间、实际使用时间、时间界限、记账数据、作业或进程数量等。
·I/O状态信息(I/O status information):这类信息包括分配给进程的I/O设备列表、打开的文件列表等。
CPU在进程间切换时用到了PCB:
当CPU切换到另一个进程时,系统需要保存老进程的状态,并且加载新进程的状态。
*进程状态图:
进程状态切换:
·就绪-->运行
-调度程序选择一个新的进程运行
·运行-->就绪
-运行进程用完了时间片
-运行进程被中断,因为一高优先级进程处于就绪状态
·运行-->等待
-OS尚未完成服务
-对一资源的访问尚不能进行
-初始化I/O且必须等待结果
-等待某一进程提供输入(IPC)
·等待-->就绪
-当所等待的事件发生时
并行和并发:
·并发是指两个或多个事件在同一时间间隔发生。并行是指在两个或多个事件在同一时刻发生。
·并发的关键是你有处理多个任务的能力,不一定要同时。
·并行的关键是你有同时处理多个任务的能力。
下面是知乎上的一个举例:
-你吃饭吃到一半,电话来了,你一直到吃完了以后才去接,这就说明你不支持并发也不支持并行。
-你吃饭吃到一半,电话来了,你停了下来接了电话,接完后继续吃饭,这说明你支持并发。
-你吃饭吃到一半,电话来了,你一边打电话一边吃饭,这说明你支持并行。
进程调度
1.调度队列
·进程进入系统时,会被加入到作业队列(Job queue)中。作业队列包括系统中所有进程。
·驻留在内存中就绪的、等待运行的进程保存在就绪队列(Ready queue)中。该队列常用链表来实现,其头结点包括指向链表的第一个和最后一个PCB块的指针。每个PCB包括一个指向就绪队列的下一个PCB的指针域。
·等待特定I/O设备的进程列表称为设备队列(Device queue)。每个设备都有自己的设备队列。
下面是就绪队列和各种设备队列:
2.调度程序
进程在其生命周期中会在各种调度队列之间迁移。为了调度,操作系统必须按某种方式从这些队列中选择进程。进程选择是由相应的调度程序(scheduler)来执行的。
·长期调度程序(作业调度程序):选择一个进程进入内存的就绪队列。---------------执行不频繁
·短期调度程序(CPU调度程序):从就绪队列中选择一个一个进程,并为之分配CPU。---执行频繁
·中期调度程序:将进程从内存(或从CPU竞争)中移出,从而降低多道程序设计的程度。之后,进程能被重新调入内存,并从中断处继续执行。这种方案称为交换。
下面是增加了中期调度的队列图:
*进程间通信:
很多时候我们需要提供环境以允许进程协作,这有许多理由,包括:信息共享、提高运算速度、模块化、方便等等。
而协作进程需要一种进程间通信机制(interprocess communication,IPC)来允许进程相互交换数据与信息。
进程间通信有两种基本模式:
·共享内存:建立起一块供协作进程共享的内存区域,进程通过向此共享区域读或写入数据来交换信息。
·消息传递:通过在协作进程间交换信息来实现通信。
下图为(a)、消息传递模式 (b)、共享内存模式
共享内存系统:
为说明协作进程这一概念,可研究一下生产者-消费者问题,这是协作进程的通用范例。生产者进程产生信息以供消费者进程消费。采用共享内存是解决生产者-消费者问题方法中的一种。为了允许生产者进程和消费者进程能够并发执行,必须要有一个缓冲区来被生产者填充并被消费者所使用。生产者和消费者必须同步,以免消费者消费一个没有生产出来的项。
可以使用两种缓冲:
无限缓冲对缓冲大小没有限制。消费者可能不得不等待新的项,但生产者总是产生新项。
有限缓冲假设缓冲大小固定。对于这种情况,如果缓冲为空,那么消费者必须等待;如果缓冲为满,那么生产者必须等待。
为更进一步了解进程共享内存如何使用有限缓冲。下面驻留在内存中的变量由生产者和消费者共享:
1 #define BUFFER_SIZE 10 2 3 typedef struct { 4 ... 5 }item; 6 7 item buffer[BUFFER_SIZE]; 8 int in = 0; 9 int out = 0;
共享缓冲是通过循环数组和两个逻辑指针来实现的:in和out。in指向缓冲中的下一个空位;out指向缓冲的第一个满位。
当in == out时,缓冲为空;当(in + 1) % BUFFER_SIZE == out时,缓冲为满。
下面是生产者进程代码,其中有一个局部变量nextProduced以存储所产生的新项:
1 item nextProduced; 2 3 while(true) { 4 //produce an item in nextProduced 5 while(((in + 1) % BUFFER_SIZE) == out) 6 ;//do nothing 7 buffer[in] = nextProduced; 8 in = (in + 1) % BUFFER_SIZE; 9 }
下面是消费者进程代码,其中有一个局部变量nextConsumed以存储所要使用的新项:
1 item nextConsumed; 2 3 while(true) { 4 while(in == out) 5 ;//do nothing 6 nextConsumed = buffer[out]; 7 out = (out + 1) % BUFFER_SIZE' 8 //consume the item in nextConsumed 9 }
这个例子没有解决生产者和消费者同时访问共享内存的问题,将在另外一篇文章上讨论在共享内存环境下协作进程如何有效实现同步。
消息传递系统:
消息传递提供一种机制以允许进程不必通过共享地址空间来实现通信和同步,这在分布式环境中特别有用。
消息传递工具至少提供两种操作:发送(消息)和接受(消息)。
下面是一些send()/receive()操作方法:
·直接或间接通信
·同步或异步通信
·自动或显式缓冲
1.命名
需要通信的进程必须有一个方法以相互引用。它们可使用直接通信或间接通信。
直接通信:需要通信的每个进程必须明确地命名通信的接受者或发送者。其原语send()和receive()定义如下:
·send(P,message):发送消息到进程P。
·receive(Q,message):接收来自进程Q的消息。
该方案的通信线路属性:
·在需要通信的每对进程之间自动建立线路。进程仅需知道相互通信的标识符。
·一个线路只与两个进程相关。
·每对进程之间只有一条线路。
上述的是直接通信中的对称寻址,即发送和接收进程必须命名对方以便通信;这个方案也可以变形为非对称寻址,即只要发送者命名接收者,而接收者不需要命名发送者,
对称和非对称寻址方案的缺点是限制了进程定义的模块化。改变进程名称可能必须坚持所有其他进程定义。
间接通信:通过邮箱或端口来发送和接收消息。邮箱可以抽象成一个对象,进程可以向其中存放信息,也可以从中删除信息。其原语send()和receive()定义如下:
·send(A,message):发送消息到邮箱A。
·receive(A,message):接收来自邮箱A的消息。
该方案的通信线路属性:
·只有在两个进程共享一个邮箱时,才能建立通信线路。
·一个线路可以与两个或更多地进程相关联。
·两个通信进程之间可有多个不同的线路,每个线路对应于一个邮箱。
2.同步
进程间的通信可以通过调用原语send()和receive()来进行。这些原语的实现有不同的设计选项。
消息传递可以是阻塞或非阻塞---也成为同步或异步。
·阻塞send:发送进程阻塞,直到消息被接收进程或邮箱所接收。
·非阻塞send:发送进程发送消息并再继续操作。
·阻塞receive:接收者阻塞,直有消息可用。
·非阻塞receive:接收者收到一个有效消息或空消息。
3.缓冲
不管通信是直接的还是间接的,通信进程所交换的消息都驻留在临时队列中。简单地讲,队列实现有三种方法:
·零流量:队列最大长度为0,因此线路中不能有任何消息处于等待。必须阻塞发送,直到接收者接收到消息。
·有限容量:若线路满,则必须阻塞发送直到队列中的空间可用为止。
·无限容量:从不阻塞发送者。
注:零流量情况称为没有缓冲的消息系统,其他情况称为自动缓冲。
此外,还有其他方式可进行进程之间的通信,如管道、socket等,将在另一篇文章介绍。