操作系统复习第二章:进程描述与控制

文章目录

    • 2.1前趋图和程序执行
        • 前趋图(DAG):
        • 程序的顺序执行:
        • 程序的并发执行:
    • 2.2进程的描述
        • 进程的定义:
        • 进程的基本状态及其转换
    • 2.3进程控制
        • 操作系统内核:
        • 进程的创建:
        • 进程的终止:
        • 进程的阻塞与唤醒
        • 进程的挂起与激活
    • 2.4进程同步
        • 两种形式的制约关系:
        • 实现临界区互斥的基本方法:
        • 信号量机制:
          • 整型信号量
          • 记录性信号量
          • AND型信号量
          • 信号量集
          • 利用信号量实现进程同步
          • 利用信号量实现进程互斥
          • 利用信号量实现前趋关系
        • 管程机制:
    • 2.5经典的进程同步问题
        • 生产者 - 消费者问题
        • 哲学家进餐问题
        • 读者-写者问题
    • 2.6进程通信
        • 进程通信的类型
          • 共享存储器系统
          • 管道通信系统
          • 消息传递系统
          • 客户机-服务器系统
    • 2.7线程的基本概念
    • 习题

2.1前趋图和程序执行

前趋图(DAG):

即一个有向无循环图,用于描述进程之间执行的先后顺序。

初始结点:指没有前驱的结点。
终止节点:没有后继的结点。

注意:前趋图中不允许有循环,否则必然存在不可能实现的前趋关系!

程序的顺序执行:

通常,一个程序由若干个程序段组成,每一个程序段完成特定的功能,它们在执行时都需要按照某种先后次序顺序执行,仅当前一程序段执行完之后,才执行后一程序段。

程序顺序执行的特征

  1. 顺序性(程序严格按照规定的顺序执行)
  2. 封闭性(程序运行时独占全机资源,程序一旦开始执行,其执行结果不受外界因素影响)
  3. 可再现性(程序执行和初始条件相同,则最终都可获得相同结果)

程序的并发执行:

指两个或多个程序或程序段在同一时间间隔内执行。

只有不存在前趋关系的程序之间才有可能并发执行,否则无法并发执行!
如图:
操作系统复习第二章:进程描述与控制_第1张图片
图中仅S1与S2可以并发执行!

程序并发执行的特征

  1. 间断性 (程序并发执行时,由于共享系统资源,致使其形成相互制约关系,相互制约导致“执行-暂停-执行”,这种间断性的活动规律)
  2. 失去封闭性(多个程序并发执行,则系统中各种资源将为他们所共享,一个程序的执行受到其他程序的影响)
  3. 不可再现性(由于失去封闭性,也导致失去可再现性)

2.2进程的描述

为什么要引入进程?
答:在多道程序环境下,程序的并发执行破坏了程序的封闭性和可再现性,使得程序和计算不再一一对应,程序活动不再处于一个封闭系统中,程序的运行出现了许多新的特征。在这种情况下,程序这种静态概念已经不能如实地反映程序活动的这些特征,为此引入了一个新的概念—-进程。

什么是进程控制块(PCB)?
进程控制块是一个专门的数据结构,目的是使并发执行的每个程序都能独立的运行。
系统利用PCB来描述进程的基本情况和活动过程,进而控制和管理进程。

进程实体(进程映像):
由程序段、相关数据段、PCB三部分组成。

一般情况下。进程实体简称为进程,

进程的定义:

  • 进程是程序的一次执行。
  • 进程是一个程序及其数据在处理机上顺序执行时所发生的活动。
  • 进程是具有独立功能的程序在一个数据集合上运行的过程,它是系统进行资源分配和调度的一个独立的单位。
  • 进程是进程实体的运行过程,是系统进行资源分配和调度的一个独立单位。

进程的特征:

  1. 动态性(进程实质是进程实体的执行过程,它由创建而产生,由调度而执行。由撤销而消亡)
  2. 并发性(各个进程实体间能并发执行,无PCB的程序不能并发执行)
  3. 独立性(进程实体是一个能独立运行,独立获得资源,和独立接受调度的基本单位)
  4. 异步性(进程按各自独立的、不可预知的速度向前推进)

进程的基本状态及其转换

