Dining Philosophers...with threads.
I just came accross this problem..and thought I'd try my own solution.
Basically each of them thinks and eats for a random amount of time.
One eats only when both chops are available, otherwise they put it down. The choice about which chopstick to pick up first is random.
So far, It has been running for 20 mins without stopping (deadlock..?) .
That makes me reasonable sure that it 'works'.
See any bug ? ..or find a case in which it stops working ?
Code:
#include <iostream>
#include <thread>
#include <mutex>
#include <array>
#include <random>
#include <chrono>
#include <vector>
const int nump=5;
class Philosopher
{
public:
Philosopher(int n_):n(n_)
{
chops.first = n;
chops.second = (n<4)?n+1:0;
randgen.seed(n);
};
void operator()(std::array<std::mutex,nump>& locks)
{
while(true)
{
std::chrono::milliseconds sleep_time (randgen()%10000),eat_time(randgen()%10000);
log("Thinking");
std::this_thread::sleep_for(sleep_time);
bool hungry=true;
int first,second;
while(hungry)
{
int choice =randgen()%2;
first =chops.first;
second = chops.second;
if(choice)
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;
}
else locks[first].unlock();
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
locks[first].unlock();
locks[second].unlock();
}
}
void log(const std::string& data)
{
while(!cout_lock.try_lock())std::this_thread::sleep_for(std::chrono::milliseconds(1));
std::cout<<"Philosopher "<<n<<" "<<data<<std::endl;
cout_lock.unlock();
}
private:
int n;
std::pair<int,int> chops;
std::mt19937 randgen;
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;
}
Removing the 1 milisecond sleep time when a try_lock fails, seems to speed up everything !
[EDIT: Strangely, this fails when the number of Philosophers is 2. The second one does not ever get the chance to eat.:(
The frequency seems to be well distributed when the number is higher, though.]