📜  使用监视器的餐饮哲学家解决方案

📅  最后修改于: 2021-09-27 15:46:39             🧑  作者: Mango

先决条件:监控、进程同步

餐饮哲学家问题——N 个哲学家围坐在圆桌旁

  • 每个哲学家之间有一根筷子
  • 哲学家必须拿起最近的两根筷子才能吃饭
  • 哲学家必须先拿起一根筷子,然后再拿起第二根,而不是同时拿起

我们需要一种算法来在多个进程(哲学家)之间分配这些有限的资源(筷子),以便解决方案没有死锁和饥饿。

存在一些解决餐饮-哲学家问题的算法,但它们可能会出现死锁情况。此外,无死锁的解决方案不一定是无饥饿的。由于编程错误,信号量可能导致死锁。仅靠监视器不足以解决这个问题,我们需要带有条件变量的监视器

基于监视器的餐饮哲学家解决方案

我们通过提出餐饮哲学家问题的无死锁解决方案来说明监视器概念。 Monitor 用于控制对状态变量和条件变量的访问。它只告诉何时进入和退出该段。这个解决方案强加了这样的限制,即哲学家只能在两根筷子都可用的情况下才能拿起她的筷子。

为了编码这个解决方案,我们需要区分我们可能会发现哲学家的三种状态。为此,我们引入以下数据结构:

THINKING –当哲学家不想访问任何一个叉子时。

HUNGRY –当哲学家想要进入临界区时。

吃——当哲学家拿到两个叉子时,即他已经进入了这个部分。

哲学家 i 可以设置变量 state[i] = EATING 仅当她的两个邻居不吃东西时
(state[(i+4) % 5] != EATING) 和 (state[(i+1) % 5] != EATING)。

// Dining-Philosophers Solution Using Monitors
monitor DP
{
    status state[5];
    condition self[5];
  
    // Pickup chopsticks
    Pickup(int i)
    {
        // indicate that I’m hungry
        state[i] = hungry;
  
        // set state to eating in test()
        // only if my left and right neighbors 
        // are not eating
        test(i);
  
        // if unable to eat, wait to be signaled
        if (state[i] != eating)
            self[i].wait;
    }
  
    // Put down chopsticks
    Putdown(int i)
    {
  
        // indicate that I’m thinking
        state[i] = thinking;
  
        // if right neighbor R=(i+1)%5 is hungry and
        // both of R’s neighbors are not eating,
        // set R’s state to eating and wake it up by 
        // signaling R’s CV
        test((i + 1) % 5);
        test((i + 4) % 5);
    }
  
    test(int i)
    {
  
        if (state[(i + 1) % 5] != eating
            && state[(i + 4) % 5] != eating
            && state[i] == hungry) {
  
            // indicate that I’m eating
            state[i] = eating;
  
            // signal() has no effect during Pickup(),
            // but is important to wake up waiting
            // hungry philosophers during Putdown()
            self[i].signal();
        }
    }
  
    init()
    {
  
        // Execution of Pickup(), Putdown() and test()
        // are all mutually exclusive,
        // i.e. only one at a time can be executing
for
    i = 0 to 4
  
        // Verify that this monitor-based solution is
        // deadlock free and mutually exclusive in that
        // no 2 neighbors can eat simultaneously
        state[i] = thinking;
    }
} // end of monitor

以上程序是餐饮哲学家问题的监视器解决方案。

我们还需要声明

condition self[5];

这允许哲学家 i 在饥饿时延迟自己但无法获得她需要的筷子。我们现在可以描述我们对餐饮哲学家问题的解决方案。筷子的分配由监视器Dining Philosophers控制。每个哲学家在开始吃饭之前,必须调用操作pickup()。这一行为可能会导致哲学家进程的暂停。手术成功完成后,哲学家就可以吃饭了。在此之后,哲学家调用 putdown() 操作。因此,哲学家 i 必须按以下顺序调用操作 pick() 和 putdown():

DiningPhilosophers.pickup(i);
              ...
              eat
              ...
DiningPhilosophers.putdown(i);

很容易证明,该解决方案可确保不会有两个邻居同时进餐,也不会发生死锁。然而,我们注意到哲学家有可能饿死。