生产者消费者问题是一个非常著名的进程同步、进程互斥的问题。
【题目描述如下:】
这个模型存在这么两个问题:
1、当缓冲区为空的时候,如何不让消费者取物品?当缓冲区满的时候,如何不让生产者继续生产?
2、由于生产进程和消费进程都是并发的,因此会产生同时访问并修改临界资源的问题,会造成结果的错误。(这主要是因为,计算机内部在进行计算的时候,要把缓存中的值拷贝到寄存器register上,然后计算完之后,再把register的值拷贝给高速缓存;如果进程在中间做到一半的时候,发生了中断,其他进程有可能将register的值改掉,那么最终的结果必然是错误的!)
首先解决问题1:
我们可以设定int empty = n; int full = 0;
empty表示缓冲区空余的位置,full表示缓冲区已经占据的位置。
根据信号量的知识,当生产者进程在往缓冲区内生产数据时,要判断empty是否大于0,即p(empty)。如果empty小于0,那么所有的生产者进程都要阻塞。
同样的,消费者在进行消费前,也要判断full是否大于0,即p(full)。如果full小于0,那么意味着缓冲区内没有任何的物品,无法进行消费,生产者进程阻塞。
伪代码表示生产者进程:
begin:
P(empty);
生产;
V(full);
end;
伪代码表示消费者进程:
begin:
P(full);
消费;
V(empty);
end;
至此,问题1我们可以解决了。
再解决问题2:
针对问题2,我们需要对将每次访问临界资源的操作,视为一个原子性的操作。这里就又需要加上一个mutex来控制。设定mutex = 1,初值为1。即,每次只能允许一个进程修改共享数据。
因此,更严谨的写法:
生产者:
begin:
P(empty);
P(mutex)
生产;
V(mutex)
V(full);
end;
消费者:
begin:
P(full);
P(mutex)
消费;
V(mutex)
V(empty);
end;
【总结:】
实际上,通过一段时间的学习可以发现,进程管理和公共厕所的管理很像【嗯,对,我是认真的~】
我们每次可以让n个人进入公共厕所,假设厕所中只有一个便池,那么厕所内部n - 1个人就需要等待这个便池中的人解决完了之后出来,下一个人才能进入便池上厕所。与此同时,解决完的人就会走出厕所,然后坐在外面等候的人又可以进入厕所了…
在这个例子中,每个人好比是一个一个的进程;厕所是一个容量为n的缓冲区;便池是一个临界资源,一次只能由一个进程所使用。【那当然啊,同时使用的话,岂不是乱套了…】