问题描述
摘自百度
有五个哲学家,他们的生活方式是交替地进行思考和进餐,哲学家们共用一张圆桌,分别坐在周围的五张椅子上,在圆桌上有五个碗和五支筷子,平时哲学家进行思考,饥饿时便试图取其左、右最靠近他的筷子,只有在他拿到两支筷子时才能进餐,该哲学家进餐完毕后,放下左右两只筷子又继续思考。
约束条件
(1)只有拿到两只筷子时,哲学家才能吃饭。
(2)如果筷子已被别人拿走,则必须等别人吃完之后才能拿到筷子。
(3)任一哲学家在自己未拿到两只筷子吃完饭前,不会放下手中已经拿到的筷子。
代码实现
死锁的情况
const int philosopher_num = 5;
std::mutex chopsticks[philosopher_num];
void Philosopher(int pid){
while (true) {
std::unique_lock<std::mutex>lk_l(chopsticks[pid-1]);//取左边的筷子
std::this_thread::sleep_for(100ms);//更快出现死锁(如果有的话)
std::unique_lock<std::mutex>lk_r(chopsticks[pid % philosopher_num]);//取右边的筷子
cout << "哲学家"<<pid<<" 线程id" << std::this_thread::get_id() <<"吃饭了" << endl;
}
}
int main()
{
vector<thread> threads;
for (int i = 0; i < philosopher_num; ++i) {
threads.push_back(thread(Philosopher,i+1));
}
for (int i = 0; i < philosopher_num; ++i) {
threads[i].join();
}
}
解决的情况1
拿两双筷子才吃饭
void Philosopher(int pid) {
while (true) {
std::unique_lock<std::mutex>lk_l(chopsticks[pid - 1],std::defer_lock);//取左边的筷子
std::this_thread::sleep_for(100ms);//更快出现死锁(如果有的话)
std::unique_lock<std::mutex>lk_r(chopsticks[pid % philosopher_num], std::defer_lock);//取右边的筷子
std::lock(lk_l, lk_r);
cout << "哲学家" << pid << " 线程id" << std::this_thread::get_id() << "吃饭了" << endl;
}
}
解决的情况2
只允许4位哲学家同时吃饭
int eating_num = 0;
std::mutex can_eat;
std::condition_variable num_eating;
void Philosopher(int pid) {
while (true) {
//能否吃饭
std::unique_lock<std::mutex>lk_e(can_eat);
num_eating.wait(lk_e, []() {return eating_num < philosopher_num - 1; });
eating_num++;
lk_e.unlock();
std::unique_lock<std::mutex>lk_l(chopsticks[pid - 1]);//取左边的筷子
std::this_thread::sleep_for(100ms);//更快出现死锁(如果有的话)
std::unique_lock<std::mutex>lk_r(chopsticks[pid % philosopher_num]);//取右边的筷子
cout << "哲学家" << pid << " 线程id" << std::this_thread::get_id() << "吃饭了" << endl;
lk_e.lock();
eating_num--;
lk_e.unlock();
num_eating.notify_all();
}
}
解决的情况3
奇数哲学家先拿左边的筷子,偶数哲学家先拿右边筷子。这种方法思想和实现上最简单,不需要使用别的技术。
void Philosopher(int pid){
while (true) {
cout << pid - 1 << endl;
if (pid % 2 == 0) {
std::unique_lock<std::mutex>lk_l(chopsticks[pid - 1]);//取左边的筷子
std::this_thread::sleep_for(100ms);//更快出现死锁(如果有的话)
std::unique_lock<std::mutex>lk_r(chopsticks[pid % philosopher_num]);//取右边的筷子
}
else {
std::unique_lock<std::mutex>lk_r(chopsticks[pid % philosopher_num]);//取右边的筷子
std::this_thread::sleep_for(100ms);//更快出现死锁(如果有的话)
std::unique_lock<std::mutex>lk_l(chopsticks[pid - 1]);//取左边的筷子
}
cout << "哲学家"<<pid<<" 线程id" << std::this_thread::get_id() <<"吃饭了" << endl;
}
}
使用C++11的锁机制解决哲学家吃饭问题太简单了