哲学家问题的两种解决方式

问题描述(来自百度百科)

哲学家就餐问题可以这样表述,假设有五位哲学家围坐在一张圆形餐桌旁,做以下两件事情之一:吃饭,或者思考。吃东西的时候,他们就停止思考,思考的时候也停止吃东西。餐桌中间有一大碗意大利面,每两个哲学家之间有一只餐叉。因为用一只餐叉很难吃到意大利面,所以假设哲学家必须用两只餐叉吃东西。他们只能使用自己左右手边的那两只餐叉。哲学家就餐问题有时也用米饭和筷子而不是意大利面和餐叉来描述,因为很明显,吃米饭必须用两根筷子。

哲学家从来不交谈,这就很危险,可能产生死锁,每个哲学家都拿着左手的餐叉,永远都在等右边的餐叉(或者相反)。即使没有死锁,也有可能发生资源耗尽。例如,假设规定当哲学家等待另一只餐叉超过五分钟后就放下自己手里的那一只餐叉,并且再等五分钟后进行下一次尝试。这个策略消除了死锁(系统总会进入到下一个状态),但仍然有可能发生“活锁”。如果五位哲学家在完全相同的时刻进入餐厅,并同时拿起左边的餐叉,那么这些哲学家就会等待五分钟,同时放下手中的餐叉,再等五分钟,又同时拿起这些餐叉。

 

解决办法

第一种:每次获取筷子时,先检查一下是否左右筷子都在,如果筷子齐全就获取两双筷子,如不在则等待。

from threading import Thread
from threading import Lock
import time, random

# 产生五只筷子
chopStickA =  Lock()
chopStickB =  Lock()
chopStickC =  Lock()
chopStickD =  Lock()
chopStickE =  Lock()



def philosopher(name,leftChopstick,RightChopstick):
    if not (leftChopstick.locked() and RightChopstick.locked()): # 如果没有两只筷子,则等待筷子
        print("%s is waiting" % (name))
        time.sleep(random.random(1,2))
    else:
        leftChopstick.acquire()
        RightChopstick.acquire()
        print("%s is eating"%(name))
        time.sleep(random.randint(1, 3))
        print("%s is over"%(name))
        leftChopstick.release()
        RightChopstick.release()


if __name__ == '__main__':
    Thread(target=philosopher,args=('philosopherA',chopStickA,chopStickB)).start()
    Thread(target=philosopher,args=('philosopherB',chopStickB,chopStickC)).start()
    Thread(target=philosopher,args=('philosopherC',chopStickC,chopStickD)).start()
    Thread(target=philosopher,args=('philosopherD',chopStickD,chopStickE)).start()
    Thread(target=philosopher,args=('philosopherE',chopStickE,chopStickA)).start()

 

第二种:设置信号量为4,每次只能有4个人同时获取筷子,这样总能有一个哲学家获得两双筷子

from threading import Thread
from threading import Semaphore, Lock
import time

# 创建5个筷子
chopStickA =  Lock()
chopStickB =  Lock()
chopStickC =  Lock()
chopStickD =  Lock()
chopStickE =  Lock()

# 至多允许4个人同时抢锁
count = Semaphore(4)


def philosopher(name,leftChopstick,RightChopstick):
    while True:
        # 抢锁之前先获取资格。
        count.acquire()
        leftChopstick.acquire()
        RightChopstick.acquire()
        print("%s is eating" % (name))
        time.sleep(random.random(1,3))
        print("%s is over" % (name))
        leftChopstick.release()
        RightChopstick.release()
        count.release()

if __name__ == '__main__':
    Thread(target=philosopher,args=('philosopherA',chopStickA,chopStickB)).start()
    Thread(target=philosopher,args=('philosopherB',chopStickB,chopStickC)).start()
    Thread(target=philosopher,args=('philosopherC',chopStickC,chopStickD)).start()
    Thread(target=philosopher,args=('philosopherD',chopStickD,chopStickE)).start()
    Thread(target=philosopher,args=('philosopherE',chopStickE,chopStickA)).start()