进程的同步与互斥--大总结

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/weixin_39956356/article/details/85254860

进程的同步与互斥


写在前面-很久没有写文章,源于今年参加了考研。在这里我分享以下计算机操作系统中有关进程的同步与互斥的问题。希望对你有帮助!

  • 1:吸烟者问题
  • 2:雪碧、可乐问题
  • 3:打印奇、偶数问题
  • 4:理发师问题
  • 5:公交车问题
  • 6:生产者、消费者问题
  • 7:读者-写者问题(写着优先)
  • 8:读者-写者问题(读者优先)
  • 9:哲学家就餐问题(0号哲学家是左撇子)
  • 10:放映电影问题
  • 11:小和尚和老和尚打水问题
  • 12:2015计算机联考-信封问题
  • 13:生产线加工问题
  • 14:独木桥问题
/**************************************************************************************************
**										吸烟者问题
** 问题描述:
**	三个吸烟者进程和一个经销商进程,每个吸烟不断制烟并吸烟,制烟的过程需要烟草、纸、火柴。		 		
**	这三个进程分别掌握烟草、纸、火柴中的一种,经销商源源不断的提供原料,每次提供三种原料的两种
**	当吸烟者发现原料正是自己所缺少的,该吸烟者就会取走这两种原料,与他之前的原料混合制烟、吸烟
**	经销商发现原料被取走了,就会继续提供任意两种原料。
** 注意:
		**这里不萌吧每个资源分别定义一个信号量,在编写代码
		  这是把原本的原子操作一分为二,会死锁
**************************************************************************************************/
semaphore Stp = 0;											//烟草和纸的组合信号量
semaphore Spm = 0;											//纸和火柴的组合信号量
semaphore Stm = 0;											//烟草和火柴的组合信号量
semaphore buffer = 1;										//缓冲区
void main(){
	cobegin{
		smokert(void){										//拥有烟草的吸烟进程
			while(true){
				P(Spm);										//有纸和火柴?
				fatch_paper_match();
				V(buffer);									//释放缓冲区
				smoke();
			}	
		}
		smokerp(void){										//拥有纸的吸烟进程
			while(true){
				P(Stm);										//有烟草和火柴?
				fatch_tobacoo_match();
				V(buffer);									//释放缓冲区
				smoke();
			}	
		}
		smokerm(void){										//拥有火柴的吸烟进程
			while(true){
				P(Stp);										//有烟草和纸?
				fatch_tobacoo_paper();
				V(buffer);									//释放缓冲区
				smoke();
			}	
		}
		agency(void){										//经销商供货进程
			int item;										//用于货物识别
			P(buffer);
			item = put_material;							//放置原料
			if(item == p_m)									//纸和火柴,则Spm+1
				V(Spm);
			else if(item == t_m)							//烟草和火柴,则Stm+1
				V(Stm);
			else											//烟草和纸,则Stp+1
				V(Stp);
		}	
	}coend
}



/**************************************************************************************************
**										吸烟者问题
** 问题描述:
**	三个吸烟者进程和一个经销商进程,每个吸烟不断制烟并吸烟,制烟的过程需要烟草、纸、火柴。		 		
**	这三个进程分别掌握烟草、纸、火柴中的一种,经销商源源不断的提供原料,每次提供三种原料的两种
**	当吸烟者发现原料正是自己所缺少的,该吸烟者就会取走这两种原料,与他之前的原料混合制烟、吸烟
**	经销商发现原料被取走了,就会继续提供任意两种原料。
** 注意:
		**这里不萌吧每个资源分别定义一个信号量,再编写代码
		  这是把原本的原子操作一分为二,会死锁
**************************************************************************************************/
semaphore mutex = 1;										//进入库房互斥信号量
semaphore kele  = M;										//可乐的控制信号量,初值为M
semaphore sprit = N;										//雪碧的控制信号量,初值为N
semaphore empty = C;										//库房空货位信号量,初值为C
semaphore full  = 0;										//库房产品数信号量,初值为0
void main(){
	cobegin{
		keleproduce(void){									//可乐生产车间进程
			while(true){
				int item;
				item = producekele();						//生产可乐
				P(kele);									//可乐是否超出吗?
				P(empty);									//有空位吗?
					P(mutex);								//互斥访问临界区(机械手空闲吗?)
						putkele();
					V(mutex);								//释放机械手
				V(full);									//增加经销商提货的数量
				V(sprit);									//增加雪碧入库数量
			}
		}
		spritproduce(void){									//雪碧生产车间进程
			while(true){
				int item;
				item = producesprit();						//生产雪碧
				P(sprit);									//雪碧是否超出吗?
				P(empty);									//有空位吗?
					P(mutex);								//互斥访问临界区(机械手空闲吗?)
						putsprit();
					V(mutex);								//释放机械手
				V(full);									//增加经销商提货的数量
				V(kele);									//增加可乐入库数量
			}
		}
		consumer(void){										//经销商提货进程
			while(true){
				int item;
				P(full)										//库房有货吗?
					P(mutex);								//互斥访问临界区(机械手空闲吗?)
						item = getkelesprit();
					V(mutex);								//释放机械手
				V(empty);
				if(item == kele)
					V(kele);								//增加可乐入库数量				
				if(item == sprit)
					V(sprit);								//增加雪碧入库数量
			}
		}	
	}coend
}



