操作系统PV操作学习总结

本文详细介绍了信号量的概念,包括整形信号量和记录型信号量的使用,以及它们在实现进程同步与互斥中的应用。通过具体实例展示了如何使用信号量解决生产者消费者问题、读者写者问题和哲学家进餐问题,以及顾客与理发师问题。这些经典问题的解决方法揭示了并发控制的重要性和信号量机制的有效性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、信号量

  1. 整形信号量:表示系统中某种资源的数量(不满足"让权等待")。
int S=1;//初始化整型信号量S,表示当前系统中可用的资源数

void wait(int S){	//wait原语,相当于"进入区"
	while(S<=0);	//如果资源数不够,就一直循环等待
	S=S-1;			//如果资源数够,占用一个资源
}

void signal(int S){ //signal原语,相当于"退出区"
	S=S+1;			//使用完资源后,退出区释放资源
}
  1. 记录型信号量:s.value<0时,|s.value|代表链表中已被阻塞的该信号进程的数目(即等待进入临界区的)遵循了"让权等待"原则。
//记录型信号量的定义
typedef struct{
	int value;			//剩余资源数
	struct process *L;	//等待队列
}semaphore;
//某进程需要使用资源时,通过wait原语申请。
void wait(semaphore S){
	S.value--;
	if(S.value<0){
		block(S.L);
	}
}
//进程使用完资源后,通过signal原语释放
void wait(semaphore S){
	S.value++;
	if(S.value<=0){
		wakeup(S.L);
	}
}

二、信号量机制实现同步与互斥

  1. 互斥:设置互斥信号量mutex,初值为1。
semaphore mutex=1;	//初始化信号量

P1(){
	...
	P(mutex);		//使用临界资源前需要加锁
	临界区代码段...
	V(mutex);		//使用临界资源后需要解锁
	...
}

P2(){
	...
	P(mutex);
	临界区代码段...			
	V(mutex);		
	...
}
  1. 同步:必须保证"一前一后"(前V后P)执行的操作。设置同步信号量S,初值为0。注:同步:要为每一对前驱关系各设置一个信号量。P、V操作必须成对出现。

二、信号量机制实现同步与互斥

  1. 互斥:设置互斥信号量mutex,初值为1。
semaphore mutex=0;	//初始化信号量,初值为0

P1(){
	代码1;
	V(S);
	代码2}

P2(){
	P(S);
	代码3;
	代码4}

三、生产者消费者问题