进程的三种基本状态:

  1. 就绪态(Ready)进程已经分配到除了CPU之外的所有必备资源,只要在获得CPU,就能立即执行。如果系统中有许多就绪状态的进程,通常按照一定的策略排成一个队列,称为就绪队列)
  2. 执行态(Running)进程已经获得CPU,其程序正在执行的状态
  3. 阻塞态(Block)指正在执行的进程由于发生某事件(如I/O请求,申请缓冲区失败)暂时无法继续执行的状态。通常系统把阻塞进程排成一个队列,称为阻塞队列。(阻塞态又称等待态、睡眠态、封锁态)

进程基本状态的转换:
操作系统复习第二章:进程描述与控制_第2张图片
操作系统复习第二章:进程描述与控制_第3张图片

创建状态和终止状态

如果系统资源不能得到满足,创建工作未完成,则把此时进程所处的状态称为创建状态。

进程进入终止状态,则不再执行。

进程管理中的数据结构:

为了便于对计算机中的各类资源(包括硬件和信息)的使用和管理,OS将它们抽象为相应的各种数据结构,以及提供一组对资源进行操作的命令,用户可利用这些数据结构及操作命令来执行相关的操作,而无需关心其实现的具体细节。

在计算机系统中,对于每个资源和每个进程都设置了一个数据结构,用于表征其实体,
称之为资源信息表或进程信息表,其中包含了资源或进程的标识、描述、状态等信息。

OS管理的数据结构一般有四种:内存表、设备表、文件表、进程表(PCB)

操作系统复习第二章:进程描述与控制_第4张图片

进程控制块中的信息:

  1. 进程标识符(用于唯一标识一个进程,分为外部标识符和内部标识符)
  2. 处理机状态
  3. 进程调度信息
  4. 进程控制信息

2.3进程控制

进程控制是进程管理最基本的功能,主要包括:

  • 创建新进程
  • 终止已完成的进程
  • 将因发生异常情况而无法运行的进程置于阻塞状态
  • 负责进程运行中的状态转换等功能

进程控制一般是通过OS内核中的原语来实现的。

操作系统内核:

为了防止OS本身及其关键数据遭受到应用程序有意或者无意的破坏,通常将处理机的执行状态分为系统态和用户态两种:

① 系统态 (又称为管态、内核态)
具有较高的特权,能执行一切指令,访问所有寄存器和存储区,传统的OS都在系统态运行。
② 用户态 (目态)
具有较低特权的执行状态,仅能执行规定的指令,访问指定的寄存器和存储区。

一般应用程序仅能在用户态运行,这样可以防止应用程序对OS的破坏。

支撑功能:

  • 中断处理
  • 时钟管理
  • 原语操作

注:原语是指由若干条指令组成,用于完成一定功能的一个过程。
(原语在执行过程中不允许被阻断)

资源管理功能

  • 进程管理(如进程的调度与分派,进程的创建与撤销等)
  • 存储器管理(地址转换,内存分配与回收的功能,以及实现内存保护与对换功能等)
  • 设备管理(各类设备驱动程序的管理,缓和CPU与I/O速度不匹配的矛盾的缓冲管理等)

进程的创建:

通常把创建进程的进程称为父进程,被创建的进程称为子进程。

引起创建进程的事件:

  1. 用户登录
  2. 作业调度
  3. 提供服务
  4. 应用请求

进程的创建:

创建原语(Create)

  1. 申请空白PCB,为新进程申请获得唯一数字标识符,并从PCB集合中索取一个空白PCB。
  2. 为新进程分配其运行所需的资源,包括各种物理和逻辑资源。
  3. 初始化进程控制块。
  4. 如果进程就绪队列能接纳新进程,便将新进程插入就绪队列。

进程的终止:

引起进程终止的事件:

  1. 正常结束
  2. 异常结束
  3. 外界干预

进程的终止过程:

  1. 根据被终止进程的标识符,从PCB集合中检索出该进程的PCB,从中读出该进程的状态。
  2. 若被终止进程正处于执行状态,应立即终止该进程的执行,并置调度标识为真,用于指示该进程终止后重新进行调度。
  3. 若该进程还有子进程,还应终止它的所有子进程,以防子进程成为不可控程序。
  4. 将被终止进程所拥有的全部进程,或者将他们归还给父进程,或者归还给系统。
  5. 将被终止进程的PCB从所在队列中移除,等待其他程序来收集信息。