/**************************************************************************************************
**										打印奇、偶数问题
** 问题描述:
**	一生产者进程P,两个消费者进程C1,C2.共用一个缓冲区Pool,缓冲区Pool最多可以放N个数	
**	进程P :将输入设备读入数存放于缓冲区Pool中,若满,则阻塞
**	进程C1:只将缓冲区中奇数打印,若无,则阻塞
**	进程C2:只将缓冲区中偶数打印,若无,则阻塞
**************************************************************************************************/
semaphore mutex = 1;										//缓冲区互斥信号量
semaphore odd   = 0;										//P与C1同步(奇数)信号量
semaphore even  = 0;										//P与C2同步(偶数)信号量
semaphore Pool  = N;										//缓冲区可用数,odd+even+Pool=N
void main(){
	cobegin{
		P(void){											//生产进程
			while(true){
				int number;									//临时存放数据
				number = fatch();
				P(Pool);									//缓冲区有空闲吗?
					P(mutex);								//互斥访问临界区
						put(number);
					V(mutex);
				if(number%2 == 0)				
					V(even);								//偶数信号量+1
				else
					V(odd);									//奇数信号量+1
			}
		}		
		C1(void){											//打印寄数进程
			while(true){
				P(odd);										//有无奇数?
					P(mutex);								//互斥访问临界区
						get_odd();
					V(mutex);
				V(Pool);									//缓冲区空闲空间+1
				print_odd();
			}
		}		
		C2(void){											//打印偶数进程
			while(true){
				P(even);									//有无偶数?
					P(mutex);								//互斥访问临界区
						get_even();
					V(mutex);
				V(Pool);									//缓冲区空闲空间+1
				print_even();
			}
		}
	}coend
}



/**************************************************************************************************
**										理发师问题
** 问题描述:
**	理发店一间工作室(仅有1个椅子),一间接待室(最多n>=1个椅子)
**		若理发店无顾客,理发师就去睡觉
**		若新顾客看到所有的椅子都坐满人,则离开
**		接待室有空椅子且理发师正在工作,则新顾客在接待室椅子上等待
**		若理发师在睡觉,则顾客唤醒理发师
**************************************************************************************************/
semaphore mutex    = 1;										//缓冲区互斥信号量
semaphore customer = 0;										//顾客人数
semaphore barber   = 0;										//理发师人数,为0表示就一个理发师
int waiting        = 0;										//等侯理发的人数
void main(){
	cobegin{
		barber(void){										//打印寄数进程
			while(true){
				P(customer);								//有顾客吗?
					p(mutex);
						waiting--;
						V(barber);							//同步信号量,有理发师啦!
					V(mutex);								//这里V(barber);在前;由于竞争。就像跑步比赛一样,冠军只有一个,但是起点是一样的,要把所有的customer排在门外
				cut_hair();									//理发
			}	
		}
		customer(void){										//打印寄数进程
			p(mutex);
			if(waiting < n){								//等待人数最多为n
				waiting++;
				V(customer);								//新顾客人数加一
				V(mutex);
				P(barber);									//由于barber仅有一个,所有进程在这全挂起,即坐着等候
				goto_hairroom();							//去理发师房间理发
			}
			else
				V(mutex);
		}
	}coend
}



/**************************************************************************************************
**										公交车问题
** 问题描述:
**	一个司机,一个门,一个售票员,请给出售票员进程、司机进程
**		司机只有等门关好了才能开车
**		只有车停好了,售票员才能开门
**		售票员可以通过观察与询问预先知道是否有乘客下车,若没有,则不用停车
**************************************************************************************************/
semaphore mutex_drive 	   = 1;								//同步信号量,由售票员发出信号,即人是否下完车或上完车了
semaphore mutex_stop 	   = 0;								//同步信号量,由售票员发出信号,是否需要停车
semaphore mutex_open_door  = 0;								//同步信号量,由司机发出信号,是否可以开门
semaphore mutex_close_door = 0;								//同步信号量,由司机发出信号,是否可以关门
void main(){
	cobegin{
		drive(void){
			while(true){
				P(mutex_drive);								//人上齐了吗?
				V(mutex_close_door);						//售票员,把门关上!
				drive();									//开车
				P(mutex_stop);								//有人要下车吗?售票员,快回答我!
				stop();
				V(mutex_open_door);							//车停好了,可以开门了
			}
		}
		conductor(void){
			while(true){
				P(mutex_close_door);						//好,门关了
				close_door();
				while(!nobody_will_leave()) just_wait();	
				V(mutex_stop);								//有人要下车
				P(mutex_open_door);							//车停好了吗?
				open_door();
				while(!nobody_leave_finish()) just_wait();	//等待上下车结束
				V(mutex_drive);								//人上齐了
			}
		}
	}coend
}



/**************************************************************************************************
**										生产者、消费者问题
** 问题描述:
**	仅有一个缓冲区,互斥访问
**		只有缓冲区有产品且无生产者访问临界区,消费者才能消费
**		只有缓冲区有空位且无消费者访问临界区,生产者才能生产
**************************************************************************************************/
semaphore mutex = 1;										//缓冲区互斥信号量
semaphore full  = N;										//产品个数
semaphore empty = 1;										//空位个数
int buffer[N];
void main(){
	cobegin{
		producer(void){										//生产者进程
			int i = 0;
			while(true){
				P(empty);									//有空位吗?
					P(mutex);
						buffer[i++] = produc_item;
						i = i % N;							//构成循环缓冲
					V(mutex);
				V(full);									//快来消费,产品+1
			}
		}
		customer(void){										//消费者进程
			int i = 0; 
			while(true){
				P(full);									//有产品吗?
					P(mutex);
						consume_item = buffer[i--];
						int i = i % N;						//构成循环缓冲
					V(mutex);
				V(empty);									//空位+1
			}
		}
	}coend
}



/**************************************************************************************************
**										读者-写者问题(读者优先)
** 问题描述:
**	读者优先
**		读者优先意味着新到的读者“插队”,这时写者很憋屈!!直到没有读者为止才可以读
**		写写不能同时,可以多个读者读
**************************************************************************************************/
semaphore write_db = 1;										//互斥信号量,互斥读操作
semaphore mutex_rc = 1;										//互斥信号量,互斥访问rc
int rc = 0;													//读者的数量
void main(){
	cobegin{
		reader(void){										//读进程
			while(true){
				P(mutex_rc);
					if(rc++ == 0)							//第一个读者来的时候,看有写者没?(相等,第一个读者哦)
						P(write_db);
				V(mutex_rc);
				read_data();
				P(mutex_rc);
					if(rc-- == 0)							//读者全读完了,有写者马上写,举个例子:读者数量由5,4,3···1.减到0,没读者啦,开始写!
						V(write_db);
				V(mutex_rc);
			}
		}
		writer(void){										//写进程
			while(true){
				P(write_db);								//写进程会被阻塞,由于之前有写读进程 P(write_db);
					write_data();
				V(write_db);
			}
		}
	}coend
}



