进程同步问题之生产者-消费者问题

目录

例题

变式1:生产者消费者串联

变式2:多个生产者消费者

变式3:对生产者(或消费者)的活动有约束

变式4:对生产者(或消费者)的并发有约束


例题

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

需要保证以下同步关系:
1.多个进程互斥地访问公共缓冲区:互斥信号量  mutex
2.不能向满的缓冲区中添加产品:可用的空资源信号量 empty
3.不能从空的缓冲区中提取产品:可用的满资源信号量 full

semaphore mutex = 1;//临界区互斥信号量
semaphore empty = n;//空闲缓冲区
semaphore full = 0;//缓冲区初始化为空

producer(){
	while(1){
		produce an item in nextp;
		P(empty);//判断缓冲区是否有空间
		P(mutex);//访问临界资源
		add nextp to buffer;
		V(mutex);//离开临界区,释放互斥信号量
		V(full);//满缓冲区数+1
	}
}

comsumer(){
	while(1){
		P(full);
		P(mutex);
		remove an item from buffer;
		V(mutex);
		V(empty);//空缓冲区数+1
		consum the item;
	}
}

main(){
	cobegin
		producer();
		comsumer();
	coend
}

注意:互斥夹紧P(mutex)这一步必须确保在缓冲区已满/有空闲之后才操作,不然会出现死锁

当然也有偷懒版本简化版本:使用AND型信号集

producer(){ 
	while(1){   
		produce an item nextp;   //生产一个数据
        Swait(empty, mutex);	//进入临界区
      	buffer[in]=nextp;       //将一个数据送入缓冲池
      	in=(in+1) mod n;        //修改in指针
	    Ssignal(mutex,full); 	  
	}
}

consumer(){  
	while (1){
		Swait(full,mutex);
		nextc=buffer[out];    //从缓冲区读出一个数据
      	out=(out+1) mod n;    //修改out指针
		Ssignal(mutex,empty);
      	consume the item in nextc; //消费一个数据
	}
}

变式1:生产者消费者串联

进程同步问题之生产者-消费者问题_第1张图片

 和单个生产者消费者差不多,注意相互之间的逻辑关系即可

semaphore mutex1 = 1,mutex2 = 1;
semaphore emptyB1 = m,emptyB2 = n;
semaphore fullB1 = 0,fullB2 = 0;

A1(){ 
	while(1){   
		produce an item nextp(Input);  
		P(emptyB1);
		P(mutex1);
		add nextp to buffer(B1);
		V(mutex1);
		V(fullB1);
	}
}

A2(){ 
	while(1){   
		P(fullB1);
		P(mutex1);
		remove an item from buffer(B1);
		V(mutex1);
		V(emptyB1);
		process the item;
		P(emptyB2);
		P(mutex2);
		add nextp to buffer(B2);
		V(mutex2);
		V(fullB2);
	}
}

