哲学家就餐问题
哲学家就餐问题。这是由计算机科学家Dijkstra提出的经典死锁场景。
原版的故事里有五个哲学家,这些哲学家们只做两件事--思考和吃饭,他们思考的时候不需要任何共享资源,但是吃饭的时候就必须使用餐具,而餐桌上的餐具是有限的,原版的故事里,餐具是叉子,吃饭的时候要用两把叉子把面条从碗里捞出来。很显然把叉子换成筷子会更合理,所以:一个哲学家需要两根筷子才能吃饭。
现在引入问题的关键:这些哲学家很穷,只买得起五根筷子。他们坐成一圈,两个人的中间放一根筷子。哲学家吃饭的时候必须同时得到左手边和右手边的筷子。如果他身边的任何一位正在使用筷子,那他只有等着。
哲学家在吃面条时一次只能拿一根筷子,拿完一根筷子后,如果另外一根筷子还没有被拿走,则哲学家拿走一根筷子。最后吃面条,放下餐具,思考。这个问题中,首先假设哲学家吃饭占用0~9秒,思考占用0~9秒。
现在分析一下哲学家就餐问题到底什么时候会出现死锁,很简单!当所有哲学家都是同一边的拿到筷子(比如:左边),则每个哲学家会一直等待旁边的哲学家放下手中的筷子,如此循环则出现了死锁。解决的思路则是,哲学家两边都有筷子的时候才拿起筷子,否则继续思考。这样保证了不会出现有哲学家只拿到一根筷子,然后一直在等待的问题。下面则编写代码解决这个问题。
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <time.h>
#define NUM 5
struct phi
{
int left;
int right;
};
int chopsticks[NUM] = {1, 2, 3, 4, 5};
struct phi philosopthers[NUM];
pthread_mutex_t chopstick1, chopstick2, chopstick3, chopstick4, chopstick5;
void var_init ( void )
{
int i = 0;
for ( i = 0; i < NUM; i++ )
{
philosopthers[i].left = 0;
philosopthers[i].right = 0;
}
}
void *philosopther1 ( void *var )
{
while ( 1 )
{
sleep (rand () % 10 );
pthread_mutex_lock ( &chopstick5 );
if ( chopsticks[4] > 0 )
{
printf ( "pthilosoptherA fetches chopstick 5\n" );
chopsticks[4] = 0;
philosopthers[0].left = 1;
}
pthread_mutex_unlock ( &chopstick5 );
pthread_mutex_lock ( &chopstick1 );
if ( chopsticks[0] > 0 && chopsticks[4] == 0)
{
printf ( "philosoptherA fetches chopstick 1\n" );
chopsticks[0] = 0;
philosopthers[0].right = 1;
}
pthread_mutex_unlock ( &chopstick1 );
if ( philosopthers[0].left == 1 && philosopthers[0].right == 1 )
{
sleep ( rand () % 10 );
chopsticks[4] = 1;
chopsticks[0] = 1;
philosopthers[0].left = 0;
philosopthers[0].right = 0;
}
}
return NULL;
}
void *philosopther2 ( void *var )
{
while ( 1 )
{
sleep (rand () % 10 );
pthread_mutex_lock ( &chopstick1 );
if ( chopsticks[0] > 0 )
{
printf ( "pthilosoptherB fetches chopstick 1\n" );
chopsticks[0] = 0;
philosopthers[1].left = 1;
}
pthread_mutex_unlock ( &chopstick1 );
pthread_mutex_lock ( &chopstick2 );
if ( chopsticks[1] > 0 && chopsticks[0] == 0)
{
printf ( "philosoptherB fetches chopstick 2\n" );
chopsticks[1] = 0;
philosopthers[1].right = 1;
}
pthread_mutex_unlock ( &chopstick2 );
if ( philosopthers[1].left == 1 && philosopthers[1].right == 1 )
{
sleep ( rand () % 10 );
chopsticks[0] = 1;
chopsticks[1] = 1;
philosopthers[1].left = 0;
philosopthers[1].right = 0;
}
}
return NULL;
}
void *philosopther3 ( void *var )
{
while ( 1 )
{
sleep (rand () % 10 );
pthread_mutex_lock ( &chopstick2 );
if ( chopsticks[1] > 0 )
{
printf ( "pthilosoptherC fetches chopstick 2\n" );
chopsticks[1] = 0;
philosopthers[2].left = 1;
}
pthread_mutex_unlock ( &chopstick2 );
pthread_mutex_lock ( &chopstick3 );
if ( chopsticks[2] > 0 && chopsticks[1] == 0)
{
printf ( "philosoptherC fetches chopstick 3\n" );
chopsticks[2] = 0;
philosopthers[2].right = 1;
}
pthread_mutex_unlock ( &chopstick3 );
if ( philosopthers[2].left == 1 && philosopthers[2].right == 1 )
{
sleep ( rand () % 10 );
chopsticks[1] = 1;
chopsticks[2] = 1;
philosopthers[2].left = 0;
philosopthers[2].right = 0;
}
}
return NULL;
}
void *philosopther4 ( void *var )
{
while ( 1 )
{
sleep (rand () % 10 );
pthread_mutex_lock ( &chopstick3 );
if ( chopsticks[2] > 0 )
{
printf ( "pthilosoptherD fetches chopstick 3\n" );
chopsticks[2] = 0;
philosopthers[3].left = 1;
}
pthread_mutex_unlock ( &chopstick3 );
pthread_mutex_lock ( &chopstick4 );
if ( chopsticks[3] > 0 && chopsticks[2] == 0)
{
printf ( "philosoptherD fetches chopstick 4\n" );
chopsticks[3] = 0;
philosopthers[3].right = 1;
}
pthread_mutex_unlock ( &chopstick4 );
if ( philosopthers[3].left == 1 && philosopthers[3].right == 1 )
{
sleep ( rand () % 10 );
chopsticks[2] = 1;
chopsticks[3] = 1;
philosopthers[3].left = 0;
philosopthers[3].right = 0;
}
}
return NULL;
}
void *philosopther5 ( void *var )
{
while ( 1 )
{
sleep (rand () % 10 );
pthread_mutex_lock ( &chopstick4 );
if ( chopsticks[3] > 0 )
{
printf ( "pthilosoptherE fetches chopstick 4\n" );
chopsticks[3] = 0;
philosopthers[4].left = 1;
}
pthread_mutex_unlock ( &chopstick4 );
pthread_mutex_lock ( &chopstick5 );
if ( chopsticks[4] > 0 && chopsticks[3] == 0)
{
printf ( "philosoptherE fetches chopstick 5\n" );
chopsticks[4] = 0;
philosopthers[4].right = 1;
}
pthread_mutex_unlock ( &chopstick5 );
if ( philosopthers[4].left == 1 && philosopthers[4].right == 1 )
{
sleep ( rand () % 10 );
chopsticks[3] = 1;
chopsticks[4] = 1;
philosopthers[4].left = 0;
philosopthers[4].right = 0;
}
}
return NULL;
}
int main ( int argc, char *argv[] )
{
pthread_t tidA, tidB, tidC, tidD, tidE;
srand ( time ( NULL ) );
var_init ();
pthread_mutex_init ( &chopstick1, NULL );
pthread_mutex_init ( &chopstick2, NULL );
pthread_mutex_init ( &chopstick3, NULL );
pthread_mutex_init ( &chopstick4, NULL );
pthread_mutex_init ( &chopstick5, NULL );
pthread_create ( &tidA, NULL, philosopther1, NULL );
pthread_create ( &tidB, NULL, philosopther2, NULL );
pthread_create ( &tidC, NULL, philosopther3, NULL );
pthread_create ( &tidD, NULL, philosopther4, NULL );
pthread_create ( &tidE, NULL, philosopther5, NULL );
pthread_join ( tidA, NULL );
pthread_join ( tidB, NULL );
pthread_join ( tidC, NULL );
pthread_join ( tidD, NULL );
pthread_join ( tidE, NULL );
return 0;
}