/**************************************************************************************************
**										读者-写者问题(写者优先)
** 问题描述:
**	写者优先
**		写者优先意味着新到的写者“插队”,这时读者很憋屈!!直到没有写者为止才可以读
**		写写不能同时,可以多个读者写
**		为了保证写者优先,在写进程通过if让读阻塞
**		当然reader()内本就会控制写者,因读的时候不能写。
**************************************************************************************************/
semaphore read_db = 1;										//互斥信号量,互斥写操作,仅有一个读
semaphore write_db = 1;										//互斥信号量,互斥读操作,仅有一个写
semaphore mutex_rc = 1;										//互斥信号量,互斥访问rc
semaphore mutex_wc = 1;										//互斥信号量,互斥访问wc
int rc = 0;													//读者的数量
int wc = 0;													//写者的数量
void main(){
	cobegin{
		reader(void){										//读进程
			while(true){
				P(read_db);									//没有写者了,才能读(一直等,看着写者插队)
					P(mutex_rc);
						if(rc++ == 0)						//第一个读者来的时候,看有写者没?(相等,第一个读者哦)
							P(write_db);
					V(mutex_rc);
				V(read_db);										
				read_data();								//可以有多个读者,不需要互斥访问
				P(mutex_rc);
					if(rc-- == 0)							//读者全读完了,有写者马上写,举个例子:读者数量由5,4,3···1.减到0,没读者啦,开始写!
						V(write_db);
				V(mutex_rc);
			}
		}
		writer(void){										//写进程(主)
			while(true){
				P(mutex_wc);								//这里和“读者优先”的读进程类似,写进程优先,是为了阻塞读进程
					if(rc++ == 0)							//第一个写者来的时候(相等,第一个写者哦),此时读阻塞
						P(read_db);
				V(mutex_wc);
					P(write_db);							//仅有一个写进程可以写
						write_data();
					V(write_db);
				P(mutex_wc);
					if(rc-- == 0)							//直到所有写者都写完了(有写者就插队)举个例子:写者数量由5,4,3···1.减到0,没写者啦,开始读!
						V(read_db);
				V(mutex_wc);
			}
		}
	}coend
}



/**************************************************************************************************
**								哲学家就餐问题(0号哲学家是左撇子)
** 问题描述:
**	假设0号哲学家是左撇子
**************************************************************************************************/
#define N 5
semaphore chopsticks[N];									//互斥信号量,互斥访问rc
void pickup_chopsticks(int i){								//拿起左右筷子
	if(i == 0){												//处理0号哲学家的特殊
		P(chopsticks[i]);
		P(chopsticks[(i+1)%N]);
	}else{
		P(chopsticks[(i+1)%N]);
		P(chopsticks[i]);
	}
}

void pickdwn_chopsticks(int i){								//放下左右筷子
	V(chopsticks[i]);
	V(chopsticks[(i+1)%N]);
}

void main(){
	while(true){
		think();
		pickup_chopsticks(i);
		eat();
		pickdwn_chopsticks(i);
	}
}



/**************************************************************************************************
**										放映电影问题
** 问题描述:
**	录像厅有三种1、2、3不同影片可供观众选择放映,需满足如下条件		 		
**	1:任一时刻只能放映一种电影,放映是自动放映的, 最后一个观众主动离开则结束当前放映
**	2:当前正在放映的观众可立即进入,观看同一种电影人数没有限制
**	3:此时观看其他的电影的人需要按到达顺序等候(如此时放映1,则2,3分别排成一队),一种
	   新电影放映时,等候该队列的人全部入场
**	4:用一个进程代表一个观众	   
** 注意:
		1:由于观看人数有限制,只能满足一部分要求,而另外两队人必须等待,
		2:由于看电影的人数有多人,故要分别设置三个计数器变量count1,count2,count3,初值均为0
		3:为三部电影分别设置信号量S1,S2,S3,初值都为1,表示对count1,count2,count3互斥访问
**************************************************************************************************/
Semaphore S1 = 1;										//对count1互斥访问
Semaphore S2 = 1;										//对count2互斥访问
Semaphore S3 = 1;										//对count3互斥访问
Semaphore S  = 1;										//只能放映一种电影
int count1 = 0;											//看m1电影的数量
int count2 = 0;											//看m2电影的数量
int count3 = 0;											//看m3电影的数量
void main(){
	cobegin{
		watch_m1(void){									//看m1电影
			P(S1);										//对count1互斥访问
				count1 = count1+1;						//这种if方式是设计的一种模板吧,读者写者!!
				if(count1 == 1)							//谁先抢到S,就要等数量减至0,才会放弃临界区
					P(S);
			V(S1);
			看电影1;
			P(S1);
				count1 = count1-1;
				if(count1 == 0)							//减到0,放弃临界区
					P(S);
			V(S1);
		}
		watch_m2(void){									//看m2电影
			P(S2);										//对count2互斥访问
				count2 = count2+1;
				if(count2 == 2)							
					P(S);								//谁先抢到S,就要等数量减至0,才会放弃临界区
			V(S2);
			看电影2;
			P(S2);
				count2 = count2-1;
				if(count2 == 0)							//减到0,放弃临界区
					P(S);
			V(S2);
		}	
		watch_m3(void){									//看m3电影
			P(S3);										//对count3互斥访问
				count3 = count3+1;
				if(count3 == 3)
					P(S);								//谁先抢到S,就要等数量减至0,才会放弃临界区
			V(S3);
			看电影3;
			P(S3);
				count3 = count3-1;
				if(count3 == 0)							//减到0,放弃临界区
					P(S);								
			V(S3);
		}
	}coend
}