进程的阻塞与唤醒

引起进程阻塞或被唤醒条件:
(参照上面进程转换图)

  1. 向系统请求共享资源失败。
  2. 等待某种操作的完成。
  3. 新数据尚未到达。
  4. 等待新任务的到达。

进程阻塞:

正在执行的进程,如果发生上述某事件,进程便通过调用阻塞原语Block,将自己阻塞起来。
阻塞是进程自身的一种主动行为!

进程唤醒:

当被阻塞进程所期待的事件发生时,比如它所启动的I/O操作已完成,或其所期待的数据已经到达,则由有关进程(比如提供数据的进程)调用唤醒原语wakeup,将等待该事件的进程唤醒。

注意:block原语和wakeup原语必须成对使用。

进程的挂起与激活

挂起操作:
为了系统和用户观察、分析进程的需要,由此引入挂起操作。
当该操作作用于某个进程时,该进程将被挂起,意味着此时进程处于静止状态。

挂起原语(Suspend)
激活原语(Active)

2.4进程同步

为什么要引入进程同步的概念?
答:在多道程序环境下,进程是并发执行的,不同进程之间存在着不同的相互制约关系。为了协调进程之间的相互制约关系,引入了进程同步的概念。

进程同步机制的主要任务:
对多个相关进程在执行次序上进行协调,使并发执行的诸进程之间能够按照一定的规则(或时序)共享系统资源,并能很好的相互合作,从而使程序的执行具有可再现性。

两种形式的制约关系:

① 间接相互制约关系(互斥)

当一个进程进入临界区使用临界资源时,另一个进程必须等待,当占用临界资源的进程退出临界区后,另一进程才允许去访问此临界资源。

② 直接相互制约关系 (同步)

指为完成某种任务而建立的两个或多个进程,这些进程因为需要在某些位置上协调它们的工作次序而等待、传递信息所产生的制约关系。进程间的直接制约关系源于它们之间的相互合作。

临界资源:一次仅允许一个进程使用的资源。如打印机、磁带机。
临界区:在每个进程中访问临界资源的那段代码称为临界区。

为禁止两个进程同时进入临界区,同步机制应遵循以下准则:
① 空闲让进。临界区空闲时,可以允许一个请求进入临界区的进程立即进入临界区。
② 忙则等待。当已有进程进入临界区时,其他试图进入临界区的进程必须等待。
③ 有限等待。对请求访问的进程,应保证能在有限时间内进入临界区。
④ 让权等待。当进程不能进入临界区时,应立即释放处理器,防止进程忙等待。

实现临界区互斥的基本方法:

软件实现方法:

  1. 单标志法。
  2. 双标志法先检查。
  3. 双标志法后检查。
  4. Peterson’s Alogrithm。

硬件实现方法:

  1. 关中断(实现互斥最简单方法之一)。
  2. 利用 Test-and-Set指令实现互斥。
  3. 利用 Swap 指令实现进程互斥。

信号量机制:

1965年荷兰学者Dijkstra提出了信号量机制(Semaphores)。信号量机制是一种功能较强的机制,可用来解决互斥与同步问题,它只能被两个标准的原语 wait(S) 和 signal(S) 访问,也可记为“Р操作”和“V操作”。

原语:是指完成某种功能且不被分割、不被中断执行的操作序列,通常可由硬件来实现。

整型信号量

整形信号量被定义为一个 表示资源数目的整型量S, wait 和signal操作可以描述为:

wait(S){
while(S<=0);
S--;
}

signal(S){
S++;
}

在整型信号量机制中的 wait 操作,只要信号量S≤0,就会不断地测试。因此,该机制并未遵循“让权等待”的准则,而是使进程处于“忙等”的状态。

记录性信号量

操作系统复习第二章:进程描述与控制_第5张图片

AND型信号量

AND同步机制的基本思想是:
将进程在整个运行过程中需要的所有资源,一次性全部地分配给进程,待进程使用完后再一起释放。只要尚有一个资源未能分配给进程,其它所有可能为之分配的资源也不分配给它。
亦即,对若干个临界资源的分配采取原子操作方式:要么把它所请求的资源全部分配到进程,要么一个也不分配。由死锁理论可知,这样就可避免死锁情况的发生。

