An event-based "Dining Philosophers" implementation.
#include <map>
#include <thread>
#include <vector>
#include <chrono>
#include <sstream>
#include <iostream>
string to_string(const thread::id& x) {
ostringstream os;
os << x;
return os.str();
}
}
#include "caf/all.hpp"
using std::cout;
using std::cerr;
using std::endl;
using std::chrono::seconds;
namespace {
reacts_to<put_atom>>;
chopstick::behavior_type taken_chopstick(chopstick::pointer
self,
actor_addr);
chopstick::behavior_type available_chopstick(chopstick::pointer self) {
return {
[=](take_atom) -> std::tuple<taken_atom, bool> {
self->become(taken_chopstick(self, self->current_sender()));
return std::make_tuple(taken_atom::value, true);
},
cerr << "chopstick received unexpected 'put'" << endl;
}
};
}
chopstick::behavior_type taken_chopstick(chopstick::pointer self,
return {
[](take_atom) -> std::tuple<taken_atom, bool> {
return std::make_tuple(taken_atom::value, false);
},
if (self->current_sender() == user)
self->become(available_chopstick(self));
}
};
}
public:
philosopher(actor_config& cfg,
const std::string& n,
const chopstick& l,
const chopstick& r)
name(n),
left(l),
right(r) {
thinking.assign(
[=](eat_atom) {
become(hungry);
send(left, take_atom::value);
send(right, take_atom::value);
}
);
hungry.assign(
[=](taken_atom, bool result) {
if (result)
become(granted);
else
become(denied);
}
);
granted.assign(
[=](taken_atom, bool result) {
if (result) {
<< " has picked up chopsticks with IDs "
<< left->id() << " and " << right->id()
<< " and starts to eat\n";
delayed_send(this, seconds(5), think_atom::value);
become(eating);
} else {
send(this, eat_atom::value);
become(thinking);
}
}
);
denied.assign(
[=](taken_atom, bool result) {
if (result)
send(this, eat_atom::value);
become(thinking);
}
);
eating.assign(
[=](think_atom) {
delayed_send(this, seconds(5), eat_atom::value);
aout(
this) << name <<
" puts down his chopsticks and starts to think\n";
become(thinking);
}
);
}
protected:
send(this, think_atom::value);
return (
[=](think_atom) {
aout(
this) << name <<
" starts to think\n";
delayed_send(this, seconds(5), eat_atom::value);
become(thinking);
}
);
}
private:
std::string name;
chopstick left;
chopstick right;
};
}
int main(int, char**) {
actor_system system;
aout(
self) <<
"chopstick ids are:";
std::vector<chopstick> chopsticks;
for (size_t i = 0; i < 5; ++i) {
chopsticks.push_back(self->spawn(available_chopstick));
aout(
self) <<
" " << chopsticks.back()->id();
}
std::vector<std::string> names {"Plato", "Hume", "Kant",
"Nietzsche", "Descartes"};
for (size_t i = 0; i < 5; ++i)
self->spawn<philosopher>(names[i], chopsticks[i], chopsticks[(i + 1) % 5]);
}