目录
2.1 前趋图和程序执行
2.1.1 前趋图
前趋图是一个有向无循环图,记为DAG(Directed Acyclic Graph),用于描述进程之间执行的前后关系。
例:具有九个结点的前趋图
前趋关系: P1→P2, P1→P3, P1→P4, P2→P5, P3→P5, P4→P6, P4→P7, P5→P8, P6→P8, P7→P9, P8→P9 ps:前驱图中不能存在循环关系。
2.1.2 程序的顺序执行及其特征
程序:源代码程序、目标代码程序、可执行程序
程序执行:编辑、编译、链接、执行
程序的结构:顺序结构、分支结构、循环结构
程序顺序执行的特征:
2.1.3 程序的并发执行及其特征
所谓程序的并发执行是指:若干个程序同时在系统中执行,这些程序的执行在时间上是重叠的,一个程序的执行尚未结束,另一个程序的执行已经开始。
一个程序段的多条语句的并发执行:
程序并发执行的特征:
间断性:由于资源共享和相互合作,并发执行的程序间形成了相互制约关系,导致程序的运行过程出现“执行—暂停—执行”的现象。
失去封闭性:程序在并发执行时,是多个程序共享系统中的资源,因此这些资源的状态将由多个程序来改变。
不可再现性:由失去封闭性导致。同样的初始条件,一个程序的多次重复执行,可得到不同的结果。
程序并发执行引发的问题:当输入的数据还未全部输入内存时,计算进程必须等待;多个执行程序共享系统资源,程序之间可能会互相影响,甚至影响输出结果;选择哪些、多少个程序进入内存执行?内存中的执行程序谁先执行,谁后执行?等等问题。
2.2 进程的描述
2.2.1 进程的定义和特征
进程的定义 :进程是程序在一个数据集合上运行的过程,它是系统进行资源分配和调度的一个独立单位。
进程同程序的比较:
进程是动态的,程序是静态的:程序是有序代码的集合;进程是程序的执行。通常进程不可在计算机之间迁移;而程序通常对应着文件、静态和可以复制。
进程是暂时的,程序是永久的:进程是一个状态变化的过程,是有一定生命期的;而程序可以作为一种软件资料长久保存。
进程与程序的组成不同:进程是由程序和数据、进程控制块三部分组成的。
进程与程序的对应关系:同一程序同时运行于若干个数据集合上,它将属于若干个不同的进程。也就是说同一程序可以对应多个进程;一个进程的执行也可以涉及到一个或几个程序(调用)。
进程的特征:
2.2.2 进程的基本状态及转换
进程的三种基本状态:
就绪状态:进程已获得除 CPU 以外的所有必要资源,只要得到 CPU,便可立即执行。
执行状态:进程已得到 CPU,其程序正在 CPU 上执行。
阻塞状态:正在执行的进程因某种事件(如 I/O 请求)的发生而暂时无法继续执行,只有等相应事件完成后,才能去竞争 CPU。
进程的五种状态转换模型:
2.2.3 挂起操作和进程状态的转换
引入挂起的进程七种状态转换模型:
引入挂起状态的原因:
使进程不能继续执行,即使挂起后的进程处于就绪状态,它也不能参与对 CPU 的竞争。因此,称被挂起的进程处于静止状态,相反,没被挂起的进程则处于活动状态。
“挂起”的实质:
终端用户的请求;父进程请求;负荷调节的需要;操作系统的需要。
2.2.4 进程管理中的数据结构
进程的组成:
进程控制块(Process Control Block, PCB )
进程控制块的作用是使一个在多道程序环境下不能独立运行的程序(含数据),成为一个能独立运行的基本单位,一个能与其它进程并发执行的进程。或者说,OS是根据PCB来对并发执行的进程进行控制和管理的。
进程与PCB是一一对应的;PCB应常驻内存。
进程控制块的组织方式:
a.单一队列方式
所有进程的PCB通过链表组成一个单一队列,适用于进程数目不多的系统。
b. 链接方式
相同状态的进程PCB组成一个链表,不同状态对应多个不同的链表。
c.索引方式
2.3 进程控制
2.3.0 基础补充
进程控制是进程管理中最基本的功能,它用于创建和撤消进程,并对进程在整个生命周期中各种状态之间的转换进行有效控制。
进程控制是由操作系统的内核通过原语来实现的。
原语:系统状态下执行的某些具有特定功能的程序段称为原语。 (原语的执行具有原子性,执行时不可分割)。
进程的控制主要包括:
创建进程、阻塞进程、唤醒进程、挂起进程、激活进程、终止进程、撤销进程等
2.3.1 进程的创建
进程图(Process Graph) :
用于描述一个进程的家族关系的有向树。
子进程可以继承父进程的所有资源,当子进程被撤消时,应将从父进程那里获得的资源归还给父进程;撤消父进程时也必须同时撤消其所有的子进程。
引起创建进程的原因:
(1) 用户登录 (2) 作业调度 (3) 提供服务:由系统内核创建新进程 (4) 应用请求:由请求的应用程序自行创建新进程
创建新进程通过进程创建原语creat()来完成。进程创建原语的主要任务是进程创建控制块 PCB。
进程的创建过程(Creation of Progress)
(1) 申请空白PCB
(2) 为新进程分配资源
(3) 初始化进程控制块
(4) 将新进程插入就绪队列
2.3.2 进程的终止
终止流程–OS通过调用进程终止原语完成进程的终止。
进程的终止过程:
(1) 查找对应的PCB
(2) 终止该进程及子孙进程
(3) 释放资源
(4) 释放PCB
通过进程终止原语来终止进程。终止进程的实质是收回 PCB。
2.3.3 进程的阻塞与唤醒
进程的阻塞
当正在执行的进程需要等待某种事件的完成或本身无新工作可做时,应调用阻塞原语将自己从执行状态转换成阻塞状态。
进程阻塞是进程的一种主动行为。通过阻塞原语block()来完成。
引发的事件:
请求系统服务得不到满足时:如问系统请求打印。
启动某种操作而需同步时:如该操作和请求该操作的进程需同步运行(即非异步操作)。
新数据尚未到达:如进程A写,进程B读,则A未写完,B不能读。
无新工作可做
进程的唤醒:
-
当阻塞进程所等待的事件完成时,应调用唤醒原语将该进程的状态从阻塞状态转换成就绪状态。通过唤醒原语wakeup()来完成。
处于阻塞状态的进程是绝不可能叫醒自己的,必须由它的合作进程用唤醒原语唤醒它。
2.3.4 进程的挂起与激活
进程的挂起:
当出现了引起进程挂起的事件时,用户请求将自己挂起,或者父进程请求挂起自己的子进程。系统通过挂起原语suspend()将指定进程挂起。
挂起具体的执行过程:
(1)检查被挂起进程的状态,如果处于活动就绪状态,就将它改为静止就绪;如果处于活动阻塞,则改为静止阻塞。
(2)将 PCB 复制到指定的内存区域供用户或父进程考查。若挂起前进程正在执行,则转调度程序重新进行进程调度。
进程的激活:
当发生激活事件后,系统利用激活原语Active( )将指定进程激活。
激活具体的操作过程是:
(1)若进程处于静止阻塞状态,则将它转换成活动阻塞状态,否则将它转换成活动就绪状态。
(2)若进程转换成活动就绪状态,而系统又采用抢占调度策略,则应检查该进程是否有权抢占 CPU,若有则应进行进程调度。
2.4 进程通信
2.4.1 进程通信的类型
进程之间互相交换信息的工作称为进程通信。
§低级通信:归结为进程之间的互斥和同步,一般只传送少量信息(信号量)。缺点:效率低,通信对用户不透明。§高级通信:能够高效传输大量数量数据的通信方式。又分为三类:共享存储器系统、消息传递系统、管道通信系统。
1. 共享存储器系统
相互通讯的进程通过共享数据结构和共享存储区进行通讯,可进一步分为:
基于共享数据结构的通信方式(效率低)进程之间通过某种数据结构,如缓冲池进行通信,属于低级通信方式。如生产者-消费者问题中的有界缓冲区。
基于共享存储区的通信方式(高级)为了传送大量信息,在存储器中划出一块共享存储区,诸进程可通过对共享存储区进行读或写来实现通信,属高级通信方式。
2. 消息传递系统
消息传递系统的分类:
(1)直接通信方式
①对称寻址方式 ②非对称寻址方式
(2)间接通信方式
进程间发送或接收消息通过信箱进行,消息可被理解成信件。也称信箱通信。
3. 管道(Pipe)通信系统
§所谓管道,是指用于连接一个读进程和一个写进程以实现它们之间通信的一个共享文件,又称pipe文件。§ 发送进程以字符流形式把大量数据送入管道,接收进程从管道中接收数据,所以叫管道通信。§ 管道的实质是一个共享文件,基本上可借助于文件系统的机制实现,包括(管道)文件的创建、打开、关闭和读写。
管道通信必须提供三方面的协调能力:
§互斥:进程对通信机构的使用应该互斥,一个进程正在使用某个管道写入或读出数据时,另一个进程就必须等待。§ 同步:管道长度有限,发送信息和接收信息之间要实现正确的同步关系。当写进程把一定数量的数据写入pipe,就去睡眠等待,直到读进程取走数据后,把它唤醒。§ 确定对方是否存在:发送者和接收者双方必须能够知道对方是否存在,如果对方已经不存在,就没有必要再发送信息。
2.4.2 消息缓冲队列通信机制
消息缓冲队列通信机制通过内存中公用的消息缓冲区进行进程通信,属于直接通信方式。发送进程利用send原语将消息直接发送给接收进程;接收进程利用receive原语接收消息。
1. 消息缓冲队列通信机制中的数据结构
(1)消息缓冲区的数据结构
typedef struct message_buffer{
int sender; //发送者ID;
int size; //消息长度;
char *text; //消息正文;
struct message_buffer *next; //消息队列指针;
}
(2)PCB中有关通信的数据项
typedef struct processcontrol_block{
…
struct message_buffer *mq; //消息队列首指针;
semaphore mutex; //消息队列互斥信号量;
semaphore sm; //消息队列资源信号量;
…
}PCB;
2. 用P、V操作来实现Send原语
void send(receiver, a)
{
getbuf(a.size,i); //根据a.size申请缓冲区i;
i.sender=a.sender;
i.size=a.size;
copy(i.text, a.text);
i.next=0;
getid(PCB set, receiver.j);
wait(j.mutex);
insert(&j.mq, i); //将消息缓冲区插入消息队列;
signal(j.mutex);
signal(j.sm);
}
3. 用wait、signal操作来实现Receive原语
void receive(b)
{
j=internal name;//j为接收进程内部的标识符;
wait(j.sm);
wait(j.mutex);
remove(j.mq, i);
signal(j.mutex);
b.sender:=i.sender;
b.size:=i.size;
b.text:=i.text;
releasebuf(i);//将消息缓冲 i 归还给系统;
}
2.5 线程
2.5.1 线程的基本概念
操作系统中引入进程的目的,是为了使多个程序能并发执行,以提高资源利用率和系统吞吐量,那么,在操作系统中再引入线程,则是为了减少程序在并发执行时所付出的时空开销,使OS具有更好的并发性。进程在资源分配发挥作用,线程负责处理机调度。
线程是进程中的一个实体,是被系统独立调度和分派的基本单位。如下图所示:
2.5.2 线程与进程的比较
线程又称为轻型进程(Light-Weight Process)或进程元,传统进程称为重型进程(Heavy-Weight Process)。
2.5.3 线程的状态与线程控制块
(1) 线程运行的三个状态
与传统的进程一样,在各线程之间也存在着共享资源和相互合作的制约关系,致使线程在运行时也具有间断性。相应地,线程在运行时也具有下述三种基本状态:
1) 执行状态,表示线程已获得处理机而正在运行;
2) 就绪状态,指线程已具备了各种执行条件,只须再获得CPU便可立即执行;
3) 阻塞状态,指线程在执行中因某事件受阻而处于暂停状态
线程状态转换同进程。
(2) 线程控制块TCB
如同每个进程有一个进程控制块(PCB)一样,系统也为每个线程配置了一个线程控制块TCB,将所有用于控制和管理线程的信息记录在线程控制块中。
(3) 多线程OS中的进程属性
通常在多线程OS中的进程都包含了多个线程,并为它们提供资源。OS支持在一个进程中的多个线程能并发执行,但此时的进程就不再作为一个执行的实体。多线程OS中的进程有以下属性:
1) 进程是一个可拥有资源的基本单位
2) 多个线程可并发执行
3) 进程已不是可执行的实体
2.5.4 线程的实现
1)内核支持线程
2)用户级线程
3)组合方式