Commit 1a3de3f7 authored by Dominik Charousset's avatar Dominik Charousset

Use atom constants in manual; several improvements

parent 82a6511b
...@@ -66,11 +66,14 @@ The example below illustrates printing of lines of text from multiple actors (in ...@@ -66,11 +66,14 @@ The example below illustrates printing of lines of text from multiple actors (in
#include <chrono> #include <chrono>
#include <cstdlib> #include <cstdlib>
#include <iostream> #include <iostream>
#include "caf/all.hpp" #include "caf/all.hpp"
using namespace caf; using namespace caf;
using std::endl; using std::endl;
using done_atom = atom_constant<atom("done")>;
int main() { int main() {
std::srand(std::time(0)); std::srand(std::time(0));
for (int i = 1; i <= 50; ++i) { for (int i = 1; i <= 50; ++i) {
...@@ -78,18 +81,18 @@ int main() { ...@@ -78,18 +81,18 @@ int main() {
aout(self) << "Hi there! This is actor nr. " aout(self) << "Hi there! This is actor nr. "
<< i << "!" << endl; << i << "!" << endl;
std::chrono::milliseconds tout{std::rand() % 1000}; std::chrono::milliseconds tout{std::rand() % 1000};
self->delayed_send(self, tout, atom("done")); self->delayed_send(self, tout, done_atom::value);
self->receive(others() >> [i, self] { self->receive(
[i, self](done_atom) {
aout(self) << "Actor nr. " aout(self) << "Actor nr. "
<< i << " says goodbye!" << endl; << i << " says goodbye!" << endl;
}); }
);
}); });
} }
// wait until all other actors we've spawned are done // wait until all other actors we've spawned are done
await_all_actors_done(); await_all_actors_done();
// done
shutdown(); shutdown();
return 0;
} }
\end{lstlisting} \end{lstlisting}
......
...@@ -99,7 +99,7 @@ Analogous to \lstinline^sync_send(...).then(...)^ for event-based actors, blocki ...@@ -99,7 +99,7 @@ Analogous to \lstinline^sync_send(...).then(...)^ for event-based actors, blocki
\begin{lstlisting} \begin{lstlisting}
void foo(blocking_actor* self, actor testee) { void foo(blocking_actor* self, actor testee) {
// testee replies with a string to 'get' // testee replies with a string to 'get'
self->sync_send(testee, atom("get")).await( self->sync_send(testee, get_atom::value).await(
[&](const std::string& str) { [&](const std::string& str) {
// handle str // handle str
}, },
......
...@@ -23,17 +23,6 @@ It is not possible to transfer a handle to a response to another actor. ...@@ -23,17 +23,6 @@ It is not possible to transfer a handle to a response to another actor.
\end{itemize} \end{itemize}
\subsection{Sending Messages}
\begin{itemize}
\item
\lstinline^send(whom, ...)^ is defined as \lstinline^send_tuple(whom, make_message(...))^.
Hence, a message sent via \lstinline^send(whom, self->last_dequeued())^ will not yield the expected result, since it wraps \lstinline^self->last_dequeued()^ into another \lstinline^message^ instance.
The correct way of forwarding messages is \lstinline^self->forward_to(whom)^.
\end{itemize}
\subsection{Sharing} \subsection{Sharing}
\begin{itemize} \begin{itemize}
......
...@@ -9,7 +9,7 @@ std::string group_module = ...; ...@@ -9,7 +9,7 @@ std::string group_module = ...;
std::string group_id = ...; std::string group_id = ...;
auto grp = group::get(group_module, group_id); auto grp = group::get(group_module, group_id);
self->join(grp); self->join(grp);
self->send(grp, atom("test")); self->send(grp, "test");
self->leave(grp); self->leave(grp);
\end{lstlisting} \end{lstlisting}
......
...@@ -6,18 +6,21 @@ This flag causes the actor to use a priority-aware mailbox implementation. ...@@ -6,18 +6,21 @@ This flag causes the actor to use a priority-aware mailbox implementation.
It is not possible to change this implementation dynamically at runtime. It is not possible to change this implementation dynamically at runtime.
\begin{lstlisting} \begin{lstlisting}
using a_atom = atom_constant<atom("a")>;
using b_atom = atom_constant<atom("b")>;
behavior testee(event_based_actor* self) { behavior testee(event_based_actor* self) {
// send 'b' with normal priority // send 'b' with normal priority
self->send(self, atom("b")); self->send(self, b_atom::value);
// send 'a' with high priority // send 'a' with high priority
self->send(message_priority::high, self, atom("a")); self->send(message_priority::high, self, a_atom::value);
// terminate after receiving a 'b' // terminate after receiving a 'b'
return { return {
on(atom("b")) >> [=] { [=](b_atom) {
aout(self) << "received 'b' => quit" << endl; aout(self) << "received 'b' => quit" << endl;
self->quit(); self->quit();
}, },
on(atom("a")) >> [=] { [=](a_atom) {
aout(self) << "received 'a'" << endl; aout(self) << "received 'a'" << endl;
}, },
}; };
......
...@@ -28,8 +28,8 @@ With \lstinline^reuse_addr = true^ binding would succeed because 10.0.0.1 and ...@@ -28,8 +28,8 @@ With \lstinline^reuse_addr = true^ binding would succeed because 10.0.0.1 and
\begin{lstlisting} \begin{lstlisting}
publish(self, 4242); publish(self, 4242);
self->become ( self->become (
on(atom("ping"), arg_match) >> [](int i) { [](ping_atom, int i) {
return make_message(atom("pong"), i); return std::make_tuple(pong_atom::value, i);
} }
); );
\end{lstlisting} \end{lstlisting}
...@@ -53,13 +53,14 @@ A \lstinline^network_error^ is thrown if the connection failed. ...@@ -53,13 +53,14 @@ A \lstinline^network_error^ is thrown if the connection failed.
\begin{lstlisting} \begin{lstlisting}
auto pong = remote_actor("localhost", 4242); auto pong = remote_actor("localhost", 4242);
self->send(pong, atom("ping"), 0); self->send(pong, ping_atom::value, 0);
self->become ( self->become (
on(atom("pong"), 10) >> [=] { [=](pong_value, int i) {
if (i >= 10) {
self->quit(); self->quit();
}, return;
on(atom("pong"), arg_match) >> [=](int i) { }
return make_message(atom("ping"), i+1); self->send(pong, ping_atom::value, i + 1);
} }
); );
\end{lstlisting} \end{lstlisting}
This diff is collapsed.
...@@ -41,46 +41,52 @@ The following example illustrates a more advanced state-based actor that impleme ...@@ -41,46 +41,52 @@ The following example illustrates a more advanced state-based actor that impleme
\clearpage \clearpage
\begin{lstlisting} \begin{lstlisting}
using pop_atom = atom_constant<atom("pop")>;
using push_atom = atom_constant<atom("push")>;
class fixed_stack : public sb_actor<fixed_stack> { class fixed_stack : public sb_actor<fixed_stack> {
public: public:
fixed_stack(size_t max) : max_size(max) { fixed_stack(size_t max) : max_size(max) {
assert(max_size > 0); full.assign(
full = ( [=](push_atom, int) {
on(atom("push"), arg_match) >> [=](int) { /* discard */ }, /* discard */
on(atom("pop")) >> [=]() -> tuple<atom_value, int> { },
[=](pop_atom) -> message {
auto result = data.back(); auto result = data.back();
data.pop_back(); data.pop_back();
if (data.empty()) become(empty); become(filled);
else become(filled); return make_message(ok_atom::value, result);
return {atom("ok"), result};
} }
); );
filled = ( filled.assign(
on(atom("push"), arg_match) >> [=](int what) { [=](push_atom, int what) {
data.push_back(what); data.push_back(what);
if (data.size() == max_size) become(full); if (data.size() == max_size) {
become(full);
}
}, },
on(atom("pop")) >> [=]() -> tuple<atom_value, int> { [=](pop_atom) -> message {
auto result = data.back(); auto result = data.back();
data.pop_back(); data.pop_back();
if (data.empty()) become(empty); if (data.empty()) {
return {atom("ok"), result}; become(empty);
}
return make_message(ok_atom::value, result);
} }
); );
empty = ( empty.assign(
on(atom("push"), arg_match) >> [=](int what) { [=](push_atom, int what) {
data.push_back(what); data.push_back(what);
if (data.size() == max_size) become(full); become(filled);
else become(filled);
}, },
on(atom("pop")) >> [=] { [=](pop_atom) {
return atom("failure"); return error_atom::value;
} }
); );
} }
private:
size_t max_size; size_t max_size;
vector<int> data; std::vector<int> data;
behavior full; behavior full;
behavior filled; behavior filled;
behavior empty; behavior empty;
...@@ -168,24 +174,31 @@ Afterwards, the server returns to its initial behavior, i.e., awaits the next \l ...@@ -168,24 +174,31 @@ Afterwards, the server returns to its initial behavior, i.e., awaits the next \l
The server actor will exit for reason \lstinline^user_defined^ whenever it receives a message that is neither a request, nor an idle message. The server actor will exit for reason \lstinline^user_defined^ whenever it receives a message that is neither a request, nor an idle message.
\begin{lstlisting} \begin{lstlisting}
using idle_atom = atom_constant<atom("idle")>;
using request_atom = atom_constant<atom("request")>;
behavior server(event_based_actor* self) { behavior server(event_based_actor* self) {
auto die = [=] { self->quit(exit_reason::user_defined); }; auto die = [=] { self->quit(exit_reason::user_defined); };
return { return {
on(atom("idle")) >> [=] { [=](idle_atom) {
auto worker = last_sender(); auto worker = last_sender();
self->become ( self->become (
keep_behavior, keep_behavior,
on(atom("request")) >> [=] { [=](request_atom) {
// forward request to idle worker // forward request to idle worker
self->forward_to(worker); self->forward_to(worker);
// await next idle message // await next idle message
self->unbecome(); self->unbecome();
}, },
on(atom("idle")) >> skip_message, [=](idle_atom) {
return skip_message();
},
others() >> die others() >> die
); );
}, },
on(atom("request")) >> skip_message, [=](request_atom) {
return skip_message();
},
others() >> die others() >> die
}; };
} }
......
...@@ -19,7 +19,6 @@ void some_fun(event_based_actor* self) { ...@@ -19,7 +19,6 @@ void some_fun(event_based_actor* self) {
} }
\end{lstlisting} \end{lstlisting}
\clearpage
\subsection{Replying to Messages} \subsection{Replying to Messages}
\label{Sec::Send::Reply} \label{Sec::Send::Reply}
...@@ -27,33 +26,34 @@ The return value of a message handler is used as response message. ...@@ -27,33 +26,34 @@ The return value of a message handler is used as response message.
Actors can also use the result of a \lstinline^sync_send^ to answer to a request, as shown below. Actors can also use the result of a \lstinline^sync_send^ to answer to a request, as shown below.
\begin{lstlisting} \begin{lstlisting}
void client(event_based_actor* self, const actor& master) { behavior client(event_based_actor* self, const actor& master) {
become ( return {
on("foo", arg_match) >> [=](const string& request) { [=](const string& request) {
return self->sync_send(master, atom("bar"), request).then( return self->sync_send(master, request).then(
[=](const std::string& response) { [=](const std::string& response) {
return response; return response;
} }
); );
} }
); };
}; };
\end{lstlisting} \end{lstlisting}
\subsection{Delaying Messages} \subsection{Delaying Messages}
Messages can be delayed, e.g., to implement time-based polling strategies, by using one of \lstinline^delayed_send^, \lstinline^delayed_send_tuple^, \lstinline^delayed_reply^, or \lstinline^delayed_reply_tuple^. Messages can be delayed by using the function \lstinline^delayed_send^.
The following example illustrates a polling strategy using \lstinline^delayed_send^.
\begin{lstlisting} \begin{lstlisting}
using poll_atom = atom_constant<atom("poll")>;
behavior poller(event_based_actor* self) { behavior poller(event_based_actor* self) {
self->delayed_send(self, std::chrono::seconds(1), atom("poll")); using std::chrono::seconds;
self->delayed_send(self, seconds(1), poll_atom::value);
return { return {
on(atom("poll")) >> [] { [](poll_atom) {
// poll a resource // poll a resource
// ... // ...
// schedule next polling // schedule next polling
self->delayed_send(self, std::chrono::seconds(1), atom("poll")); self->delayed_send(self, seconds(1), poll_atom::value);
} }
}; };
} }
......
...@@ -2,30 +2,23 @@ ...@@ -2,30 +2,23 @@
\label{Sec::Sync} \label{Sec::Sync}
\lib supports both asynchronous and synchronous communication. \lib supports both asynchronous and synchronous communication.
The member functions \lstinline^sync_send^ and \lstinline^sync_send_tuple^ send synchronous request messages. The member function \lstinline^sync_send^ sends synchronous request messages.
\begin{lstlisting} \begin{lstlisting}
template<typename... Args> template<typename... Args>
__unspecified__ sync_send(actor whom, Args&&... what); __unspecified__ sync_send(actor whom, Args&&... what);
__unspecified__ sync_send_tuple(actor whom, message what);
template<typename Duration, typename... Args> template<typename Duration, typename... Args>
__unspecified__ timed_sync_send(actor whom, __unspecified__ timed_sync_send(actor whom,
Duration timeout, Duration timeout,
Args&&... what); Args&&... what);
template<typename Duration, typename... Args>
__unspecified__ timed_sync_send_tuple(actor whom,
Duration timeout,
message what);
\end{lstlisting} \end{lstlisting}
A synchronous message is sent to the receiving actor's mailbox like any other asynchronous message. A synchronous message is sent to the receiving actor's mailbox like any other (asynchronous) message.
The response message, on the other hand, is treated separately. The response message, on the other hand, is treated separately.
The difference between \lstinline^sync_send^ and \lstinline^timed_sync_send^ is how timeouts are handled. The difference between \lstinline^sync_send^ and \lstinline^timed_sync_send^ is how timeouts are handled.
The behavior of \lstinline^sync_send^ is analogous to \lstinline^send^, i.e., timeouts are specified by using \lstinline^after(...)^ statements (see \ref{Sec::Receive::Timeouts}). The behavior of \lstinline^sync_send^ is analogous to \lstinline^send^, i.e., timeouts are specified by using \lstinline^after(...)^ statements (see Section \ref{Sec::Receive::Timeouts}).
When using \lstinline^timed_sync_send^ function, \lstinline^after(...)^ statements are ignored and the actor will receive a \lstinline^sync_timeout_msg^ after the given duration instead. When using \lstinline^timed_sync_send^ function, \lstinline^after(...)^ statements are ignored and the actor will receive a \lstinline^sync_timeout_msg^ after the given duration instead.
\subsection{Error Messages} \subsection{Error Messages}
...@@ -46,7 +39,7 @@ When sending a synchronous message, the response handler can be passed by either ...@@ -46,7 +39,7 @@ When sending a synchronous message, the response handler can be passed by either
\begin{lstlisting} \begin{lstlisting}
void foo(event_based_actor* self, actor testee) { void foo(event_based_actor* self, actor testee) {
// testee replies with a string to 'get' // testee replies with a string to 'get'
self->sync_send(testee, atom("get")).then( self->sync_send(testee, get_atom::value).then(
[=](const std::string& str) { [=](const std::string& str) {
// handle str // handle str
}, },
...@@ -82,7 +75,7 @@ void foo(event_based_actor* self, actor testee) { ...@@ -82,7 +75,7 @@ void foo(event_based_actor* self, actor testee) {
aout << "timeout occured" << endl; aout << "timeout occured" << endl;
}; };
// set response handler by using "then" // set response handler by using "then"
timed_sync_send(testee, std::chrono::seconds(30), atom("get")).then( timed_sync_send(testee, std::chrono::seconds(30), get_atom::value).then(
[=](const std::string& str) { /* handle str */ } [=](const std::string& str) { /* handle str */ }
); );
\end{lstlisting} \end{lstlisting}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment