操作系统—生产者与消费者

天勤计算机考研笔记

PV操作中经典的生成者(producer)和消费者(consumer)问题

nyLIq1.png

问题分析

生产者—消费者问题,实际上就是二者共用了一块缓冲区(题中的仓库),所以生产者之间和消费者之间是互斥的关系,但同时生产者消费者之间又是协同的关系,所以将其归类为进程同步问题。

解决方案1

根据问题,我们很容易写出下面的代码,其中的item即“产品”。

nyONe1.md.png

但执行之后可能会产生一个很严重的问题:因为程序是并发执行的,所以很可能导致producer()进程执行到某条语句的时候,因为调度的原因,cpu被分配给了consumer()进程。严重情况下,可能会导致二者都进入阻塞状态,如下图情况:

nyzaGV.md.png

这种情况也称为死锁

发生这种情况的根本原因,是因为对于producerconsumer这两个进程而言,本题中的“仓库”是临界资源,(访问仓库的代码putItemIntoBuffer()称为临界区),多个进程同时访问临界资源,就可能导致问题,这个问题也叫竞争条件(Race condition)

解决方案1.1—同步问题

为了解决竞争条件问题,就引入了信号量。

其实方案1中的itemCount也是信号,但它仅仅解决了是否阻塞/唤醒合作进程,没能说明具体阻塞/唤醒几个进程,也就是说没能体现出的概念。

所以我们换个方式,对于producer,我们关注仓库中还有多少个空位置empty,而对于consumer则关注仓库中已放入多少个产品full。这就达到不再使用临界资源的情况。如下图所示:

n6PrNj.md.png

从图中可以看出,producer实际上是在不断消耗空位置个数,如果cpu始终在执行producer,那么empty被消耗为空,producer被阻塞,继续执行的话empty小于0,其绝对值就等于被阻塞的进程数。

同理,full<0的绝对值就是consumer被阻塞的进程数。

注意:这里当empty和full都大于0时,表示的是空位数和产品数。但是当二者小于0时,代表的是阻塞的producer和consumer!!!

从上面可以看出,emptyfull存在逻辑上相反的关系,即$empty=n-full$,但是在各自的进程中,其过程又具有相似性,因此我们可以抽象出一个值,记为value,其结构体如下图所示:

n6RpuD.md.png

图中的两个函数就是PV操作

接下来就可以改写producerconsumer的代码:

n6Rev8.md.png

先来看producer()

P操作:

1
P(empty);

传入参数empty,如果empty自减后小于0,则说明仓库中没有空位置,则把当前的producer阻塞掉;如果empty自减后大于0,则说明仓库中仍然有位置,则继续执行当前进程:

1
putItemIntoBuffer();//往仓库中加入一个商品

再执行V操作:

1
V(full)

当前的进程使用完了临界资源,则需要将full+1,即释放了一个资源,例子中也就是产品数+1。值得注意的是若full+1<=0,那说明consumer之前有阻塞。

S小于0应该是说没有临界资源可供使用,为什么还要唤醒进程?

V原语操作的本质在于:一个进程使用完临界资源后,释放临界资源,使S加1,以通知其它的进程,这个时候如果S<0,表明有进程阻塞在该类资源上,因此要从阻塞队列里唤醒一个进程来“转手”该类资源。比如,有两个某类资源,四个进程A、B、C、D要用该类资源,最开始S=2,当A进入,S=1,当B进入S=0,表明该类资源刚好用完, 当C进入时S=-1,表明有一个进程被阻塞了,D进入,S=-2。当A用完该类资源时,进行V操作,S=-1,释放该类资源,因为S<0,表明有进程阻塞在该类资源上,于是唤醒一个。

上面这段话,结合第一个引用中的内容更好理解。

这里之前理解上还有个小误区,唤醒了consumer的进程是进入就绪态而不是执行态,因此当前的进程——这里是producer,还是需要继续执行直到完成。

右边consumer的操作和producer类似。

解决方案1.2—互斥问题

方案1.1解决了同步问题,但仍然存在互斥问题。即我们假设putItemIntoBuffer()函数中的代码如下:

1
2
Buffer[i]=item;
i++;

这样如果当producer-1执行到第一行语句时,cpu发生了调度,此时又有个进程producer-2执行了第一行语句,那么显然Buffer[i]中的元素就被覆盖掉了。

为了处理这个问题,我们只需要在一个进程执行上面两行代码时,不允许任何其他进程介入即可,如下图:

n6xKqH.md.png

注意一下emptyfullmutex的初值。

最后得出一些小结论:

n6xUsg.md.png

n6x0ds.md.png

-------------End-------------
梦想总是要有的,万一有人有钱呢?