用餐哲学家多线程不会结束



我正试图使用python 中的互斥锁来解决用餐哲学家的问题

import threading
import time
chopstick_a = threading.Lock()
chopstick_b = threading.Lock()
chopstick_c = threading.Lock()
sushi_count = 500
def philosopher(name, first_chopstick, second_chopstick):
global sushi_count
#print(name,'is trying to eat')
while sushi_count > 0:  # eat sushi until it's all gone
first_chopstick.acquire()
second_chopstick.acquire()
if sushi_count > 0:
sushi_count -= 1
print(name)
print(name, 'took a piece! Sushi remaining:', sushi_count)

second_chopstick.release()
first_chopstick.release()


if __name__ == '__main__':
threading.Thread(target=philosopher, args=('phil_one', chopstick_a, chopstick_b)).start()
threading.Thread(target=philosopher, args=('phil_two', chopstick_b, chopstick_c)).start()
threading.Thread(target=philosopher, args=('phil_three', chopstick_c, chopstick_a)).start()

问题是,这个程序永远不会以零结束,只有一个哲学家可以吃掉

这是一个从未达到零的样本输出

phil_one took a piece! Sushi remaining: 466
phil_one
phil_one took a piece! Sushi remaining: 465
phil_one
phil_one took a piece! Sushi remaining: 464
phil_one
phil_one took a piece! Sushi remaining: 463
phil_one
phil_one took a piece! Sushi remaining: 462
phil_one
phil_one took a piece! Sushi remaining: 461
phil_one
phil_one took a piece! Sushi remaining: 460
phil_one
phil_one took a piece! Sushi remaining: 459
phil_one
phil_one took a piece! Sushi remaining: 458
phil_one
phil_one took a piece! Sushi remaining: 457
phil_one
phil_one took a piece! Sushi remaining: 456

程序从不以零结束。。。

其他答案解决了这个问题,

。。。只有一个哲学家能吃掉

这个问题被称为饥饿:一个(或多个(线程不断赢得访问某些资源的竞争,而其他线程不断输掉竞争。

这是一种通常会导致饥饿的反模式:

while some_trivial_condition:
my_mutex.lock()
do_some_work()
my_mutex.unlock()

每当线程释放my_mutex时,几乎接下来要做的就是再次尝试锁定互斥对象。另一个线程潜入并获取锁的机会窗口非常小。刚刚释放锁的线程已经在运行,而其他线程都在休眠,(被阻塞,(正在等待,这一事实使问题变得更糟。

在大多数操作系统中,线程调度的目标是最有效地利用CPU。这意味着,当两个或多个线程争夺同一资源时,操作系统将倾向于最快获取资源的线程,而而不是等待时间最长的线程。

在一些编程系统中,但在Python标准库中,有一种叫做公平锁的东西,其行为完全相反:操作系统总是唤醒等待公平锁时间最长的线程。

用餐哲学家问题是一个没有简单解决方案的简单问题的例子。

在你的特殊方法中,每根筷子都有一把锁。考虑以下场景:

  1. 每个哲学家都同时拿起左手筷子。既然这是开始,所有的筷子都可以自由拿。正是这样。现在没有免费的筷子了
  2. 每个哲学家都在等待合适的筷子。但这种情况从来没有发生过,因为除了等待,没有人做任何事情

您遇到了死锁。

现在,您可能会感到困惑,因为您实际上在挂起之前看到了一些输出。这是因为不是每个哲学家都有相同的速度。这是一个比喻:不是每个循环迭代都以相同的速度工作,有些操作执行得更快,有些则慢一点。还有一个操作系统调度程序,用于确定哪个线程运行以及何时运行。此外,Python还有一个叫做GIL的东西,这使得它几乎是单线程的。所有这些(以及更多(的组合可以导致";phil_one";哲学家循环几次,然后其他人运行,整个系统最终陷入僵局。

我强烈鼓励你阅读维基页面(我一开始链接的那个(。你可以在那里找到一些解决问题的办法。

祝贺您,您陷入僵局。死锁本身几乎是一个哲学问题。发生了什么?

哲学家一拿了一些寿司,松开了筷子A和B
  • 哲学家二获得了筷子B
  • 哲学家一获得了筷子A
  • 哲学家一仍在等待获得筷子B。可能还需要一段时间
  • 最新更新