哲学家就餐问题(如何避免死锁)(多线程版)

深渊向深渊呼唤

哲学家就餐问题

多线程编程中,常常会遇到线程间访问共享资源的问题,如果处理不当则会发生死锁,某一个线程可能永远访问不到共享资源。
为了避免死锁的发生,提出哲学家就餐问题。

下面展示一些代码片段

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <sys/mman.h>

/* 多线程之间通过互斥锁实现哲学家就餐问题(如何避免死锁) 
    得到两把锁则进餐,只得到第一把锁,得不到第二把锁则释放已经拥有的第一把锁

*/
pthread_mutex_t mutex[5];

void *tfun(void *arg)
{
    int left,right;
    int i = (int)arg;
    int ret;

    if(i == 4)
    {
        left = 0,right = i;
    }
    else
    {
        left = i;right = i+1;
    }
    while(1)
    {

        pthread_mutex_lock(&mutex[left]);
        //利用trylock非阻塞函数,加锁失败则立即返回,不则塞
        ret = pthread_mutex_trylock(&mutex[right]);
        if(ret == 0)
        {
            printf("%dth thread get lock\n",i);
            sleep(1);   //模拟哲学家进餐过程
            
            pthread_mutex_unlock(&mutex[right]);
            printf("%dth thread unlock right %d----------------\n",i,right);
            pthread_mutex_unlock(&mutex[left]);
            printf("%dth thread unlock left %d----------------\n",i,left);
            sleep(1);
        }
        else
        {
            
            pthread_mutex_unlock(&mutex[left]);
            printf("%dth thread unlock left %d-----------------------------------\n",i,left);
            sleep(1);
        }

    }

    pthread_exit(NULL);
}


int main()
{
    pthread_t tid[5];//定义五个互斥锁-对应5只筷子
    int i;

    for(i=0;i<5;i++)
    {
    	//互斥锁初始化
        pthread_mutex_init(&mutex[i],NULL);
    }

    for(i=0;i<5;i++)
    {
    	//创建五个线程--对应5个哲学家。编号为0-4
        pthread_create(&tid[i],NULL,tfun,(void *)i);
    }
    
    for(i=0;i<5;i++)
    {
        pthread_join(tid[i],NULL);
    }
    
    for(i=0;i<5;i++)
    {
        pthread_mutex_destroy(&mutex[i]);
    }

    return 0;
}

振荡:如果每个人都攥着自己左手的锁,尝试去拿右手锁,拿不到则将锁释放。过会儿五个人又同时再攥着左手锁尝试拿右手锁,依然拿不到。如此往复形成另外一种极端死锁的现象——振荡。
程序中哲学家都先去拿左边的筷子,再拿右边的筷子,为了避免振荡,第四个哲学家反其道而行,先拿右边的筷子,再拿左边的筷子。
两个筷子都拿到则进餐,如果只拿到第一个筷子,没有拿到第二个筷子,则释放已有的筷子。

避免死锁的方法:
1:若得不到所有所需的资源时,放弃已经获得的资源,等待。
2:保证资源的获取顺序,要求每个线程获取资源的顺序一致,如:A获取顺序1、2、3;B顺序也应该是1、2、3.若B为3、2、1则易出现死锁的现象。

栏目