不按顺序吃法,将死锁的“循环等待”条件破坏即可,我的做法是奇数先拿左手筷子,偶数先拿右手筷子。
代码如下
#include <iostream>
#include <thread>
#include <mutex>
#include <vector>
#include <set>
#include <future>
const int num_philosophers = 5;
std::atomic<int> cnt(0);
// 筷子类,用于控制哲学家的行为
class Chopstick {
private:
std::mutex mutex; // 互斥锁,用于保证只有一个哲学家能够拿起这根筷子
public:
// 拿起筷子
void pickUp() {
mutex.lock();
}
// 放下筷子
void putDown() {
mutex.unlock();
}
};
// 哲学家类
class Philosopher {
private:
int id; // 哲学家的编号
Chopstick& firstChopstick; // 第一双获取的筷子
Chopstick& secondChopstick; // 第二双获取的筷子
public:
// 构造函数
Philosopher(int id, Chopstick& first_chopstick, Chopstick& second_chopstick)
: id(id), firstChopstick(first_chopstick), secondChopstick(second_chopstick) {}
// 进餐的函数
void dine() {
while(1)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
// 开始进餐
firstChopstick.pickUp();
secondChopstick.pickUp();
cnt.fetch_add(1);
std::cout << "哲学家 " << id << " 完成用餐. 当前计数:" << cnt.load() << std::endl;
// 完成进餐
firstChopstick.putDown();
secondChopstick.putDown();
}
}
};
int main() {
std::vector<Chopstick> chopsticks(num_philosophers); // 创建筷子
std::vector<Philosopher> philosophers; // 创建哲学家
// 创建哲学家对象并放入容器中
for (int i = 0; i < num_philosophers; ++i) {
if (i % 2)
philosophers.emplace_back(i, chopsticks[i], chopsticks[(i + 1) % num_philosophers]);
else
philosophers.emplace_back(i, chopsticks[(i + 1) % num_philosophers], chopsticks[i]);
}
// 启动线程
std::vector<std::thread> threads;
for (int i = num_philosophers - 1; i >= 0; --i) {
threads.emplace_back(&Philosopher::dine, &philosophers[i]);
}
// 等待所有线程结束
for (auto& thread : threads) {
thread.join();
}
return 0;
}
需要按顺序吃饭时。这里使用wait
加notify_*
实现
wait notify就是锁,被notify唤醒了才会去拿筷子,一次只会有一个线程在跑,根本就不需要大锁,换成5把小锁即可。筷子也不需要锁。
#include <iostream>
#include <thread>
#include <mutex>
#include <vector>
#include <set>
#include <future>
std::mutex cnt_mtx;
const int num_philosophers = 5;
std::vector<std::condition_variable> cv(num_philosophers);
std::vector<std::mutex> mtx(num_philosophers);
std::vector<int>ready(num_philosophers, 0);
std::atomic<int> cnt(0);
// 筷子类,用于控制哲学家的行为
class Chopstick {
public:
// 拿起筷子
void pickUp() {
}
// 放下筷子
void putDown() {
}
};
// 哲学家类
class Philosopher {
private:
int id; // 哲学家的编号
Chopstick& firstChopstick; // 第一双获取的筷子
Chopstick& secondChopstick; // 第二双获取的筷子
public:
// 构造函数
Philosopher(int id, Chopstick& first_chopstick, Chopstick& second_chopstick)
: id(id), firstChopstick(first_chopstick), secondChopstick(second_chopstick) {}
// 进餐的函数
void dine() {
while(1)
{
std::unique_lock<std::mutex> lck(mtx[id]);
while(ready[id] != 1) cv[id].wait(lck);
ready[id] = 0;
std::this_thread::sleep_for(std::chrono::milliseconds(1));
// 开始进餐
firstChopstick.pickUp();
secondChopstick.pickUp();
cnt.fetch_add(1);
std::cout << "哲学家 " << id << " 完成用餐. 当前计数:" << cnt.load() << std::endl;
ready[(id+1) % num_philosophers] = 1;
cv[(id+1) % num_philosophers].notify_one();
// 完成进餐
firstChopstick.putDown();
secondChopstick.putDown();
}
}
};
void go() {
std::this_thread::sleep_for(std::chrono::milliseconds(1000)); //要sleep,保证在所有线程创建完成之后才运行
std::unique_lock<std::mutex> lck(mtx[num_philosophers-1]);
ready[0] = 1;
cv[0].notify_one();
}
int main() {
std::vector<Chopstick> chopsticks(num_philosophers); // 创建筷子
std::vector<Philosopher> philosophers; // 创建哲学家
// 创建哲学家对象并放入容器中
for (int i = 0; i < num_philosophers; ++i) {
if (i % 2)
philosophers.emplace_back(i, chopsticks[i], chopsticks[(i + 1) % num_philosophers]);
else
philosophers.emplace_back(i, chopsticks[(i + 1) % num_philosophers], chopsticks[i]);
}
// 启动线程
std::vector<std::thread> threads;
for (int i = num_philosophers - 1; i >= 0; --i) {
threads.emplace_back(&Philosopher::dine, &philosophers[i]);
}
std::cout << "main: " << cnt.load() << std::endl;
go();
// 等待所有线程结束
for (auto& thread : threads) {
thread.join();
}
return 0;
}