进程(线程)间同步互斥经典问题(二)哲学家问题

问题描述:


哲学家问题,用于抽象死锁资源耗尽问题:

  • 有n个叉子,n个哲学家,每个哲学家需要两把叉子才能吃饭。
  • 他们围着圆桌坐,也就是每个人左手边右手边都有叉子,但是可能是同一把叉子。
  • 每把叉子同时只能有一个人在用

问题分析:


主要是要考虑死锁资源耗尽的问题:

  • 考虑死锁的情况,每个人都拿起叉子,那么都在睡觉等另一个哲学家放下叉子,那么所有的进程都在睡觉,没有进程能够唤醒,那么陷入死锁
  • 考虑资源耗尽的情况,假设我们通过设置一个时间,让拿起叉子的哲学家自己醒来放下叉子,过一段时间再重新拿起,那么如果所有进程都同时开始执行,也会陷入一种死循环中,与死锁其实也是等同的了。

基本思路:


  • 我们定义fork[MAX]表示每个叉子的状态,每个叉子有两个状态:
    • 脏:初始值,说明叉子没有被用过或者被当前持有者已经用过
    • 净:表示已经被人拿起,但是还没有被用过
  • 那么对于一个饿的科学家,他首先会询问两侧的勺子是否是干净的
    • 如果是脏的,那么说明它已经被当前持有人用过,所以是已经可以被放下,那么我可以拿走,叉子被擦干净。
    • 对于一个干净的叉子,一定是正在等待被使用的,所以我只能睡觉等它使用完后拿走它的脏叉子。
    • 如果两个哲学家竞争同一资源时,让给编号小的哲学家
  • 那么我们为了方便编程,考虑将上面的概念对应到信号量上,因为每个叉子同时只能有一个哲学家操作,才能保证不出现混乱,那么每个叉子需要一个锁,每个哲学家只有在它为脏的时候才能取,所以每个叉子作为一个初值为1的信号量即可。然后加一个互斥锁,防止死锁的出现。

代码如下:


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>

#define MAX 5
#define TRUE 1

#define p(x) sem_wait(&x)
#define v(x) sem_post(&x)

/*
sem_wait(&x)
sem_wait是一个原子操作,它的作用使从信号量的值中减"1",
但它永远会先等待该信好两为一个非零值才开始做减法
sem_post(&x)
在不冲突的情况下,给信号量的值加上一个"1"
*/

sem_t forks[MAX];//记录叉子的状态,0代表干净,1代表脏
pthread_mutex_t mutex;

void init ( )
{
    int i;
    //初始话信号量,叉子的初始状态是脏(1)
    for ( i = 0 ; i < MAX ; i++ )
        sem_init( &forks[i] , 0 , 1 );
}

//描述哲学家的操作的函数
void * philosopher ( void* arg )
{
    int* p = (int*)arg;
    int x = *p;//获得哲学家的id
    while ( TRUE )
    {
        pthread_mutex_lock(&mutex);
        p(forks[x]);//如果叉子脏,那么由当前拿叉子的人擦干净拿来
        p(forks[(x+1)%MAX]);//同上
        printf ( "the %dth philosopher having meal...\n" , x );
        sleep(1);//哲学家吃啊吃...
        v(forks[x]);//吃饭后弄脏了叉子
        v(forks[(x+1)%MAX]);//同上
        pthread_mutex_unlock(&mutex);
        sleep(2);//哲学家等自己变饿
    }
}

int main ( )
{
    init ();//初始化叉子的状态
    pthread_t id[MAX];//用来存每个哲学家线程的id
    int tid[MAX];//用来存每个哲学家的id
    int i;
    for ( i = 0 ; i < MAX ; i++ )
    {
        tid[i] = i;
        //创建一个新的线程
        pthread_create ( &id[i] , NULL , philosopher , &tid[i] );
    }
    //设置主线程阻塞,等待每个哲学家线程
    for ( i = 0 ; i < MAX ; i++ )
        pthread_join ( id[i] , NULL );
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值