An event-based "Dining Philosophers" implementation.
An event-based "Dining Philosophers" implementation.
#include "caf/actor_from_state.hpp"
#include "caf/actor_ostream.hpp"
#include "caf/actor_system.hpp"
#include "caf/caf_main.hpp"
#include "caf/mail_cache.hpp"
#include <chrono>
#include <map>
#include <sstream>
#include <thread>
#include <utility>
#include <vector>
CAF_BEGIN_TYPE_ID_BLOCK(dining_philosophers, first_custom_type_id)
CAF_ADD_ATOM(dining_philosophers, take_atom)
CAF_ADD_ATOM(dining_philosophers, taken_atom)
CAF_ADD_ATOM(dining_philosophers, eat_atom)
CAF_ADD_ATOM(dining_philosophers, think_atom)
CAF_END_TYPE_ID_BLOCK(dining_philosophers)
using namespace std::literals;
constexpr size_t mail_cache_size = 20;
struct chopstick_trait {
using signatures
};
using chopstick_actor = typed_actor<chopstick_trait>;
struct chopstick_state {
explicit chopstick_state(chopstick_actor::pointer selfptr) : self(selfptr) {
}
chopstick_actor::behavior_type make_behavior() {
return {
self->become(keep_behavior, taken(self->current_sender()));
return {taken_atom_v, true};
},
[this](put_atom) {
self->println("chopstick received unexpected 'put'");
},
};
}
return {
return {taken_atom_v, false};
},
[this, user](put_atom) {
if (self->current_sender() == user)
self->unbecome();
},
};
}
chopstick_actor::pointer self;
};
class philosopher_state {
public:
chopstick_actor l, chopstick_actor r)
: self(selfptr),
cache(selfptr, mail_cache_size),
auto skip_unmatched = [
this](
message msg) { cache.stash(std::move(msg)); };
[this](eat_atom) {
self->become(hungry);
cache.unstash();
self->mail(take_atom_v).send(left);
self->mail(take_atom_v).send(right);
},
skip_unmatched,
};
[
this](taken_atom,
bool result) {
self->become(granted);
else
self->become(denied);
cache.unstash();
},
skip_unmatched,
};
[
this](taken_atom,
bool result) {
self->println("{} has picked up chopsticks with "
"IDs {} and {} and starts to eat",
name, left->id(), right->id());
self->mail(think_atom_v).delay(5s).send(self);
self->become(eating);
} else {
self->mail(put_atom_v)
.send(self->current_sender() == left ? right : left);
self->mail(eat_atom_v).send(self);
self->become(thinking);
}
cache.unstash();
},
skip_unmatched,
};
[
this](taken_atom,
bool result) {
self->mail(put_atom_v)
.send(self->current_sender() == left ? left : right);
self->mail(eat_atom_v).send(self);
self->become(thinking);
cache.unstash();
},
skip_unmatched,
};
[this](think_atom) {
self->mail(put_atom_v).send(left);
self->mail(put_atom_v).send(right);
self->mail(eat_atom_v).delay(5s).send(self);
self->println("{} puts down his chopsticks and starts to think", name);
self->become(thinking);
cache.unstash();
},
skip_unmatched,
};
}
self->println("{} starts to think", name);
self->mail(eat_atom_v).delay(5s).send(self);
return thinking;
}
std::string name;
chopstick_actor left;
chopstick_actor right;
};
auto chopsticks = std::vector<chopstick_actor>{};
for (size_t i = 0; i < 5; ++i) {
chopsticks.push_back(sys.
spawn(actor_from_state<chopstick_state>));
sys.
println(
"- {}", chopsticks.back()->id());
}
auto names = std::vector{"Plato"s, "Hume"s, "Kant"s, "Nietzsche"s,
"Descartes"s};
for (size_t i = 0; i < 5; ++i)
sys.
spawn(actor_from_state<philosopher_state>, names[i], chopsticks[i],
chopsticks[(i + 1) % 5]);
}
CAF_MAIN(id_block::dining_philosophers)
Actor environment including scheduler, registry, and optional components such as a middleman.
Definition actor_system.hpp:87
infer_handle_from_class_t< C > spawn(Ts &&... xs)
Returns a new actor of type C using xs... as constructor arguments.
Definition actor_system.hpp:383
void println(term color, std::string_view fmt, Args &&... args)
Adds a new line to stdout.
Definition actor_system.hpp:462
Describes the behavior of an actor, i.e., provides a message handler and an optional timeout.
Definition behavior.hpp:24
A cooperatively scheduled, event-based actor implementation.
Definition event_based_actor.hpp:31
A simple cache for storing mailbox elements for an actor for later reuse.
Definition mail_cache.hpp:18
Describes a fixed-length, copy-on-write, type-erased tuple with elements of any type.
Definition message.hpp:32
Wraps the result of a message handler to represent either a value (wrapped into a message),...
Definition result.hpp:107
Root namespace of libcaf.
Definition abstract_actor.cpp:23
A list of types.
Definition type_list.hpp:11