/**************************************************************************************************
**										小和尚和老和尚打水问题
** 问题描述:
**	某寺庙有老、小和尚若干,小和尚提水,老和尚喝水,每次喝一桶	 		
**	1:水缸可以装10桶水,水来自水中,井窄,一次只能放一个桶
**	2:水桶有三个。每次入杠仅只一桶水,取水,注水不可同时进行
**	4:取水,注水进程   
** 注意:
		1:由于观看人数有限制,只能满足一部分要求,而另外两队人必须等待,
		2:由于看电影的人数有多人,故要分别设置三个计数器变量count1,count2,count3,初值均为0
		3:为三部电影分别设置信号量S1,S2,S3,初值都为1,表示对count1,count2,count3互斥访问
**************************************************************************************************/
//同步信号量
Semaphore empty = 10;									//缸可以装10通水
Semaphore full = 0;										//与empty是一对,设计方法!
//互斥信号量
Semaphore mutex_well = 1;								//对count3互斥访问
Semaphore mutex_vat  = 1;								//只能放映一种电影

Semaphore pail = 3;										//水桶数量3个
void main(){
	cobegin{
		xiao_Monk(void){								//小和尚打水
			P(empty);									//需要打水吗?			
				P(pail);								//有桶吗?
					P(mutex_well);						//互斥访问井
						从井取一桶水;
					V(mutex_well);
					P(mutex_vat);						//互斥访问缸
						将水倒入缸中
					V(mutex_vat);
				V(full);
			V(pail);									//放下桶	
		}
		lao_Monk(void){									//看m2电影
			P(full);									//有水吗?
				P(pail);								//有桶吗?
					P(mutex_vat);						//互斥访问缸
						从缸里取水;
					V(mutex_vat);
				P(empty);
					喝水;
			V(pail);
		}	
	}coend
}



/**************************************************************************************************
**										信封问题
** 问题描述:
**	A,B两人进行辩论,	 		
**	1:每个人都从自己的信封里取出对方的问题,并回答其中问题,之后提出一个新问题放入对方的邮箱里
**	2:A信箱最多放M封信,B信箱最多放N封信
**	3:初始A信箱有x(0<x<M)个邮件,初始B信箱有y(0<y<N)个邮件,每次取一封信相应的邮件减1
** 注意:
		1:由于观看人数有限制,只能满足一部分要求,而另外两队人必须等待,
		2:由于看电影的人数有多人,故要分别设置三个计数器变量count1,count2,count3,初值均为0
		3:为三部电影分别设置信号量S1,S2,S3,初值都为1,表示对count1,count2,count3互斥访问
**************************************************************************************************/
//对A而言
Semaphore remain_A = M-x;									//A信箱还可以放M-x封信
Semaphore current_A = x;									//A信箱还已经放了x封信
//对B而言
Semaphore remain_B = N-y;									//B信箱还可以放N-y封信
Semaphore current_B = y;									//B信箱还已经放了y封信
//互斥访问
Semaphore mutex_A = 1;										//对A信箱互斥访问
Semaphore mutex_B = 1;										//对B信箱互斥访问
void main(){
	cobegin{
		A(void){										//A同学
			P(current_A);								//A信箱有信吗?			
				P(mutex_A);								
					从A信封取一封信;
				V(mutex_A);						   		
			V(remain_A);								//A信箱可以多放一封信
				回答其中的问题并提出一个新问题;	
			P(remain_B);								//B信箱有空可放吗?			
				P(mutex_B);								
					从A信封取一封信;
				V(mutex_B);								
			V(current_B);
		}
		B(void){										//B同学
			P(current_B);								//B信箱有信吗?			
				P(mutex_B);															
					从B信封取一封信;
				V(mutex_B);						   		
			V(remain_B);								//B信箱可以多放一封信
				回答其中的问题并提出一个新问题;	
			P(remain_A);								//A信箱有空可放吗?				
				P(mutex_A);								
					从A信封取一封信;
				V(mutex_A);								
			V(current_A);
		}	
	}coend
}



