哲学家就餐问题(条件变量)

        1965年,著名计算机科学家艾兹格·迪科斯彻,提出并解决了一个他称之为哲学家就餐的同步问题。

        从那时起,每个发明同步原语的人,都希望通过解决哲学家就餐问题来展示其同步原语的精妙之处。

这个问题可以简单地描述如下:

        五个哲学家围坐在一张圆桌周围,每个哲学家面前都有一盘通心粉。由于通心粉很滑,所以需要两把叉子才能夹住。
        相邻两个盘子之间放有一把叉子。哲学家的生活中有两种交替活动时段:即吃饭和思考。
        当一个哲学家觉得饿了时,他就试图分两次去取其左边和右边的叉子,每次拿一把,但不分次序。
        如果成功地得到了两把叉子,就开始吃饭,吃完后放下叉子继续思考。

哲学家就餐问题(条件变量)_第1张图片
关键问题:
能为每一个哲学家写一段描述其行为的程序,且决不会死锁吗?

提示:
        如果五位哲学家同时拿起左面的叉子,就没有人能够拿到他们各自右面的叉子,于是发生了死锁。
        如果每位哲学家在拿到左面的叉子后,发现其右面的叉子不可用,那么就先放下左面的叉的,等待一段时间,再重复此过程。
        可能在某一个瞬间,所有的哲学家都同时拿起左叉,看到右叉不可用,又都放下左叉,等一会儿,又都同时拿起左叉,如此重复下去。虽然程序在不停运行,都无法取得进展,于是发生了活锁。

思路:
        解决问题的关键在于,必须保证任意一位哲学家只有在其左右两个邻居都没有在进餐时,才允许其进入进餐状态。
        这样做不仅不会发生死锁,而且对于任意数量的哲学家都能获得最大限度的并行性。

#include 
#include 
#include 
#include 
#include 

#define DINNERS 5

char *dinners[DINNERS] = {
     "亚里士多德","柏拉图","牛顿","马哥白尼","伏尔泰"};

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

pthread_cond_t conds[DINNERS] = {
     
    PTHREAD_COND_INITIALIZER,    
    PTHREAD_COND_INITIALIZER,    
    PTHREAD_COND_INITIALIZER,    
    PTHREAD_COND_INITIALIZER,    
    PTHREAD_COND_INITIALIZER    
};

typedef enum STATUS{
     
    EAT,  //吃饭
    HUN,  //挨饿
    THI   //思考
}STA;

STA status[DINNERS] = {
     THI,THI,THI,THI,THI};

void eat(int i){
     
    int r = (i+1)%DINNERS;
    int l = (i-1+DINNERS)%DINNERS;
    pthread_mutex_lock(&mutex);
    while(status[r] == EAT || status[l] == EAT){
     
        status[i] = HUN;
        printf("%s 正在挨饿...\n",dinners[i]);
        pthread_cond_wait(&conds[i],&mutex);
    }
    status[i] = EAT;
    printf("%s 正在就餐....\n",dinners[i]);
    pthread_mutex_unlock(&mutex);
    usleep((rand()%100) *1000);
}
void think(int i){
     
    int r = (i+1)%DINNERS;
    int l = (i-1+DINNERS)%DINNERS;
    pthread_mutex_lock(&mutex);
    printf("%s 吃饱了,开始思考问题了!\n",dinners[i]);
    status[i] = THI;
    pthread_cond_signal(&conds[r]);
    pthread_cond_signal(&conds[l]);
    pthread_mutex_unlock(&mutex);
    usleep((rand()%100)*1000);
}

void *dinner(void *arg){
     
    int i = (int)(arg);    
    for(;;){
     
        eat(i);
        think(i);
    }
}


int main(){
     
    srand(time(NULL));
    pthread_t ids[DINNERS];
    int i;
    for(i=0;i<DINNERS;i++){
     
        pthread_create(&ids[i],NULL,dinner,(void*)i);    
    }
    getchar();
    return 0;    
}

你可能感兴趣的:(多线程,c语言)