哲学家就餐问题
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 }