操作系统期末重点

本来自信的以为自己能把全部的内容复习完,深夜十一点看着满桌的头发我才意识到,听着老师划的重点才是真香,虽说老师已经很明确的划了重点,但我好像还是什么都不会,脑袋里一片空白,这就是平时摸鱼的下场,摸鱼摸得爽,考试火葬场,唉,可是又有什么办法呢,只能临阵磨枪了。那么开始正文吧,加油,奥里给!

1、信号量机制

信号量实现互斥的基本原理

两个或多个进程可以通过传递信号进行合作,可以迫使进程在某个位置暂时停止执行(阻塞等待),指导它收到一个可以“向前推进”的信号(被唤醒)

相应的,将实现信号灯作用的变量成为信号量

  • 信号量:仅能由同步原语进行操作的整型变量
  • 同步原语:P/wait操作、V/signal操作
  • 信号量类型:整形、记录型、AND型、信号量机制

一、整型信号量

1、原语描述

S:表示资源数目

int S = 1;	//初始化整型信号量S,表示当前系统中可用打印机资源数

void wait(int S){	//wait源于,相当于“进入区”
	while(s<=0);	。。如果资源数不够,就一直等待循环	
	S--;	//如果资源数够,则占用一个资源
}
void signal(S){	//signal原语,相当于“退出区”
	S++;	//使用完资源后,在退出区释放资源
}
  1. 与普通整数变量的区别:对信号量的操作只有三种,即“初始化、P操作、V操作”
  2. “检查”和“上锁”一气呵成,避免了并发、异步导致的问题
  3. 不满足”让权等待“原则,会发生”忙等“

二、记录型信号量

1、原语描述

/*记录型信号量的定义*/
typedef struct {
	int value;	//剩余资源数
	struct process *L;	//等待队列
}	semaphore;
/*某进程需要使用资源时,通过wait原语申请*/
void wait (semaphore S) {
	S.value --;
	if (S.value < 0) {
		block(S,L);	//如果剩余资源数不够,使用block原语使进程从运行态进度阻塞态,并把挂到信号量S的等待队列(阻塞队列)中
	}
}
/*进程使用完后,使用signal原语释放*/
void signal (semaphore S) {
	s.value ++;
	if(S.value <= 0) {
		wakeup(S,L);	//释放资源后,若还有别的进程在等待这种资源,则使用wakeup原语唤醒等待队列中的一个进程,该进程从阻塞态变为就绪态
	}
}
  1. wait(S)、signal(S)也可以记为P(S)、V(S),这对原语可用于实现对系统资源的“申请”和“释放”
  2. S.value 的初值表示系统中某种资源的数目
  3. 对信号量S的一次P操作意味着进程请求一个单位的该类资源,因此需要执行S.value–,表示资源数减1,当S.value < 0 时表示该类资源已经分配完毕,因此进程应调用block原语进行自我阻塞(当前运行的进程从运行态→阻塞态),主动放弃处理及,并且插入该类资源的等待队列S,L中。符合“让权等待”原则,不会出现”忙等“现象
  4. 对信号量S的一次V操作意味着进程释放一个单位的该类资源,因此需要执行S.value <= 0,表示依然有进程在等待该类资源,因此调用wakeup原语唤醒等待队列中的第一个进程(被唤醒进程从阻塞态→就绪态

信号量的应用

信号量机制实现进程互斥

  1. 分析并发进程的关键活动,划定临界区(如:打印机)
  2. 设置互斥信号量mutex,初值为1
  3. 在临界区之前执行P(mutex)
  4. 在临界区之后执行V(mutex)
semaphore mutex = 1;	//题目中无特别说明一般如此声明信号量
P1() {P(mutex);	//使用临界资源前要加锁
	临界区代码段...
	V(mutex);	//使用临界资源后要解锁}

P2(){P(mutex);	
	临界区代码段...
	V(mutex);}

注意:

  1. 不同的临界资源需要设置不同的互斥信号量(如:打印机设置为mutex1,摄像头设置为mutex2;)
  2. P、V操作必须成对出现

信号量机制实现进程同步

进程同步:要让各并发进程按要求有序地推进
3. 分析什么地方需要实现“同步关系”,即必须保证“一前一后”执行的两个操作(或两句代码)
4. 设置同步信号量S,初值为0;
5. 在“前操作”之后执行V(S);
6. 在“后操作”之前执行P(S);

操作系统期末重点_第1张图片

信号量机制实现进程前驱

进程前驱:多层的同步关系
其实每一个前驱关系就是一个进程同步问题(需要保证一前一后的操作)
因此:

  1. 要为每一对前驱关系设置一个同步变量
  2. 在“前操作”之后对相应的同步变量执行V操作
  3. 在“后操作”之钱对相应的同步变量执行P操作

操作系统期末重点_第2张图片

2、生产者-消费者问题

问题分析

  • 系统中有一组生产者进程和一组消费者进程,生产者进程每次生产一个产品放入缓冲区,消费者进程每次从缓冲区中取出一个产品(数据)并使用
  • 只有缓冲区没满时,生产者才能把产品放入缓冲区,否则必须等待
  • 只有缓冲区不空时,消费者才能从中取出产品,否则必须等待
  • 缓冲区是临界资源,各进程必须互斥地访问(防止并发时数据被覆盖)
    操作系统期末重点_第3张图片
    操作系统期末重点_第4张图片

如何实现

semaphore mutex = 1;	//互斥信号量,实现对缓冲区的互斥访问
semaphore empty = n;	//同步信号量,表示空闲缓冲区的数量
semaphore full = 0;		//同步信号量,表示产品的数量,也即非空缓冲区的数量
producer () {
	while(1) {
		生产一个产品;
		P(empty);	//消耗一个空闲缓冲区
 	    P(mutex);	//*
		把产品放入缓冲区;
	    V(mutex);	//*
		V(full);	//增加一个产品**
	}
}

*实现互斥是在同一个进程中进行一对PV操作P(mutex)V(mutex)

consumer (){
	while(1) {
		P(full);	//消耗一个产品**
		P(mutex);
		从缓冲区中取出一个产品;
		V(mutex);
		V(empty);	//增加一个空闲缓冲区
		使用产品;
	}
}

**实现两个进程同步是在其中一个进程中执行P,另一个进程中执行V操作V(full)P(full)

思考:能否改变相邻P、V操作的顺序

不能,实现互斥的P操作一定要在实现同步的P操作之后,即P(mutex)一定要在P(empty)之后,因为如果不是这样,可能会导致死锁
操作系统期末重点_第5张图片
使用产品;也不能放到PV之间,因为这样会降低系统的并发度:在执行使用产品;代码时,如果不释放临界资源,其他需要临界资源的进程就无法使用,降低了系统的并发度

你可能感兴趣的:(操作系统期末重点)