生产者消费者问题(英语:Producer-consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同步问题的经典案例。该问题描述了两个共享固定大小缓冲区的线程——即所谓的“生产者”和“消费者”——在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。
要解决该问题,就必须让生产者在缓冲区满时休眠(要么干脆就放弃数据),等到下次消费者消耗缓冲区中的数据的时候,生产者才能被唤醒,开始往缓冲区添加数据。同样,也可以让消费者在缓冲区空时进入休眠,等到生产者往缓冲区添加数据之后,再唤醒消费者。通常采用进程间通信的方法解决该问题,常用的方法有信号灯法等。如果解决方法不够完善,则容易出现死锁的情况。出现死锁时,两个线程都会陷入休眠,等待对方唤醒自己。该问题也能被推广到多个生产者和消费者的情形。

在这里插入图片描述
如何实现:

  1. 生产者、消费者共享一个初始为空、大小为n的缓冲区
  2. 缓冲区没满时,生产者才能把产品放入缓冲区,否则必须等待。
  3. 缓冲区不空时,消费者才能从中取出产品,否则必须等待。
  4. 缓冲区时临界资源,各进程必须互斥访问。
semaphore mutex=1;	//互斥信号量,实现对缓冲区的互斥访问
semaphore empty=n;	//同步信号量,表示空闲缓冲区的数量
semaphore full=0;	//同步信号量,表示产品数量,即非空缓冲区的数量

producer(){
	while(1){
		生产一个产品;
		P(empty);
		P(mutex);
		讲产品放入缓冲区;
		V(mutex);
		V(full);
	}
}

consumer(){
	while(1){
		生产一个产品;
		P(full);
		P(mutex);
		从缓冲区取出一个产品;
		V(mutex);
		V(empty);
		使用产品;
	}
}

四、读者与写者问题

读者—写者问题(Readers-Writers problem)也是一个经典的并发程序设计问题,是经常出现的一种同步问题。计算机系统中的数据(文件、记录)常被多个进程共享,但其中某些进程可能只要求读数据(称为读者Reader);另一些进程则要求修改数据(称为写者Writer)。就共享数据而言,Reader和Writer是两组并发进程共享一组数据区,要求:
(1)允许多个读者同时执行读操作;
(2)不允许读者、写者同时操作;
(3)不允许多个写者同时操作。

写者优先

semaphore rw=1;	    //用于实现对文件的互斥访问
int count=0;		//记录当前有几个读进程在访问文件
semaphore mutex=1;	//用于保证对count变量的互斥访问
semaphore w=1//用于实现"写优先"

writer(){
	while(1){
		P(w);
		p(rw);
		写文件...
		V(rw);
		V(w);
	}
}

reader(){
	while(1){
		P(w);
		p(mutex);
		if(count==0)p(rw);
		count++;
		V(mutex);
		V(w);
		读文件...
		P(mutex);
		count--;
		if(count==0)V(rw);
		V(mutex);
	}
}

五、哲学家进餐问题

有五个哲学家,他们的生活方式是交替地进行思考和进餐,哲学家们共用一张圆桌,分别坐在周围的五张椅子上,在圆桌上有五个碗和五支筷子,平时哲学家进行思考,饥饿时便试图取其左、右最靠近他的筷子,只有在他拿到两支筷子时才能进餐,该哲学家进餐完毕后,放下左右两只筷子又继续思考。
约束条件
(1)只有拿到两只筷子时,哲学家才能吃饭。
(2)如果筷子已被别人拿走,则必须等别人吃完之后才能拿到筷子。
(3)任一哲学家在自己未拿到两只筷子吃完饭前,不会放下手中已经拿到的筷子。

如何实现

  1. 可以对哲学家施加一些限制条件,比如允许四个哲学家同时进餐,这样可以保证至少有一个科学家是可以拿到左右两只筷子的。
semaphore chopstick[5]={1,1,1,1,1};	//用一个信号量表示一只筷子
semaphore num=4;                   	//限制为4个哲学家

void philosophyer(int i){
	while(1){
		P(num);
		P(chopstick[i]);
		P(chopstick[(i+1)%5]);
		...//eat
		V(chopstick[i]);
		V(chopstick[(i+1)%5]);
		V(num);
		...//think
	}
}
  1. 要求奇数号哲学家先拿左边筷子,然后再拿右边的筷子,而偶数号哲学家相反。用这种方法保证如果相邻的两个奇偶号哲学家都想吃饭,那么只会有其中一个拿起第一只筷子,另一个会直接阻塞,这就避免了占有一支后再等待另一只的情况。
semaphore chopstick[5]={1,1,1,1,1};	//用一个信号量表示一只筷子

void philosophyer(int i){
	if(i%2==0)
	while(1){
		P(chopstick[(i+1)%5]);  //偶数哲学家先拿右边筷子
		P(chopstick[i]);
		...//eat
		V(chopstick[(i+1)%5]);
		V(chopstick[i]);
		...//think
	}
	else
	while(1){
		P(chopstick[i]); 		//奇数哲学家先拿左边筷子
		P(chopstick[(i+1)%5]);
		...//eat
		V(chopstick[i]);
		V(chopstick[(i+1)%5]);
		...//think
	}
}

六、顾客与理发师问题

一个理发师,一把理发椅,n把等候理发的顾客椅子,如果没有顾客则理发师便在理发椅上睡觉 ,当有一个顾客到达时,首先看理发师在干什么,如果理发师在睡觉,则唤醒理发师理发,如果理发师正在理发,则查看是否有空的顾客椅子可坐, 如果有,坐下等待,如果没有,则离开。

int chairs=5,waiting=0;	//定义椅子数和正在等待顾客数量
semaphore baber=0;		//理发师信号量
semaphore customer=0;	//顾客信号量
semaphore mutex=1;		//互斥信号量

void barber(){
	while(1){
		P(customer);
		P(mutex);
		waiting--;
		V(mutex);
		...//cut
		V(barber);
	}
}

void comstomer(){
	while(1){
		P(mutex);
		if(waiting<chairs){  //店里还有座
			waiting++;
			V(customer);
			V(mutex);
			P(barber);
			...//get
		}else
			V(mutex);
	}
}

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值