本实验的目的是为了模拟并结局不死锁的哲学家问题,采用C++语言进行编写程序,程序中使用“控制进食的人的数量”的方式来预防死锁,并通过多线程并发的方式来模拟哲学家决策以及控制程序。(运行代码需要支持C++11及以上的编译器)
#include <iostream>
#include <thread>
#include <mutex>
#include <random>
//using namespace std;
const int NUM_PHILOSOPHERS = 5;//定义哲学家的数量
int fork[NUM_PHILOSOPHERS]={0};
int count = 0,now = 0; // count表示已经进食了的哲学家的数量;now表示当前正在参与进食的哲学家的数量,用于控制预防死锁,模拟信号量
bool eating[NUM_PHILOSOPHERS] = {false}; // 表示每个哲学家的进食状态,进食过表示已经饱了,再发出进食指令将不再执行
char run='r';//控制模拟程序进行
int fwait(int n)//模拟wait
{
if(!fork[n])
{
fork[n]=1;
return 1;
}else
{
return 0;
}
}
void fsignal(int n)//模拟signal
{
fork[n]=0;
}
bool checkeat(bool eating[])//检测所有哲学家的进食情况,如果所有哲学家均已进食过,则返回true
{
for(int i=0; i < NUM_PHILOSOPHERS; ++i)//遍历所有哲学家的状态
{
if(!eating[i])//如果遍历到一个处于饥饿状态的哲学家,就放回false。
{
return false;
}
}
return true;
}
void initeat(bool eating[])
{
for(int i=0; i < NUM_PHILOSOPHERS; ++i)
{
eating[i]=false;
}
}
void pcbctrl(int i)//控制线程
{
std::cout<<"欢迎使用哲学家问题模拟程序,该程序使用“r”和“e”字符控制运行与结束,其他字符表示暂停。"<<std::endl;
while (true)
{
std::cin>>run;//通过run来控制程序
if(run=='e')
{
std::cout << "!Philosopher program exit!" << std::endl;
break;
}
if(run=='r')
{
initeat(eating);//初始化eating
count=0;//初始化已经吃了饭的哲学家的数量
}
if(checkeat(eating))
{
std::cout << "****!所有哲学家均已完成进食!****" << count << std::endl;//所有哲学家均已完成进食
}
}
}
void philosopher(int id) {
std::this_thread::sleep_for(std::chrono::milliseconds(3000));//wait for 3 seconds
int left_fork = id;//摆在左边的叉子
int right_fork = (id + 1) % NUM_PHILOSOPHERS;//摆在右边的叉子
while (true) {//当进食次数或者哲学家进食状态其中一个为真,则继续循环
if(run=='e')
{
break;
}
else if(run=='r'){
int choice = rand(); // 生成随机数,使用随机数来控制哲学家进食或者思考
//模拟哲学家决策
if (choice % 2 == 1) //模拟选择思考操作
{
std::cout << "Philosopher " << id << " is thinking" << std::endl;// 模拟哲学家思考
std::this_thread::sleep_for(std::chrono::milliseconds(2000));//模拟思考时间
}
else if(!eating[id])//模拟选择吃饭操作,判断当前是否处于为进食的状态,若处于未进食的状态,则开始进食操作
{
bool flag=true;//用于控制进食循环,知道进食成功
while(flag)
{
std::cout << "Philosopher " << id << " feel hungry!****" << std::endl;//模拟哲学家饥饿状态
if(now<NUM_PHILOSOPHERS&&!checkeat(eating))
{
int l=0,r=0,t1=0,t2=0;
now++;//当前正在参与进食的哲学家+1
while(l==0||r==0)
{
if(l==0){l= fwait(left_fork);}
if(l==1&&t1==0){
++t1;
std::cout << "Philosopher " << id << " took the left fork" << std::endl;
}
if(r==0){r= fwait(right_fork);}
if(r==1&&t2==0){
++t2;
std::cout << "Philosopher " << id << " took the right fork" << std::endl;
}
if(r==1&&l==1){
std::cout << "Philosopher " << id << " is eating" << std::endl;
eating[id] = true;//该哲学家已吃饱
count++;//进食次数+1
std::this_thread::sleep_for(std::chrono::milliseconds(2000));//模拟哲学家吃饭
fsignal(left_fork);
fsignal(right_fork);
now--;//正在进食的哲学家-1
flag = false;//结束循环
break;
}
//forks[left_fork].unlock();
//forks[right_fork].unlock();
}
std::cout << "Philosopher " << id << " is full!**" << std::endl;
}
}
}else
{
std::cout << "Philosopher " << id << " is full!**" << std::endl;
}
}
}
}
int main() {
std::thread philosophers[NUM_PHILOSOPHERS];//定义哲学家线程
std::thread pcbctrl1;//定义控制线程
pcbctrl1= std::thread(pcbctrl,1);
// 创建哲学家线程
for (int i = 0; i < NUM_PHILOSOPHERS; ++i) {
philosophers[i] = std::thread(philosopher, i);
}
// 加入哲学家线程
for (int i = 0; i < NUM_PHILOSOPHERS; ++i) {
philosophers[i].join();
if(i==NUM_PHILOSOPHERS-1){//加入控制线程
pcbctrl1.join();
}
}
std::cout<<"程序结束!"<<std::endl;
return 0;
}