以上都是一些经典的问题,接下来写一下具体PV操作上需要注意的问题。
一、生产者—消费者问题
其主要是设置好资源 empty 和 full。生产者需要empty,而消费者需要full,同时这两者对于缓冲区的访问是互斥的,再设置一个mutax就好了。
记住先观察再上锁。
二、父女母子问题
即多生产者多消费者问题。 其中的缓冲区只有一个盘子,记为empty,然后父亲放苹果,妈妈放橘子,儿子吃橘子,女儿吃苹果。其中母亲父亲共用同一个资源empty,而儿子和女儿都是分别的,然后可以认为四人对于缓冲区的访问都是互斥的,共用缓冲区mutax,这样思路会简单一些,不用纠结儿子和女儿拿水果究竟是不是互斥的。
三、读者写者问题
这个是个比较值得重视的问题,也是最常用的问题。
读者可以一起读,但是写者不可以一起写,而且写者只能一个人写。
因为这里出现了同类型进行,即读者类和写者类,和之前的爸爸妈妈两个人不一样。
在这个问题中,读者和写者是互斥的,写者和写者也是互斥的,但是不用设置两个互斥变量,这个就是“类”问题和“个”问题的区别,只需要设置一个变量rw表示读者和写者互斥就好了,这样的话就会出现四种情况:
读者运行,写者来访,被rw阻挡在外
写者运行,读者来访,被rw阻挡在外
写者运行,写者来访,被rw阻挡在外——特别要注意,两个写者互斥可以依靠rw解决。
读者运行,读者来访,被rw阻挡在外——这样就不行了,这个与题意矛盾。
这个时候就要设置一个count变量,来表示读者的数目,由于每个读进程来的时候都要实现P(rw),导致堵塞,所以只要提前看一下count的数值,只要其大于0就可以直接访问了,所以我们只要第一个进来的读者阻挡写者,最后一个读者放行就好了。
但是这个时候也要注意count是要设置互斥变量mutax保证其一气呵成的,因为如果每个读者都在确定好了count = 0然后切换下一个读者,也确定好后count = 0切换下一个读者,这样再运行p(rw),这样会导致只有一个读者在阅读,其余的读者都由于rw为负数而堵塞了,所以需要将count设置互斥变量。
但是就算是这样,问题也没有解决,因为读者是四面八方过来的,只要有一个读者在里面阅读,就可以有无数个读者过来阅读,如果读者是源源不断的,那么写者不是得“饿死”吗?
这个时候就要考虑用一个互斥变量w来控制读者的流量,且这个变量是读者和写者共用的,写者可以用这个变量来控制读者不能进去,而写者能进去,相当于在临界区外面架了一座桥,读者不能四面八方进去了,读者和写者都可以控制桥的上升,桥上升之后后续的读者就不能进入临界区了,尽管这个时候临界区里面还有读者在读,等到读者没在读了之后,写者就可以进去了。读者用它相当于又加了一层互斥,作用和实现count互斥的变量是一样的,没啥区别,主要是为了写者能方面控制读者。
除此之外,需要注意写者在升上桥了之后,是在执行完count之后再放下桥,和mutax作用一样,如果在读者进程最后释放桥,那么就会导致多个读者不能同时读的问题。
注意rw是同时控制读者写者和写者写者的关系。
计数变量count需要互斥。
互斥变量w控制读者流量,同时在count执行完之后释放。
三、哲学家问题
主要就是设置一个互斥变量,对于拿筷子这个动作是互斥的,只要互斥了之后,其他人就不可以拿筷子,而且等之前拿筷子的人吃完饭就可以拿起筷子吃饭了。
四、抽烟者问题
这个问题展现了同步的魅力。
一个供给者,三个抽烟者,供给者会给出三个抽烟组合,三个抽烟者依次需要这三个,同时,抽烟者抽完烟之后,需要给供给者发出信号,抽烟者才可以继续生产。
总的来说就是:供给者供给——抽烟者抽烟,同时发出信号——供给者才可以结束进程,执行下一个供给。
所以供给者进程不能一次性执行完,需要一个同步变量finish兜住,使得其进程不能结束,然后等吸烟者抽完了之后,发出了信号V(finish)之后才可以接着生产。
这里其实没有互斥关系,抽烟动作都是独立的,只不过就是没有材料来抽烟就会被堵塞,等到供给者生产出来之后就会被唤醒。