您的位置:首页 > 其它

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

2015-11-05 00:58 525 查看

问题描述:

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

有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 );
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息