信号量集

操作系统复习第二章:进程描述与控制_第6张图片

利用信号量实现进程同步

设S为实现进程 P1,P2 同步的公共信号量,初值为 0。进程 P2 中的语句 y 要使用进程 P1 中语句 x 的运行结果,所以只有当语句 x 执行完成之后语句 y才可以执行。其实现进程同步的算法如下:
【wait(S) 相当于 P(S),signal(S) 相当于V(S) 】

semaphore S=0;
P1(){
x;
signal(S);  //语句x已完成 ,S=1
...
}

P2(){
...
wait(S);  //检查语句x是否完成,
y;
...
}


若 P2 先执行到 P(S) 时,S 为 0,执行 Р 操作会把进程 P2 阻塞,并放入阻塞队列;当进程 P1 中的 x 执行完后,执行V操作,把 P2 从阻塞队列中放回就绪队列,当 P2 得到处理机时,就得以继续执行。

利用信号量实现进程互斥

为使多个进程能互斥的访问某临界资源, 设置一个互斥信号量mutex, 赋初值=1,然后将各进程访问该资源的临界区CS放在 wait(mutex) 和 signal(mutex) 之间即可。

设mutex=1,取值范围为(-1,0,1)。
当mutex = 1时,表示两个进程皆未进入需要互斥的临界区;
当mutex =0时,表示有一个进程进入临界区运行,另外一个必须等待,挂入阻塞队列;
当mutex =-1时,表示有一个进程正在临界区运行,另外一个进程因等待而阻塞在信号量队列中,需要被当前已在临界区运行的进程退出时唤醒。

semaphore mutex = 1;
PA(){
    while(1){
        wait(mutex);  //准备访问临界资源,P操作 加锁
        临界区
        signal(mutex)  //访问结束 V操作 解锁
        剩余区
    }
    
}
PB(){
    while(1){
        wait(mutex);   //准备访问临界资源,P操作 加锁
        临界区
        signal(mutex)   //访问结束 V操作 解锁
        剩余区
    }
}

总结一下PV操作在同步互斥中的应用:

  • 在同步问题中,若某个行为要用到某种资源,则在这个行为前面Р这种资源一下;若某个行为会提供某种资源,则在这个行为后面V这种资源一下。
  • 在互斥问题中,P,V操作要紧夹使用互斥资源的那个。
利用信号量实现前趋关系

操作系统复习第二章:进程描述与控制_第7张图片

操作系统复习第二章:进程描述与控制_第8张图片

管程机制:

为什么引入管程?
虽然信号量机制是一种既方便、又有效的进程同步机制,但每个要访问临界资源的进程都必须自备同步操作 wait(S)和 signal(S)。这就使大量的同步操作分散在各个进程中。这不仅给系统的管理带来了麻烦,而且还会因同步操作的使用不当而导致系统死锁。这样,在解决上述问题的过程中,便产生了一种新的进程同步工具—─管程(Monitors)。

管程实现:
利用共享数据结构抽象地表示系统中的共享资源,而把对该数据结构实施的操作定义为一组过程。进程对共享资源的申请、释放等操作,都通过这组过程来实现,这组过程还可以根据资源情况,或接受或阻塞进程的访问,确保每次仅有一个进程使用共享资源,这样就可以统一管理对共享资源的所有访问,实现进程互斥。

这个代表共享资源的数据结构,以及由对该共享数据结构实施操作的一组过程所组成的资源管理程序,称为管程(monitor )。

管程定义了一个数据结构和能为并发进程所执行(在该数据结构上)的一组操作,这组操作能同步进程和改变管程中的数据。

由上述定义可知,管程由4部分组成:
①管程的名称;
②局部于管程内部的共享数据结构说明;
③对该数据结构进行操作的一组过程(或函数);
④对局部于管程内部的共享数据设置初始值的语句。

2.5经典的进程同步问题

生产者 - 消费者问题

问题描述: 一组生产者进程和一组消费者进程共享一个初始为空、大小为n的缓冲区,只有缓冲区没满时,生产者才能把产品放入缓冲区,否则必须等待;只有缓冲区不空时,消费者才能从中取出产品,否则必须等待。由于缓冲区是临界资源,它只允许一个生产者放入产品,或一个消费者从中取出产品。

