Code:
#include <iostream>
#include <thread>
#include <mutex>
#include <array>
#include <random>
#include <chrono>
#include <vector>
#include <ctime>
const int NumP=5;
class Philosopher
{
public:
Philosopher(int n_,int health_=200):n(n_),health(health_)
{
chops.first = n;
chops.second = (n + 1) % NumP;
randgen.seed((n+1)* static_cast<unsigned int>(std::time(nullptr)));
for(int i=0;i<NumP;++i)
{
logtab[i]=[]
(int n){std::string temp;while(n--)temp+="\t\t\t";return temp;}
(i);//3 tabs for a coloumn in the log output, change as required for your terminal
}
};
void operator()(std::array<std::mutex,NumP>& locks)
{
while(true)
{
std::chrono::milliseconds sleep_time ((randgen()%10+1)*100),eat_time((randgen()%10+1)*100);
log("Thinking");
std::this_thread::sleep_for(sleep_time);
bool hungry=true;
int temp_health=health;
int first,second;
while(hungry)
{
bool choice =randgen() < (randgen.max()+1)/2 ;
first =chops.first;
second = chops.second;
if(choice)//The order of choice becomes random
std::swap(first,second);
if(locks[first].try_lock())
if(locks[second].try_lock())
{
log("Eating");
std::this_thread::sleep_for(eat_time);
hungry=false;
break;
}
else locks[first].unlock();//Putting the first one down too
std::this_thread::sleep_for(std::chrono::milliseconds(20));//Try again
temp_health--;
if(!temp_health)
{
log("Leaving");//Becasue of lack of food in the seminar!
return;
}
}
locks[first].unlock();
locks[second].unlock();
}
}
void log(const std::string& fooing)
{
while(!cout_lock.try_lock())
std::this_thread::sleep_for(std::chrono::milliseconds(20));
std::cout<<logtab[n]<<"Philosopher "<<n<<" "<<fooing<<std::endl;
cout_lock.unlock();
}
private:
int n;//'Roll' no. of the philosophers!
std::pair<int,int> chops; // ^--- chops
std::mt19937 randgen;//Typedef of the Mersenne Twister engine with some weird looking parameters
int health;//Each philosopher tries to eat health no. of times and then gets annoyed and leaves.
std::array<std::string,NumP> logtab;
static std::mutex cout_lock;
};
std::mutex Philosopher::cout_lock;
int main()
{
std::array<std::mutex,NumP> chops;
std::vector<std::thread> threads;
for(int i=0;i<NumP;++i)
threads.push_back
(
std::thread
(
Philosopher(i),
std::ref(chops)
)
);
for(auto& t:threads)
t.join();
return 0;
}