操作系统学习笔记——进程的同步与互斥(三)

操作系统学习笔记——进程的同步与互斥(三)

主要是理解信号量,提高做题能力,帮助形象的理解和记忆


一、进程实现同步与互斥的几种方法

提示:为了解决临界区的互斥访问问题,操作系统给出了很多方法; 同时给出了四个原则:空闲让进,忙则等待,有限等待,让权等待。

1.软件检测法

主要是一些算法

  • 单标志法:违背了空闲让进
  • 双标志前检查法:违背了忙则等待
  • 双标志后检查法:可能会导致“饥饿”
  • Peterson’s Algorithm :增加了一个公用的标志位,等于单标结合双后的方法

2.硬件实现法

提示:利用中断和原语来实现
包括了

  • 中断屏蔽法:优点是方便,缺点是降低系统效率
  • 硬件指令法:利用原语,优点是可以适用于多个数目的进程,缺点是比较耗费时间

二、信号量

信号量机制其实是硬件指令法中的一种,由P&V两种原子操作来协助完成。 利用代码来介绍一下信号量的基本操作

struct {
	int value;
	struct proc *HEAD;	//等待队列
}semaphore;				//给结构体改名为信号量
void P(semaphore S){
	S.value--;
	if(S.value < 0){
	//然后把这个进程链接到等待队列
	block();			//让这个进程不再占用CPU资源
	}
}
void V(semaphore S){
	S.vlaue++;
	if(S.value<=0){
	//然后把这个进程移出来
	wakeup();			//唤醒这个队列,使之进入就绪态
	}
}

三、信号量_实现同步

如何体现进程同步?
先设置变量为0,要求先完成的在完成后V一下,要求后完成的在开始前P一下。

举个例子,现有两个进程分别为P1,P2,这里要求,P2进程必须要等待P1进程完全执行后才可以执行。这里面的问题就涉及到了同步问题,如果P2没有等到P1执行完就开始执行了,显然是我们不能接受的结果。
那么如何用信号量来解决这个问题呢?

  1. 设置同步信号量:semaphore S=0
  2. 区分要求逻辑上先执行完毕的进程:这里是P1
  3. 区分要求逻辑上后执行完毕的进程:P2

下面利用代码解决这个问题

semaphore S = 0;			//设置全局同步变量
P1(){
	...;
	V(S);					//此时的value值为0,执行完毕后,V一下,值为1
}

P2(){
	p(S);					//如果此时没有V过S,则值为0,再减就是-1,会阻塞
	...;					//相反V过之后,值为1,减1后为0,能完成资源申请
	...;
}	

四、信号量_实现互斥

如何体现进程间的互斥呢?
先设置变量为1,公用同一个信号量,开始用之前P,结束后V。

举个例子,现有两个进程分别为P1,P2,这里要求,P1与P2不能同时访问某一临界区,那么如何用信号量来解决这个问题呢?

  1. 设置同步信号量:semaphore S=1
  2. 然后采用复制粘贴的方式,编写两个进程的函数

下面利用代码解决这个问题

semaphore S = 1;			//设置全局互斥变量
P1(){
	P(S);					//用之前P
	//进入临界区
	V(S);					//结束后V
}

P2(){
	P(S);					//用之前P
	//进入临界区
	V(S);					//结束后V
}

五、信号量_实现前驱关系

如何体现进程间的前驱关系?
实现前驱关系,可以视作更高级的同步。
为每个前驱要求设置独立的同步变量初始值为0

举个例子,要求实现如下图所示的前驱关系:
在这里插入图片描述
理一下题目的思路,S1完成后,才可以进行S2,S3。S2完成后,才可以进行S4,S5。S3,S4,S5完成后才可以进行S6。

  1. 分别设置同步信号量:上面有多少条线就设置多少个同步信号量
  2. 然后分别书写这些进程

下面利用代码解决这个问题