A3(){
	while(1){
		P(fullB2);
		P(mutex2);
		remove an item from buffer(B2);
		V(mutex2);
		V(emptyB2);
		Ouput;
	
}

main(){
	Cobegin
		A1();
		A2();
		A3();
	Coend
}

变式2:多个生产者消费者

桌上有一空盘,允许存放一只水果。爸爸可向盘中放苹果,也可向盘中放桔子,儿子专等吃盘中的桔子,女儿专等吃盘中的苹果。规定当盘空时一次只能放一只水果供吃者取用,请用P、V原语实现爸爸、儿子、女儿三个并发进程的同步。

实际上这个问题可以抽象成两个消费者和一个生产者被链接到大小为1的缓冲区上

semaphore plate = 1,apple = 0,orange = 0;

father(){ 
	while(1){   
		P(plate);
		put the fruit on the plate;
		if(isapple) V(apple);
		else V(orange);
	}
}

daughter(){ 
	while(1){   
		P(apple);
		eat;
		V(plate);
	}
}

son(){
	while(1){
		P(orange);
		eat;
		V(orange);
	}
	
}

main(){
	Cobegin
		father();
		daughter();
		son();
	Coend
}

桌上有一空盘,最多可容纳两只水果,每次只能放入或取出一只水果。爸爸专向盘中放苹果,妈妈专向盘中放桔子。两个儿子专等吃盘中的桔子,两个女儿专等吃盘中的苹果。请用P、V操作实现爸爸、妈妈、儿子、女儿之间的同步与互斥关系。

问题可以抽象成两个消费者和两个生产者被链接到大小为2的缓冲区上,那为什么这题要多设置一个互斥的信号量呢?因为上一题的缓冲区大小只有1,默认只能互斥访问,而这次缓冲区大小为2,需要在设置三个同步信号量外,额外设置一个互斥信号量

semaphore plate = 2,apple = 0,orange = 0;
semaphore mutex = 1;

father(){ 
	while(1){   
		P(plate);
		P(mutex);
		put the fruit on the plate;
		v(mutex);
		V(apple);

	}
}

mother(){
	while(1){
		P(orange);
		P(mutex);
		put the fruit on the plate;
		V(mutex);
		V(orange);
	}
}

daughter(){ 
	while(1){   
		P(apple);
		P(mutex);
		eat;
		V(mutex);
		V(plate);
	}
}

son(){
	while(1){
		P(orange);
		P(mutex);
		eat;
		V(mutex);
		V(orange);
	}
	
}

main(){
	Cobegin
		father();
		mother();
		daughter();
		son();
	Coend
}

变式3:对生产者(或消费者)的活动有约束

系统中有多个生产者进程和多个消费者进程,共享一个能存放1000件产品的环形缓冲区(初始为空。当缓冲区未满时,生产者进程可以放入其生产的一件产品,否则等待;当缓冲区未空时,消费者进程可以从缓冲区取走一件产品,否则等待。

要求一个消费者进程从缓冲区连续取出10件产品后,其他消费者进程才可以取产品。请使用信号量P,V(wait(),signal())操作实现进程间的互斥与同步,要求写出完整的过程,并说明所用信号量的含义和初值。

 这个问题可以考虑设置一个消费者之间的互斥量,当一个消费者准备取产品时,首先要看是不是已经有一个消费者正在取产品,如果是需要等它连续取完十件后才能开始取,否则可以从缓冲区开始取产品

semaphore empty = 1000;
semaphore full = 0;
semaphore mutex1 = 1;//缓冲区互斥量
semaphore mutex2 = 1;//消费者之间的互斥量

producer(){ 
	while(1){   
		produce an item in nextp;
		P(empty);
		P(mutex1);
		add nextp to buffer;
		V(mutex1);
		V(full);
	}
}

comsumer(){
	while(1){
		P(mutex2);
		for(int i=1;i<=10;i++){
			P(full);
			P(mutex1);
			remove an item from buffer;
			V(mutex1);
			V(empty);
		}
		V(mutex2);//消费了10个产品,消费者缓冲区使用完毕

	}
}


main(){
	Cobegin
		producer();
		comsumer();
	Coend
}

变式4:对生产者(或消费者)的并发有约束

某寺庙,有小和尚、老和尚若干。有一水缸,由小和尚用水桶从井中提水入缸,老和尚用水桶从缸里取水饮用。水缸可容10桶水,水取自同一井中。水井径窄,每次只能容一个水桶取水水桶总数为3个。每次入、取缸水仅为1桶,且不可以同时进行。试用P、V操作给出小和尚、老和尚动作的算法描述。

提取题干信息:记录型信号量有两个:水缸和水桶,互斥信号量两个:水井取水、水缸入、取水

接下来就可以根据题意去实现了

//empty1为水缸 cnt为空闲水桶数量
semaphore empty1 = 10,full1 = 0;
semaphore cnt = 3;
semaphore mutex1 = 1;//水井互斥量
semaphore mutex2 = 1;//水缸互斥量

young(){ 
	while(1){   
		P(empty1);//查看水缸是否没满
		P(cnt);//查看是否有空余水桶

		P(mutex1);
		打水;
		V(mutex1);

		P(mutex2);
		将水倒入水缸中;
		V(mutex2);

		V(cnt);
		V(full1);
	}
}

old(){
	while(1){
		P(full1);//查看水缸是否有水
		P(cnt);//查看是否有空余水桶
		P(mutex2);
		从水缸中取水;
		V(mutex2);
		V(cnt2);
		V(empty1);
	}
}

你可能感兴趣的:(操作系统,c++)