哲学家就餐问题

1. 使用PV信号量使就餐互斥方案的缺点

将就餐看成必须互斥访问的临界资源, 这样会造成资源(叉子)的浪费.五把叉子, 一次应该有两个不相邻的哲学家同时进餐.

 

2. 算法实现

数据结构

 1 #define N 5 // 哲学家个数
 2 #define LEFT i-1 // 第i个哲学家的左邻居
 3 #define RIGHT (i+1)%N // 第i个哲学家的右邻居
 4 #define THINKING 0 // 思考状态
 5 #define HUNGRY 1 // 饥饿状态
 6 #define EATING 2 // 进餐状态
 7 int state[N]; // 记录每个人的状态 0 1 2
 8 
 9 semaphore mutex = 1; // 保证操作state[N]是互斥的
10 semaphore s[N] = 0; // 一个哲学家吃饱之后, 需要唤醒邻居, 同步

 

主函数

 1 void philosopher(int i)
 2 {
 3     while (true)
 4     {
 5         think(); // 思考
 6         take_forks(i); // 尝试拿两把叉子
 7         eat(); // 进餐
 8         put_forks(i); // 放下两把叉子
 9     }
10 }

 

功能: 尝试获取两把叉子, 获取不到便阻塞

 1 // i为哲学家编号
 2 void take_forks(int i)
 3 {
 4     // 其它哲学家判断邻居时, 会读取state[N], 所以应该对state[i]进行互斥保护
 5     P(mutex);
 6     // 我饿了!
 7     state[i] = HUNGRY;
 8     // 尝试拿两把叉子
 9     test_take_left_right_forks(i);
10     V(mutex);
11     // 若拿到叉子, 这里就不会被阻塞, 反之同理
12     P(s[i]);
13 }

 

功能: 放下两把叉子, 并尝试唤醒邻居

 1 void put_forks(int i)
 2 {
 3     P(mutex);
 4     // 放下两把叉子
 5     state[i] = THINKING;
 6     // 左邻居是否可以进餐
 7     test_take_left_right_forks(LEFT);
 8     // 右邻居是否可以进餐
 9     test_take_left_right_forks(RIGHT);
10     V(mutex);
11 }

 

拿叉子策略

 1 void test_take_left_right_forks(int i)
 2 {
 3     if (state[i] == HUNGRY && state[LEFT] != EATING && state[RIGHT] != EATING)
 4     {
 5         // 正在进食状态
 6         state[i] = EATING;
 7         // 通知自己进食
 8         V(s[i]);
 9     }
10 }

 

posted on 2018-11-18 13:14  ert999  阅读(314)  评论(0编辑  收藏  举报

导航