Here's the core of a C++ program simulating what we just described (click here for full program):
static const unsigned int kNumPhilosophers = 5; // must be 2 or greater
static const unsigned int kNumForks = kNumPhilosophers;
static const unsigned int kNumMeals = 3;
static mutex forks[kNumForks]; // forks modeled as mutexes
static void think(unsigned int id) {
cout << oslock << id << " starts thinking." << endl << osunlock;
sleep_for(getThinkTime());
cout << oslock << id << " all done thinking. " << endl << osunlock;
}
static void eat(unsigned int id) {
unsigned int left = id;
unsigned int right = (id + 1) % kNumForks;
forks[left].lock();
forks[right].lock();
cout << oslock << id << " starts eating om nom nom nom." << endl << osunlock;
sleep_for(getEatTime());
cout << oslock << id << " all done eating." << endl << osunlock;
forks[left].unlock();
forks[right].unlock();
}
static void philosopher(unsigned int id) {
for (unsigned int i = 0; i < kNumMeals; i++) {
think(id);
eat(id);
}
}
int main(int argc, const char *argv[]) {
thread philosophers[kNumPhilosophers];
for (unsigned int i = 0; i < kNumPhilosophers; i++)
philosophers[i] = thread(philosopher, i);
for (thread& p: philosophers)
p.join();
return 0;
}Here's the core of a program that takes the second approach (click here for full program):
static const unsigned int kNumPhilosophers = 5;
static const unsigned int kNumForks = kNumPhilosophers;
static const unsigned int kNumMeals = 3;
static mutex forks[kNumForks];
static unsigned int numAllowed = kNumPhilosophers - 1; // impose limit to avoid deadlock
static mutex numAllowedLock;
static void think(unsigned int id) {
cout << oslock << id << " starts thinking." << endl << osunlock;
sleep_for(getThinkTime());
cout << oslock << id << " all done thinking. " << endl << osunlock;
}
static void waitForPermission() {
while (true) {
numAllowedLock.lock();
if (numAllowed > 0) break;
numAllowedLock.unlock();
sleep_for(10);
}
numAllowed--;
numAllowedLock.unlock();
}
static void grantPermission() {
numAllowedLock.lock();
numAllowed++;
numAllowedLock.unlock();
}
static void eat(unsigned int id) {
unsigned int left = id;
unsigned int right = (id + 1) % kNumForks;
waitForPermission();
forks[left].lock();
forks[right].lock();
cout << oslock << id << " starts eating om nom nom nom." << endl << osunlock;
sleep_for(getEatTime());
cout << oslock << id << " all done eating." << endl << osunlock;
grantPermission();
forks[left].unlock();
forks[right].unlock();
} static void waitForPermission() {
while (true) {
numAllowedLock.lock();
if (numAllowed > 0) break;
numAllowedLock.unlock();
sleep_for(10);
}
numAllowed--;
numAllowedLock.unlock();
}
static mutex forks[kNumForks];
static int numAllowed = kNumForks - 1;
static mutex m;
static condition_variable_any cv;
static void waitForPermission() {
lock_guard<mutex> lg(m);
cv.wait(m, []{ return numAllowed > 0; });
numAllowed--;
}
static void grantPermission() {
lock_guard<mutex> lg(m);
numAllowed++;
if (numAllowed == 1) cv.notify_all();
}
static mutex forks[kNumForks];
static int numAllowed = kNumForks - 1;
static mutex m;
static condition_variable_any cv;
static void waitForPermission() {
lock_guard<mutex> lg(m);
cv.wait(m, []{ return numAllowed > 0; });
numAllowed--;
}
static void grantPermission() {
lock_guard<mutex> lg(m);
numAllowed++;
if (numAllowed == 1) cv.notify_all();
}