C++ Actor Framework 1.0.0
|
Blocking functions to receive messages.
The blocking API of CAF is intended to be used for migrating previously threaded applications. When writing new code, you should consider the nonblocking API based on become
and unbecome
first.
The function send
can be used to send a message to an actor. The first argument is the receiver of the message followed by any number of values:
~~ // spawn some actors actor_system_config cfg; actor_system system{cfg}; auto a1 = system.spawn(...); auto a2 = system.spawn(...); auto a3 = system.spawn(...);
// an actor executed in the current thread scoped_actor self{system};
// define an atom for message annotation using hello_atom = atom_constant<atom("hello")>; using compute_atom = atom_constant<atom("compute")>; using result_atom = atom_constant<atom("result")>;
// send a message to a1 self->mail(hello_atom::value, "hello a1!").send(a1);
// send a message to a1, a2, and a3 auto msg = make_message(compute_atom::value, 1, 2, 3); self->mail(msg).send(a1); self->mail(msg).send(a2); self->mail(msg).send(a3); ~~
The function receive
takes a behavior
as argument. The behavior is a list of { callback } rules where the callback argument types define a pattern for matching messages.
~~ { [&self](hello_atom, const std::string& msg) { self->println("received hello message: {}", msg); }, [](compute_atom, int i0, int i1, int i2) { // send our result back to the sender of this messages return make_message(result_atom::value, i0 + i1 + i2); } } ~~
Blocking actors such as the scoped actor can call their receive member to handle incoming messages.
~~ self->receive( [&self](result_atom, int i) { self->println("result is: {}", i); } ); ~~
Please read the manual for further details about pattern matching.
Atoms are a nice way to add semantic information to a message. Assuming an actor wants to provide a "math service" for integers. It could provide operations such as addition, subtraction, etc. This operations all have two operands. Thus, the actor does not know what operation the sender of a message wanted by receiving just two integers.
Example actor: ~~ using plus_atom = atom_constant<atom("plus")>; using minus_atom = atom_constant<atom("minus")>; behavior math_actor() { return { [](plus_atom, int a, int b) { return make_message(atom("result"), a + b); }, [](minus_atom, int a, int b) { return make_message(atom("result"), a - b); } }; } ~~
The previous examples used receive
to create a behavior on-the-fly. This is inefficient in a loop since the argument passed to receive is created in each iteration again. It's possible to store the behavior in a variable and pass that variable to receive. This fixes the issue of re-creation each iteration but rips apart definition and usage.
There are three convenience functions implementing receive loops to declare behavior where it belongs without unnecessary copies: receive_while,
receive_for
and do_receive
.
receive_while
creates a functor evaluating a lambda expression. The loop continues until the given lambda returns false
. A simple example:
~~ size_t received = 0; receive_while([&] { return received < 10; }) ( [&](int) { ++received; } ); // ... ~~
receive_for
is a simple ranged-based loop:
~~ std::vector<int> results; size_t i = 0; receive_for(i, 10) ( [&](int value) { results.push_back(value); } ); ~~
do_receive
returns a functor providing the function until
that takes a lambda expression. The loop continues until the given lambda returns true. Example:
~~ size_t received = 0; do_receive ( [&](int) { ++received; } ).until([&] { return received >= 10; }); // ... ~~
The function delayed_send
provides a simple way to delay a message. This is particularly useful for recurring events, e.g., periodical polling. Usage example:
~~ scoped_actor self{...};
self->mail(poll_atom::value).delay(std::chrono::seconds(1)).send(self); bool running = true; self->receive_while([&](){ return running; }) ( // ... [&](poll_atom) { // ... poll something ... // and do it again after 1sec self->mail(poll_atom::value).delay(std::chrono::seconds(1)).send(self); } ); ~~
See also the dancing kirby example
.