生产者-消费者问题是相互合作的进程关系的一种抽象,例如,在输入时,输入进程是生产者,计算进程是消费者;而在输出时,则计算进程是生产者,而打印进程是消费者。

利用记录型信号量解决生产者-消费者问题

信号量设置:

  • 互斥信号量 mutex,实现各进程对缓冲池的互斥访问,初值为1;
  • 信号量 full 用于记录当前缓冲池中的“满”缓冲区数,初值为0。
  • 信号量empty用于记录当前缓冲池中的“空”缓冲区数,初值为n。

算法描述如下:

int in=0, out=0;
item buffer[n]; //缓冲池buffer,有n个缓冲区 

semaphore mutex=1, empty=n, full=0;

void producer(){
	
	do{
		producer an item nextp;
		...
		wait(empty);  //判断是否有空闲缓冲区,有则继续往下执行 empty-1,否则先将自己阻塞

		wait(mutex); // 上锁 申请缓冲区资源
		buffer[in]=nextp;  //将产品放入一个缓冲区 
		in=(in+1)%n;  //输入指针+1 
		signal(mutex); //解锁 释放缓冲区资源
		signal(full); // 满缓冲区数+1 
	}while(true);
	
} 

void consumer(){
	
	do{
		wait(full);  //判断是否有满缓冲区,有则继续往下执行 full减一,否则先将自己阻塞
		wait(mutex);   //上锁 申请缓冲区资源
		nextc=buffer[out];  //取产品 
		out=(out+1)%n;  //输出指针+1 
		signal(mutex);  //解锁 释放缓冲区资源
		signal(empty);  // 空缓冲区数+1 
		consumer the item in nextc;
		...
	}while(true);
	
} 

void main(){
	
	cobegin
	//并发执行 
		producer(); consumer();
	coend 
}

/*in=out: 缓冲池空
(in+1)%n=out: 缓冲池满
*/

利用 AND 信号量解决生产者-消费者问题

  • 用Swait(empty,mutex)来代替wait(empty)和 wait(mutex);
  • 用 Ssignal(mutex, full)来代替signal(mutex)和signal(full);
  • 用Swait(full,mutex)代替 wait(full)和 wait(mutex);
  • 用Ssignal(mutex,empty)代替Signal(mutex)和 Signal(empty)。

算法描述如下:

int in=0, out=0;
item buffer[n]; //缓冲池buffer,有n个缓冲区 

semaphore mutex=1, empty=n, full=0;

void producer(){
	
	do{
		producer an item nextp;
		...
		Swait(empty,mutex);
		buffer[in]=nextp;  //将产品放入一个缓冲区 
		in=(in+1)%n;  //输入指针+1 
		Ssignal(mutex,full); 
	}while(true);
	
} 

void consumer(){
	
	do{
		Swait(full,mutex);  
		nextc=buffer[out];  //取产品 
		out=(out+1)%n;  //输出指针+1 
		Ssignal(mutex,empty);  //解锁 释放缓冲区资源
		consumer the item in nextc;
		...
	}while(true);
	
} 

void main(){
	
	cobegin
	//并发执行 
		producer(); consumer();
	coend 
}


利用 管程 解决生产者-消费者问题:

首先建立一个管程procducerconsumer,其中包括两个过程:
(1) put(x)过程。生产者利用该过程将自己生产的产品投放到缓冲池中,并用整型变量count来表示在缓冲池中已有的产品数目,当count≥N时,表示缓冲池已满,生产者须等待。
(2) get(x)过程。消费者利用该过程从缓冲池中取出一个产品,当count≤0时,表示缓冲池中已无可取用的产品,消费者应等待。

对于条件变量notfull和notempty,分别有两个过程cwait和 csignal对它们进行操作:
(1) cwait(condition)过程:当管程被一个进程占用时,其他进程调用该过程时阻塞,并挂在条件condition的队列上。
(2) csignal(condition)过程:唤醒在cwait执行后阻塞在条件condition队列上的进程,如果这样的进程不止一个,则选择其中一个实施唤醒操作;如果队列为空,则无操作而返回。

算法描述如下:

