Skip to content

Instantly share code, notes, and snippets.

@mkolod
Created April 20, 2018 05:46
Show Gist options
  • Save mkolod/b16a849b21a4b4f2fb8889a630a24703 to your computer and use it in GitHub Desktop.
Save mkolod/b16a849b21a4b4f2fb8889a630a24703 to your computer and use it in GitHub Desktop.
C++11 Dining Philosophers
//-----------------------------------------------------------------------------
// Desc: Dining Philosophers sample.
//
// Demonstrates how to use Monitor object (lock) to protect critical section.
//
// Scenario is such that there are 5 philosophers and 5 tools on each side of a philosopher.
// Each philosopher can only take one tool on the left and one on the right.
// One of the philosophers must wait for a tool to become available because whoever grabs
// a tool will hold it until he eats and puts the tool back on the table.
//
// Application of the pattern could be transferring money from account A to account B.
// Important here is to pass locking objects always in the same (increasing) order.
// If the order is mixed you would encounter random deadlocks at runtime.
//-----------------------------------------------------------------------------
#include <algorithm>
#include <iostream>
#include <memory>
#include <mutex>
#include <string>
#include <thread>
#include <exception>
#include <vector>
#include <cstddef>
using namespace std;
class Chopstick
{
public:
Chopstick(){};
mutex m;
};
int main()
{
auto eat = [](Chopstick* leftChopstick, Chopstick* rightChopstick, int philosopherNumber, int leftChopstickNumber, int rightChopstickNumber)
{
if (leftChopstick == rightChopstick)
{
throw runtime_error("Left and right chopsticks should not be the same!");
}
lock(leftChopstick->m, rightChopstick->m); // ensures there are no deadlocks
lock_guard<mutex> a(leftChopstick->m, adopt_lock);
string sl = " Philosopher " + to_string(philosopherNumber) + " picked " + to_string(leftChopstickNumber) + " chopstick.\n";
cout << sl.c_str();
lock_guard<mutex> b(rightChopstick->m, adopt_lock);
string sr = " Philosopher " + to_string(philosopherNumber) + " picked " + to_string(rightChopstickNumber) + " chopstick.\n";
cout << sr.c_str();
string pe = "Philosopher " + to_string(philosopherNumber) + " eats.\n";
cout << pe;
};
static const size_t numPhilosophers = 5;
vector< unique_ptr<Chopstick> > chopsticks(numPhilosophers);
for (size_t i {0}; i < numPhilosophers; ++i)
{
auto c1 = unique_ptr<Chopstick>(new Chopstick()); //make_unique in C++14
chopsticks[i] = move(c1);
}
// This is where we create philosophers, each of 5 tasks represents one philosopher.
vector<thread> tasks(numPhilosophers);
tasks[0] = thread(eat,
chopsticks[0].get(), // left chopstick: #1
chopsticks[numPhilosophers - 1].get(), // right chopstick: #5
0 + 1, // philosopher number
1, // left chopstick number
numPhilosophers // right chopstick number
);
for (size_t i{1}; i < numPhilosophers; ++i)
{
tasks[i] = (thread(eat,
chopsticks[i - 1].get(), // left chopstick
chopsticks[i].get(), // right chopstick
i + 1, // philosopher number
i, // left chopstick number
i + 1 // right chopstick number
)
);
}
for_each(tasks.begin(), tasks.end(), mem_fn(&thread::join));
return 0;
}
/*
Philosopher 1 picked 1 chopstick.
Philosopher 3 picked 2 chopstick.
Philosopher 1 picked 5 chopstick.
Philosopher 3 picked 3 chopstick.
Philosopher 1 eats.
Philosopher 3 eats.
Philosopher 5 picked 4 chopstick.
Philosopher 2 picked 1 chopstick.
Philosopher 2 picked 2 chopstick.
Philosopher 5 picked 5 chopstick.
Philosopher 2 eats.
Philosopher 5 eats.
Philosopher 4 picked 3 chopstick.
Philosopher 4 picked 4 chopstick.
Philosopher 4 eats.
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment