|
- import threading
- import time
- class Consumption:
- def __init__(self, counts):
- self.counts=counts
- self.forks=[Fork() for _ in range(self.counts)]
- self.philosophers=[Philosopher(i) for i in range(self.counts)]
- def consumption(self, position):
- philosopher=self.philosophers[position]
- left_fork, right_fork = self.forks[position], self.forks[(position+1) % self.counts]
- first_fork = left_fork if position%2 == 0 else right_fork
- second_fork=right_fork if position%2==0 else left_fork
- while not philosopher.leave:
- philosopher.with_forks(first_fork, second_fork)
- class Fork:
- def __init__(self):
- self.lock=threading.Lock()
- def wait(self):
- try:
- self.lock.acquire(timeout=3)
- return True
- except threading.Timeout:
- return False
- def signal(self):
- self.lock.release()
- class Philosopher:
- def __init__(self,position):
- self.satiety=50
- self.leave=False
- self.position=position
- self.forks=[]
- def with_forks(self, *forks):
- for fork in forks:
- if not fork.wait():
- self.reduce()
- return
- else:
- self.forks.append(fork)
- self.eat()
- def put_forks(self):
- counts=len(self.forks)
- for i in range(counts):
- self.forks[i].signal()
- self.forks.pop(i)
- def eat(self,):
- time.sleep(10)
- self.rise()
- def anger(self):
- self.put_forks()
- self.leave=True
- print(f"Dr.{self.position} is so hungry that he can't bear it and decide to leave.")
- def be_full(self,philosopher):
- self.put_forks()
- self.leave=True
- print(f"Dr.{self.position} feel satisfied and leave the table.")
- def rise(self):
- if self.satiety>=0 and self.satiety<100:
- self.satiety+=10
- else:
- self.be_full()
- def reduce(self):
- if self.satiety>=0 and self.satiety<100:
- self.satiety-=10
- else:
- self.anger()
- if __name__=="__main__":
- counts=5
- consumption=Consumption(counts)
- for i in range(counts):
- threading.Thread(target=consumption.consumption,args=(i,)).start()
复制代码 哲学家饥饿问题是计算机科学家迪杰斯特拉(Dijkstra)提出的经典并发问题。
有5个哲学家(线程)坐在圆桌上,每个哲学家之间放着一把叉子。一个哲学家要吃饭,他需要左右两边的叉子。如果相邻的两个哲学家同时试图拿起中间的叉子,就可能产生死锁。
- Consumption类初始化时,根据传入的哲学家数量(counts)创建相应数量的叉子和哲学家对象。
- consumption方法用于模拟某位哲学家的就餐过程。根据哲学家的位置,确定他需要获取的叉子的顺序(先左后右或先右后左,以避免死锁),并尝试拿起叉子吃饭。
- Fork类表示叉子,包含一个线程锁来控制对叉子的访问。wait方法尝试获取锁,如果获取成功返回True,否则在设定的超时时间后返回False。signal方法用于释放锁。
- Philosopher类代表哲学家,包含哲学家的状态(如满意度、是否离开等)和与叉子交互的方法(如拿起叉子、放下叉子等)。
- 在Philosopher类中,with_forks方法尝试让哲学家拿起左右两边的叉子,如果拿起成功则开始吃饭,否则根据哲学家的满意度决定是否离开。
- eat方法模拟吃饭过程,吃完后增加哲学家的满意度。
- anger和be_full方法分别模拟哲学家因饥饿而愤怒离开和吃饱后满意离开的情况。
- rise和reduce方法分别用于增加和减少哲学家的满意度。
|
- 白冥
:这段代码通过一些策略来避免死锁:
哲学家编号与叉子获取顺序:根据哲学家的编号(偶数或奇数),他们首先尝试拿起左边的叉子或右边的叉子。这有助于防止相邻的哲学家同时拿起同一把叉子,从而降低死锁的风险。
锁的超时机制:在尝试获取叉子(即锁)时,设置了一个3秒的超时时间。如果超时,则放弃获取叉子,这也有助于防止死锁。
哲学家的状态:每个哲学家有一个“饥饿度”(satiety),当他们成功吃到时,饥饿度会降低;如果因为超时而未能获取到叉子,饥饿度会增加。当饥饿度达到100时,哲学家会感到满足并离开桌子;当饥饿度降到0以下时,哲学家会因为太饿而生气地离开桌子。
-
|