CAF 0.17.6
|
/ / Blocking functions to receive messages.
/ / 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->send(a1, hello_atom_v, "hello a1!"); / / // send a message to a1, a2, and a3 / auto msg = make_message(compute_atom_v, 1, 2, 3); / self->send(a1, msg); / self->send(a2, msg); / self->send(a3, msg); / ~~ / /
/ / 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. / / ~~ / { / [](hello_atom, const std::string& msg) { / cout << "received hello message: " << msg << endl; / }, / [](compute_atom, int i0, int i1, int i2) { / // send our result back to the sender of this messages / return make_message(result_atom_v, i0 + i1 + i2); / } / } / ~~ / / Blocking actors such as the scoped actor can call their receive member / to handle incoming messages. / / ~~ / self->receive( / [](result_atom, int i) { / cout << "result is: " << i << endl; / } / ); / ~~ / / Please read the manual for further details about pattern matching. / /
/ / Atoms are a nice way to add semantic informations to a message. Assuming an / actor wants to provide a "math sevice" 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->delayed_send(self, std::chrono::seconds(1), poll_atom_v); / bool running = true; / self->receive_while([&](){ return running; }) ( / // ... / [&](poll_atom) { / // ... poll something ... / // and do it again after 1sec / self->delayed_send(self, std::chrono::seconds(1), poll_atom_v); / } / ); / ~~ / / See also the dancing kirby example
. / /