Monitor procducerconsumer {
//对管程的定义
	item buffer[N]; //缓冲池
	int in, out;
	condition notfull, notempty; //条件变量
	int count; //缓冲池中已有产品数量
	public:
	void put(item x) {
	//放产品
		if (count>=N) cwait(notfull);
		buffer[in] = x;
		in = (in+1) % N;
		count++;
		csignal(notempty);
	}

	void get(item x){
	//取产品
		if (count<=O) cwait(notempty);
		x = buffer[out];
		out = (out+1) % N;
		count--;
		csignal(notfull);
	}

	{in=O;out=O;count=O;}
	
}PC;

void producer() {
	item x;
	while(TRUE){
		...
		produce an item in nextp;
		PC.put(x);
	}
}

void consumer() {
	item x;
	while(TRUE) {
		PC.get(x);
		consume the item in nextc;
		...
	}
}

void main() {
	cobegin
	proceducer();consumer();
	coend
}

哲学家进餐问题

问题描述:
有五个哲学家共用一张圆桌,分别坐在周围的五张椅子上,在圆桌上有五个碗和五只筷子,他们的生活方式是交替地进行思考和进餐。平时,一个哲学家进行思考,饥饿时便试图取用其左右最靠近他的筷子,只有在他拿到两只筷子时才能进餐。进餐毕,放下筷子继续思考。
操作系统复习第二章:进程描述与控制_第9张图片
利用记录型信号量解决哲学家进餐问题
经分析可知,放在桌子上的筷子是临界资源,在一段时间内只允许一位哲学家使用。为了实现对筷子的互斥使用,可以用一个信号量表示一只筷子,由这五个信号量构成信号量数组。其描述如下:
semaphore chopstick[5]={1,1,1,1,1};
所有信号量均被初始化为1,第i位哲学家的活动可描述为:

semaphore chopstick[5]={1,1,1,1,1};
do {
	wait(chopstick[i]);  //拿左边筷子
	wait(chopstick[(i+1)%5]); //拿右边筷子
	//eatsignal(chopstick[i]);  //放左边筷子
	signal(chopstick[(i+1)%5]);  //放右边筷子//think
}while[TRUE];

假如每个哲学家都拿左边筷子,即5个信号量chopstick同时为0,则5个进程同时无限期等待而引起死锁。
解决办法:
(1)至多只允许有四位哲学家同时去拿左边的筷子,最终能保证至少有一位哲学家能够进餐,并在用毕时能释放出他用过的两只筷子,从而使更多的哲学家能够进餐。
(2)仅当哲学家的左、右两只筷子均可用时,才允许他拿起筷子进餐。
(3)规定奇数号哲学家先拿他左边的筷子,然后再去拿右边的筷子;而偶数号哲学家则相反。按此规定,将是1、2号哲学家竞争1号筷子;3、4号哲学家竞争3号筷子。即五位哲学家都先竞争奇数号筷子,获得后,再去竞争偶数号筷子,最后总会有一位哲学家能获得两只筷子而进餐。

利用AND信号量机制解决哲学家进餐问题

在哲学家进餐问题中,要求每个哲学家先获得两个临界资源(筷子)后方能进餐,这在本质上就是前面所介绍的AND同步问题,故用AND信号量机制可获得最简洁的解法。

semaphore chopstick[5]={1,1,1,1,1};
do {//think
...
Swait(chopstick[(i+1)%5], chopstick[i]);
...
//eat
...
Ssignal(chopstick[(i+1)%5], chopstick[i]);
}while[TRUE];

读者-写者问题

问题描述:
有读者和写者两组并发进程,共享一个文件,当两个或以上的读进程同时访问共享数据时不会产生副作用,但若某个写进程和其他进程(读进程或写进程)同时访问共享数据时则可能导致数据不一致的错误。因此要求:

  • 允许多个读者可以同时对文件执行读操作;
  • 只允许一个写者往文件中写信息;
  • 任一写者在完成写操作之前不允许其他读者或写者工作;
  • 写者执行写操作前,应让已有的读者和写者全部退出。

信号量设置:
互斥信号量wmutex: 保证读写进程 读写互斥,写写互斥。
整型变量readcount:记录读者进程数目,初值为0。
互斥信号量rmutex: 实现对readcount互斥访问。