/**************************************************************************************************
**										生产线加工问题
** 问题描述:
**	自行车生产线有一只箱子,里面有N个位置(N>=3),每个位置可以放一个车架或车轮,有三个工人	 		
**	1:加工一个车架,车架放入箱中
**	2:加工一个车轮,车轮放入箱中
**	3:取两个车轮和一个车架,组装成一辆自行车
** 注意:
		1:最多可以放的车轮数:N-1
		2:最多可以放的车架数:N-2
**************************************************************************************************/
Semaphore wheel = 0;										//车轮数
Semaphore frame = 0;										//车架数
Semaphore empty = N;										//空位数
Semaphore wheel_M = N-1;									//最多可以放的车轮数,极限要有一个车架
Semaphore frame_M = N-2;									//最多可以放的车架数,极限要有两个车轮
void main(){
	cobegin{
		worker1(void){									//工人1
			while(TRUE){
				加工一个车架;
				P(frame_M);								//检查车架是否达最大
					P(empty);								
						车架放入箱中;
					V(frame);							//车架数加1				   	
			}
		}
		worker2(void){									//工人2
			while(TRUE){
				加工一个车轮;
				P(wheel_M);								//检查车架是否达最大
					P(empty);								
						车轮放入箱中;
					V(wheel);							//车轮数加1				   	
			}
		}	
		worker3(void){									//工人3
			while(TRUE){
				P(frame);								//取一个车架				
					取一个车架;
				V(empty);							
				V(frame_M);								//可用车架数架1
				
				P(wheel);								//取两个车轮
					P(wheel);
						取两个车轮;
					V(wheel_M);
				V(wheel_M);
				V(empty);
				V(empty);
			}
		}
	}coend
}



/**************************************************************************************************
**										独木桥问题
** 问题描述:
**	独木桥只能单向行驶,一个方向车还没有过完时,另外方向不能过	 		
**	1:不防假设南北方向通行
**************************************************************************************************/
Semaphore mutexSN = 1;									//保护countSN
Semaphore mutexNS = 1;									//保护countNS
Semaphore bridge = 1;									//互斥访问桥
int countSN = 0;										//计数变量(由南到北的车辆数)
int countSN = 0;										//计数变量(由北到南的车辆数)
void main(){
	cobegin{
		SToN(void){										//由南到北
			P(mutexSN);									//检查车架是否达最大
				if(countSN == 0)
					P(bridge);							//谁先来,谁先过		
				countSN++;
			P(mutexSN);
			过桥;
			P(mutexSN);
				countSN--;
				if(countSN == 0)						//该方向没有车辆了
					V(bridge);	
			P(mutexSN);
		}
		NTos(void){										//由北到南
			P(mutexNS);									
				if(countNS == 0)		
					P(bridge);							
				countNS++;
			P(mutexNS);
			过桥;
			P(mutexNS);
				countNS--;
				if(countNS == 0)						//该方向没有车辆了
					V(bridge);	
			P(mutexNS);
		}	
	}coend
}

最后:源文件及链接

链接:https://pan.baidu.com/s/1VpOOH3OP7AiDMedgeZFPQg 密码:eq4y

猜你喜欢

转载自blog.csdn.net/weixin_39956356/article/details/85254860