semaphore S12,S13,S24,S25,S46,S56,S36 = 0;			//设置全局同步变量
S1(){
	...;
	V(S12);					//结束后V
	V(S13);					//结束后V
}

S2(){
	p(S12);					//开始前P
	...;
	V(S24);					//结束后V
	V(S25);					//结束后V
}

S3(){
	p(S13);					//开始前P
	...;
	V(S36);					//结束后V
}

S4(){
	p(S24);					//开始前P
	...;
	V(S56);					//结束后V
}

S5(){
	p(S25);					//开始前P
	...;
	V(S56);					//结束后V
}

S6(){
	P(S36);					//开始前P
	P(S46);
	P(S56);					
	...;
}

六、信号量的经典示例

1.消费者问题

详解

2.读写者问题

有一个许多进程共享的数据区,这个数据区可以是一个文件或者主存 的一块空间;有一些只读取这个数据区的进程(Reader)和一些只往数据区写数据的进 程(Writer),此外还需要满足以下条件:
(1)任意多个读进程可以同时读这个文件;
(2)一次只有一个写进程可以往文件中写;
(3)如果一个写进程正在进行操作,禁止任何读进程度文件。

int count = 0;                  //⽤用于记录当前的读者数量量 

semaphore mutex = 1;            //⽤用于保护更更新count变量量时的互斥 semaphore rw = 1;               //⽤用于保证读者和写者互斥地访问⽂文件 

writer () {                     //写者进程
        while (1) {        
        P(rw);                  //互斥访问共享⽂文件        
        Writing;                //写⼊入        
        V(rw);                  //释放共享⽂文件    
	}
}

reader () {                     // 读者进程
    while (1) {
	P(mutex);               	//互斥访问count变量量        
	if (count == 0) {       	//当第⼀一个读进程读共享⽂文件时            				 
		 P(rw);              	//阻⽌止写进程写 
	}
	 count++;               	//读者计数器器加1        
	 V(mutex);               	//释放互斥变量量count        
	 reading;                	//读取        
	 P(mutex);               	//互斥访问count变量量       
	 count--;                	//读者计数器器减1        
	 if (count == 0) {       	//当最后⼀一个读进程读完共享⽂文件 	
	 	V(rw);             	 	//允许写进程写  
	 }
	  V(mutex);               	//释放互斥变量量count 
	}
}

3.哲学家问题

由Dijkstra提出并解决的哲学家进餐问题(The Dinning Philosophers Problem)是典型的同步问题。该问题是描述有五个哲学家共用一张圆桌,分别坐在周围的五张椅子上,在圆桌上有五个碗和五只筷子,他们的生活方式是交替地进行思考和进餐。平时,一个哲学家进行思考,饥饿时便试图取用其左右最靠近他的筷子,只有在他拿到两只筷子时才能进餐。进餐完毕,放下筷子继续思考。

方案一:直接拿筷子,但五个人可能会同时拿起自己左手边的筷子,是不允许的,所以只准四个人拿

semaphore chopstick[5] = {1, 1, 1, 1, 1};
semaphore r = 4;
Pi() { 
	while (1) {
		P(r); 								//请求进餐
		P(chopstick[i]); 					//请求左⼿边的筷⼦
		P(chopstick[(i + 1) % 5]); 			//请求右⼿边的筷⼦
		eat;
		V(chopstick[i]); 					//放回左边筷⼦
		V(chopstick[(i + 1) % 5]); 			//放回右边筷⼦
		V(r);
		think;
	}
}

方案二:只要拿筷子,就是互斥的操作

semaphore chopstick[5]={1,1,1,1,1};
semaphore mutex = 1; 						//互斥地取筷子
Pi (){              						//i号哲学家的进程 
	while(1){
	P(mutex); 
	P(chopstick[i]); 						//拿左 
	P(chopstick[(i+1)%5]); 					//拿右 
	V(mutex); 
	eat;
	V(chopstick[i]); 						//放左 
	V(chopstick[(i+1)%5]); 					//放右 
	think;
	}
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值