算法描述如下:

semaphore rmutex=1,wmutex=1;
int readcount=O;

void reader() {
	do {
		
		wait(rmutex);  //有读者进入,上锁 互斥访问readcount
		if (readcount==O) wait(wmutex); //判断是否是第一个读者进程 ,若是则申请资源 ,上锁书 (直到readcount=0 才释放资源,在此期间不允许写进程执行);若不是第一个则不用申请资源,直接往下进行 
		readcount++; //读者进程+1 
		signal(rmutex); //开锁 释放readcount变量
		 
		perform read operation;
		
		wait(rmutex);  //读者进程已读完准备离开,上锁 互斥访问readcount
		readcount--;  //读者进程-1 
		if (readcount==O) signal(wmutex); //如果是最后一个读者进程离开,则释放掉资源,此时写进程才允许运行;否则继续占用资源 
		signal(rmutex);  //开锁 释放readcount变量
		
	} while(TRUE);
}

void writer() {
	do {
		wait(wmutex); //申请资源 
		perform write operation;
		signal(wmutex);  //释放资源 
	} while(TRUE);
}

void main() {
	cobegin
	reader(); writer();
	coend
}

2.6进程通信

  1. 进程通信指进程之间的信息交换。
  2. PV操作由于效率低,且通信对用户不透明,我们只能称之为低级进程通信。
  3. 在进程之间要传送大量数据时,我们应利用OS提供的高级通信工具,高级进程通信指使用方便高效的传送大量数据的通信方式。

进程通信的类型

高级进程通信可以归为四大类:

共享存储器系统

进程之间基于共享空间进行通信

  • 基于共享数据结构的通信方式(低级通信)
  • 基于共享存储区的通信方式(高级通信)
管道通信系统

指用于连接一个读进程和一个写进程以实现它们之间通信的一个共享文件,又名 pipe文件。向管道提供输入的发送进程(即写进程)以字符流形式将大量的数据送入管道;而接受管道输出的接收进程(即读进程)则从管道中接收(读)数据。由于发送进程和接收进程是利用管道进行通信的,故又称为管道通信。
为了协调双方的通信,管道机制必须提供以下三方面的协调能力:
①互斥
②同步
③确定对方是否存在。

管道通信必然是半双工通信。

消息传递系统

在该机制中,进程不必借助任何共享存储区或数据结构,而是以格式化的消息(message)为单位,将通信的数据封装在消息中,并利用操作系统提供的一组通信命令(原语),在进程间进行消息传递,完成进程间的数据交换。
该方式隐藏了通信实现细节,使通信过程对用户透明化,降低了通信程序设计的复杂性和错误率。

客户机-服务器系统

主要的实现方法分为三类:套接字、远程过程调用和远程方法调用。

消息传递通信实现方式:

  1. 直接消息传递系统
  2. 信箱通信

2.7线程的基本概念

引入进程的目的是更好地使多道程序并发执行,提高资源利用率和系统吞吐量;而引入线程的目的则是减小程序在并发执行时所付出的时空开销,提高操作系统的并发性能。

线程最直接的理解就是“轻量级进程”,它是一个基本的CPU执行单元,也是程序执行流的最小单元,由线程ID、程序计数器、寄存器集合和堆栈组成。

线程运行的三种状态:就绪-执行-阻塞(和进程状态转换一样)

线程控制块:TCB

线程的实现方式:

①内核支持线程KST
②用户级线程ULT
③组合方式(多对一、一对一、多对多)


习题

1.信号量的物理意义是:当前信号量的值大于零时,表示(系统中某类资源的数目 );当信号量值小于零时,其绝对值表示 ( 在该信号量链表中已阻塞进程的数目)。

2.信号量的初值必须是大于零的整数。(Ⅹ)

3.进程间的高级通信机制可归结为3大类,分别是
(1) 共享存储器系统
(2) 消息传递系统
(3) 管道通信

4.设有n个进程共用一个相同的程序段(临界区),如果每次最多允许m个进程(m<=n)同时进入临界区,则信号量的初值为(m).


所学课本:
计算机操作系统 第四版(汤小丹等)西安电子科技大学出版社
王道操作系统复习指导(王道论坛)电子工业出版社

你可能感兴趣的:(操作系统,计算机操作系统)