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

Use atom constants in manual; several improvements

parent 82a6511b
......@@ -66,30 +66,33 @@ The example below illustrates printing of lines of text from multiple actors (in
#include <chrono>
#include <cstdlib>
#include <iostream>
#include "caf/all.hpp"
using namespace caf;
using std::endl;
using done_atom = atom_constant<atom("done")>;
int main() {
std::srand(std::time(0));
for (int i = 1; i <= 50; ++i) {
spawn<blocking_api>([i](blocking_actor* self) {
aout(self) << "Hi there! This is actor nr. "
<< i << "!" << endl;
std::chrono::milliseconds tout{std::rand() % 1000};
self->delayed_send(self, tout, atom("done"));
self->receive(others() >> [i, self] {
aout(self) << "Actor nr. "
<< i << " says goodbye!" << endl;
});
});
}
// wait until all other actors we've spawned are done
await_all_actors_done();
// done
shutdown();
return 0;
std::srand(std::time(0));
for (int i = 1; i <= 50; ++i) {
spawn<blocking_api>([i](blocking_actor* self) {
aout(self) << "Hi there! This is actor nr. "
<< i << "!" << endl;
std::chrono::milliseconds tout{std::rand() % 1000};
self->delayed_send(self, tout, done_atom::value);
self->receive(
[i, self](done_atom) {
aout(self) << "Actor nr. "
<< i << " says goodbye!" << endl;
}
);
});
}
// wait until all other actors we've spawned are done
await_all_actors_done();
shutdown();
}
\end{lstlisting}
......
......@@ -99,7 +99,7 @@ Analogous to \lstinline^sync_send(...).then(...)^ for event-based actors, blocki
\begin{lstlisting}
void foo(blocking_actor* self, actor testee) {
// 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) {
// handle str
},
......
......@@ -23,17 +23,6 @@ It is not possible to transfer a handle to a response to another actor.
\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}
\begin{itemize}
......
......@@ -9,7 +9,7 @@ std::string group_module = ...;
std::string group_id = ...;
auto grp = group::get(group_module, group_id);
self->join(grp);
self->send(grp, atom("test"));
self->send(grp, "test");
self->leave(grp);
\end{lstlisting}
......
......@@ -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.
\begin{lstlisting}
using a_atom = atom_constant<atom("a")>;
using b_atom = atom_constant<atom("b")>;
behavior testee(event_based_actor* self) {
// send 'b' with normal priority
self->send(self, atom("b"));
self->send(self, b_atom::value);
// 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'
return {
on(atom("b")) >> [=] {
[=](b_atom) {
aout(self) << "received 'b' => quit" << endl;
self->quit();
},
on(atom("a")) >> [=] {
[=](a_atom) {
aout(self) << "received 'a'" << endl;
},
};
......
......@@ -28,8 +28,8 @@ With \lstinline^reuse_addr = true^ binding would succeed because 10.0.0.1 and
\begin{lstlisting}
publish(self, 4242);
self->become (
on(atom("ping"), arg_match) >> [](int i) {
return make_message(atom("pong"), i);
[](ping_atom, int i) {
return std::make_tuple(pong_atom::value, i);
}
);
\end{lstlisting}
......@@ -53,13 +53,14 @@ A \lstinline^network_error^ is thrown if the connection failed.
\begin{lstlisting}
auto pong = remote_actor("localhost", 4242);
self->send(pong, atom("ping"), 0);
self->send(pong, ping_atom::value, 0);
self->become (
on(atom("pong"), 10) >> [=] {
self->quit();
},
on(atom("pong"), arg_match) >> [=](int i) {
return make_message(atom("ping"), i+1);
[=](pong_value, int i) {
if (i >= 10) {
self->quit();
return;
}
self->send(pong, ping_atom::value, i + 1);
}
);
\end{lstlisting}
This diff is collapsed.
......@@ -41,50 +41,56 @@ The following example illustrates a more advanced state-based actor that impleme
\clearpage
\begin{lstlisting}
using pop_atom = atom_constant<atom("pop")>;
using push_atom = atom_constant<atom("push")>;
class fixed_stack : public sb_actor<fixed_stack> {
public:
fixed_stack(size_t max) : max_size(max) {
assert(max_size > 0);
full = (
on(atom("push"), arg_match) >> [=](int) { /* discard */ },
on(atom("pop")) >> [=]() -> tuple<atom_value, int> {
full.assign(
[=](push_atom, int) {
/* discard */
},
[=](pop_atom) -> message {
auto result = data.back();
data.pop_back();
if (data.empty()) become(empty);
else become(filled);
return {atom("ok"), result};
become(filled);
return make_message(ok_atom::value, result);
}
);
filled = (
on(atom("push"), arg_match) >> [=](int what) {
filled.assign(
[=](push_atom, int 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();
data.pop_back();
if (data.empty()) become(empty);
return {atom("ok"), result};
if (data.empty()) {
become(empty);
}
return make_message(ok_atom::value, result);
}
);
empty = (
on(atom("push"), arg_match) >> [=](int what) {
empty.assign(
[=](push_atom, int what) {
data.push_back(what);
if (data.size() == max_size) become(full);
else become(filled);
become(filled);
},
on(atom("pop")) >> [=] {
return atom("failure");
[=](pop_atom) {
return error_atom::value;
}
);
}
private:
size_t max_size;
vector<int> data;
behavior full;
behavior filled;
behavior empty;
behavior& init_state = empty;
size_t max_size;
std::vector<int> data;
behavior full;
behavior filled;
behavior empty;
behavior& init_state = empty;
};
\end{lstlisting}
......@@ -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.
\begin{lstlisting}
using idle_atom = atom_constant<atom("idle")>;
using request_atom = atom_constant<atom("request")>;
behavior server(event_based_actor* self) {
auto die = [=] { self->quit(exit_reason::user_defined); };
return {
on(atom("idle")) >> [=] {
[=](idle_atom) {
auto worker = last_sender();
self->become (
keep_behavior,
on(atom("request")) >> [=] {
[=](request_atom) {
// forward request to idle worker
self->forward_to(worker);
// await next idle message
self->unbecome();
},
on(atom("idle")) >> skip_message,
[=](idle_atom) {
return skip_message();
},
others() >> die
);
},
on(atom("request")) >> skip_message,
[=](request_atom) {
return skip_message();
},
others() >> die
};
}
......
......@@ -19,7 +19,6 @@ void some_fun(event_based_actor* self) {
}
\end{lstlisting}
\clearpage
\subsection{Replying to Messages}
\label{Sec::Send::Reply}
......@@ -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.
\begin{lstlisting}
void client(event_based_actor* self, const actor& master) {
become (
on("foo", arg_match) >> [=](const string& request) {
return self->sync_send(master, atom("bar"), request).then(
behavior client(event_based_actor* self, const actor& master) {
return {
[=](const string& request) {
return self->sync_send(master, request).then(
[=](const std::string& response) {
return response;
}
);
}
);
};
};
\end{lstlisting}
\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^.
The following example illustrates a polling strategy using \lstinline^delayed_send^.
Messages can be delayed by using the function \lstinline^delayed_send^.
\begin{lstlisting}
using poll_atom = atom_constant<atom("poll")>;
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 {
on(atom("poll")) >> [] {
[](poll_atom) {
// poll a resource
// ...
// 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 @@
\label{Sec::Sync}
\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}
template<typename... Args>
__unspecified__ sync_send(actor whom, Args&&... what);
__unspecified__ sync_send_tuple(actor whom, message what);
template<typename Duration, typename... Args>
__unspecified__ timed_sync_send(actor whom,
Duration timeout,
Args&&... what);
template<typename Duration, typename... Args>
__unspecified__ timed_sync_send_tuple(actor whom,
Duration timeout,
message what);
\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 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.
\subsection{Error Messages}
......@@ -46,7 +39,7 @@ When sending a synchronous message, the response handler can be passed by either
\begin{lstlisting}
void foo(event_based_actor* self, actor testee) {
// 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) {
// handle str
},
......@@ -82,7 +75,7 @@ void foo(event_based_actor* self, actor testee) {
aout << "timeout occured" << endl;
};
// 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 */ }
);
\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