📅  最后修改于: 2020-12-15 09:32:10             🧑  作者: Mango
餐饮哲学家的问题是经典的同步问题,即五个哲学家围坐在一张圆桌旁,他们的工作是交替思考和吃饭。一碗面条放在桌子中央,每个哲学家用五根筷子。要吃一个哲学家,既需要左右筷子。只有当哲学家的左,右筷子都可用时,他才能进食。如果哲学家的左,右筷子都不可用,则哲学家放下他们的(左或右)筷子,然后重新开始思考。
餐饮哲学家展示了大量并发控制问题,因此这是一个经典的同步问题。
围坐在桌子旁的五位哲学家
餐饮哲学家问题-让我们用以下代码了解餐饮哲学家问题,我们使用图1作为参考,以使您准确地理解问题。五个哲学家分别表示为P0,P1,P2,P3和P4,五个筷子分别表示为C0,C1,C2,C3和C4。
Void Philosopher
{
while(1)
{
take_chopstick[i];
take_chopstick[ (i+1) % 5] ;
. .
. EATING THE NOODLE
.
put_chopstick[i] );
put_chopstick[ (i+1) % 5] ;
.
. THINKING
}
}
让我们讨论上面的代码:
假设哲学家P0要吃饭,它将进入Philosopher()函数,并执行take_chopstick [i];通过执行此操作,在执行take_chopstick [(i + 1)%5]之后,它将保持C0筷子。通过这样做,它握住了C1筷子(因为i = 0,因此(0 + 1)%5 = 1)
同样,假设现在哲学家P1要吃东西,它将进入Philosopher()函数,并执行take_chopstick [i];通过执行此操作,在执行take_chopstick [(i + 1)%5]之后,它会握住C1筷子。通过这样做,它握住了C2筷子(因为i = 1,因此(1 + 1)%5 = 2)
但是实际上筷子C1不可用,因为它已经被哲学家P0所采用,因此上述代码会产生问题并产生竞争条件。
我们使用信号量来代表筷子,这确实可以解决餐饮哲学家问题。将使用“等待”和“信号”操作来解决“用餐哲学家”问题,可以执行摘筷子的等待操作,而可以释放筷子的信号量。
信号量:信号量是S中的一个整数变量,除初始化外,信号量仅可通过两个标准原子操作-wait和signal访问,其定义如下:
1. wait( S )
{
while( S <= 0) ;
S--;
}
2. signal( S )
{
S++;
}
从以上wait的定义中可以清楚地看出,如果S <= 0,则它将进入无限循环(由于分号;在while循环之后)。信号的工作是增加S的值。
筷子的结构是一个信号量数组,如下所示:
semaphore C[5];
最初,信号量C0,C1,C2,C3和C4的每个元素都将初始化为1,因为筷子在桌子上,任何哲学家都没有捡起。
让我们通过使用信号量操作wait和signal来修改Dining哲学家问题的上述代码,所需的代码如下所示:
void Philosopher
{
while(1)
{
Wait( take_chopstickC[i] );
Wait( take_chopstickC[(i+1) % 5] ) ;
. .
. EATING THE NOODLE
.
Signal( put_chopstickC[i] );
Signal( put_chopstickC[ (i+1) % 5] ) ;
.
. THINKING
}
}
在上面的代码中,对take_chopstickC [i]和take_chopstickC [(i + 1)%5]执行第一次等待操作。这表明哲学家我从左和右拿起了筷子。然后执行进食函数。
一旦哲学家i进食完成,就对take_chopstickC [i]和take_chopstickC [(i + 1)%5]进行信号操作。这表明我吃过哲学家并放下了左右筷子。最后,哲学家开始重新思考。
令i = 0(初始值),假设哲学家P0要吃东西,它将进入Philosopher()函数,并执行Wait(take_chopstickC [i]);通过这样做,它将保持C0筷子并将信号量C0减小为0 ,然后执行Wait(take_chopstickC [(i + 1)%5]);通过这样做,它握住了C1筷子(因为i = 0,因此(0 + 1)%5 = 1)并将信号量C1减小为0
同样,假设现在哲学家P1要吃饭,它将进入Philosopher()函数,并执行Wait(take_chopstickC [i]);通过这样做,它将尝试握住C1筷子,但将无法执行此操作,因为信号器C1的值已被哲学家P0设置为0,因此它将进入无限循环,因此哲学家P1不会这样做能够拿起筷子C1,而如果哲学家P2想吃饭,它将进入Philosopher()函数,并执行Wait(take_chopstickC [i]);通过这样做,它握住了C2筷子并将信号量C2减小为0,之后,它执行Wait(take_chopstickC [(i + 1)%5]);通过这样做,它将握住C3筷子(因为i = 2,因此(2 + 1)%5 = 3)并将信号量C3减小为0。
因此,以上代码为餐饮哲学家的问题提供了解决方案,只有当哲学家的左,右筷子都可用时,哲学家才能进餐,而哲学家则需要等待。同样,两个独立的哲学家可以同时进食(即,哲学家P0和P2,P1和P3以及P2和P4可以同时进食,因为它们都是独立的过程,并且遵循上述用餐哲学家问题的约束)
通过上述用餐哲学家问题的解决方案,我们证明了没有两个相邻的哲学家可以在同一时间进餐。上述解决方案的缺点是该解决方案可能导致死锁状态。如果所有哲学家都同时拿起左筷子,就会发生这种情况,这将导致僵局,并且所有哲学家都无法进食。
为了避免死锁,一些解决方案如下:
问题的设计是为了说明避免死锁的挑战,系统的死锁状态是无法进行系统升级的状态。考虑一个指导每个哲学家的行为如下的提议: