使用二进制信号量用餐哲学家

Posted

技术标签:

【中文标题】使用二进制信号量用餐哲学家【英文标题】:Dining philosophers using binary semaphores 【发布时间】:2018-01-21 06:06:42 【问题描述】:

这个伪代码能否以最大并行度解决哲学家进餐问题?这里mutex是一个初始化为1的二进制信号量。假设叉子的编号从0到(N-1)。从 0 到 (N-1) 共有 N 个哲学家。

void philosopher(int i)    // ith philosopher
   
   while (true)
   
        think();
        down(&mutex);          // acquire lock
        take_fork(i);            // take left fork
        take_fork((i+1)%N);        // take right fork
        up(&mutex);          // release the lock
        eat();
        down(&mutex);       // acquire lock
        put_fork(i);
        put_fork((i+1)%N);
        up(&mutex);        // release the lock
       

这应该以最大的并行度解决哲学家进餐问题,因为在一位哲学家获得两个分叉后,锁就会被释放。但会吗?会不会有活力的问题?我很困惑。

【问题讨论】:

当哲学家获得互斥体并发现他的右叉被占用时会发生什么? take_fork 会失败从而导致左叉未释放吗? 这应该是不可能的,因为互斥锁已经被其他哲学家关闭了。 @DmitriChubarov 【参考方案1】:

为了回答你的问题,我想提供一些似乎导致你的哲学家进入不受欢迎状态的事件。

考虑一个具有 N>2 个哲学家 Ph(0),...,Ph(N-1) 和以下动作序列的系统:

Ph(1).think();
Ph(0).think();
Ph(1).down(&mutex);
Ph(1).take_fork(1);
Ph(1).take_fork(2);
Ph(1).up(&mutex);
Ph(0).down(&mutex);
Ph(0).take_fork(0);
Ph(0).take_fork(1);

回想一下fork(1) 已经被Ph(1) 获取。现在根据take_fork() 的语义,可能会发生不同的行为。

如果无法获得分叉,take_fork() 立即失败,则永远不会释放 fork(0)

如果take_fork() 挂起直到资源被释放,那么互斥锁将永远不会被释放,其他哲学家都无法取得进展,因此一次只有一个哲学家在吃饭。

【讨论】:

以上是关于使用二进制信号量用餐哲学家的主要内容,如果未能解决你的问题,请参考以下文章

如何在 C++ 中增加信号量值,以解决哲学家用餐问题

使用信号量 (BACI) 就餐哲学家

Java并发编程系列之Semaphore详解

使用信号量的餐饮哲学家(BACI)

操作系统第6次实验报告:使用信号量解决进程互斥访问

操作系统第6次实验报告:使用信号量解决进程互斥访问