一文搞懂 生产者-消费者问题

PV原语

在操作系统的课程中,我们有学习到PV原语,所谓原语,即为不可中断的过程。我们可以先简单的理解为:

  • P:申请资源,将信号量的值减一
  • V:释放资源,将信号量的值加一

P操作之后,若信号量的值仍大于等于零,则进程继续运行。若小于零,则将该进程放入等待序列中去。(若信号量为-3,则说明当前等待队列有3个进程等待访问)。

V操作之后,若信号量的值仍大于零(注意和P操作的区别),则进程继续运行。若小于等于零,则从等待队列中释放一个进程,然后再返回原进程或转进程调度。

同步互斥

同步即为进程之间相互协调,线程之间的访问有一定的顺序关系。而互斥指的是某一资源同时只允许一个访问者进行访问。在我们分析问题时,我们首先要找出同步互斥的关系。

生产者消费者问题

生产者消费者有很多的应用场景,我们首先来看一个最简单的场景。

1) 一个生产者,一个消费者,公用一个缓冲区。

问题分析

我们可以理解为爸爸给儿子削苹果吃,爸爸每削完一个苹果放在盘子里,等待儿子去吃,儿子拿走盘子里的苹果吃掉之后,爸爸会再削一个苹果。爸爸就是生产者,儿子就是消费者,而盘子只有一个,也就是缓冲区。

爸爸与儿子对盘子的访问是互斥的,当盘子为空时,爸爸削苹果放入盘子,当盘子有苹果的时候,儿子吃掉苹果。

我们需要两个信号量来表示缓冲区是满还是空。

empty = 1;// 1表示缓冲区空,0表示缓冲区满
full = 0;// 1表示缓冲区满,0表示缓冲区空 
// 生产者伪代码
produce{
	while(true){
		P(empty);// empty-1
		生产商品,放入缓冲区;
		V(full);// full+1
	}
}

// 消费者伪代码
Customer{
	while(true){
		p(full);
		从缓冲区取出产品,消费产品;
		V(empty);
	}
}

这就是最基本的生产者消费者问题了,只涉及到一个生产者一个消费者和一个缓冲区问题,不知道各位理解了没有,如果理解了,可以接着往下看。

2) 一个生产者,一个消费者,公用n个环形缓冲区。

问题分析

还是刚才爸爸和儿子的故事,但这个时候我们多拿了几个盘子,并且我们把盘子摆成了圆环状。我们要求爸爸按顺序依次将苹果放入这些盘子中去。这时候再来思考一下,我们应该如何去解决这个问题呢?

在这个问题中,我们需要获取到可用缓冲区的位置,我们用in和out来表示缓冲区的编号。in和out的范围是1~n-1。

empty = 1;// 1表示缓冲区空,0表示缓冲区满
full = 0;// 1表示缓冲区满,0表示缓冲区空 
int in = 1;
int out = 1;
// 生产者伪代码
produce{
	while(true){
		P(empty);// empty-1
		生产商品,放入缓冲区in;
		in = (in+1) mod n;// 模运算即取余运算
		V(full);// full+1
	}
}

// 消费者伪代码
Customer{
	while(true){
		p(full);
		从缓冲区out取出产品,消费产品;
		out = (out+1) mod n;
		V(empty);
	}
}

3) 一组生产者,一组消费者,公用n个环形缓冲区

问题分析

还是刚才那一家,不过现在爷爷奶奶,爸爸妈妈,儿子女儿齐上阵了。现在该怎么办,刚才两个问题我们的生产者消费者都只有一个,生产者和生产者不会去抢盘子,因为只有他自己。消费者和消费者也不会抢苹果,因为只有他自己。

但现在情况改变了,盘子里只能放一个苹果,爸爸放了,妈妈就不能放了,盘子里也只有一个苹果,儿子吃了,女儿就不能吃了。这时候生产者和生产者就产生了互斥关系,消费者和消费者也产生了互斥关系。我们需要设计两个互斥信号量来保证它们之间的互斥关系。

empty = 1;// 1表示缓冲区空,0表示缓冲区满
full = 0;// 1表示缓冲区满,0表示缓冲区空 
int in = 1;
int out = 1;
int mutex1 = 1;//用于生产者对缓冲区的互斥
int mutex2 = 1;//用于消费者对缓冲区的互斥
// 生产者伪代码
produce{
	while(true){
		P(empty);// empty-1
		P(mutex1);
		生产商品,放入缓冲区in;
		in = (in+1) mod n;// 模运算即取余运算
		V(mutex1);
		V(full);// full+1
	}
}

// 消费者伪代码
Customer{
	while(true){
		p(full);
		P(mutex2);
		从缓冲区out取出产品,消费产品;
		out = (out+1) mod n;
		V(mutex2)
		V(empty);
	}
}
  • 3
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不冬眠的小钱学长

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值