Commit a2bd2466 authored by Dominik Charousset's avatar Dominik Charousset

added manual to GIT repository

parent 7f86e260
...@@ -5,7 +5,6 @@ html/ ...@@ -5,7 +5,6 @@ html/
build/* build/*
build-clang/* build-clang/*
build-gcc/* build-gcc/*
manual/*
Makefile Makefile
bin/* bin/*
lib/* lib/*
%\section{Actor Companions}
%\subsection{Treat Qt GUI Elements as Actors}
\section{Management \& Error Detection}
\libcppa adapts Erlang's well-established fault propagation model.
It allows to build actor subsystem in which either all actors are alive or have collectively failed.
\subsection{Links}
Linked actors monitor each other.
An actor sends an exit message to all of its links as part of its termination.
The default behavior for actors receiving such an exit message is to die for the same reason, if the exit reason is non-normal.
Actors can \textit{trap} exit messages to handle them manually.
\begin{lstlisting}
actor_ptr worker = ...;
// receive exit messages as regular messages
self->trap_exit(true);
// monitor spawned actor
self->link_to(worker);
// wait until worker exited
become (
on(atom("EXIT"), exit_reason::normal) >> [] {
// worker finished computation
},
on(atom("EXIT"), arg_match) >> [](std::uint32_t reason) {
// worker died unexpectedly
}
);
\end{lstlisting}
\subsection{Monitors}
\label{Sec::Management::Monitors}
A monitor observes the lifetime of an actor.
Monitored actors send a down message to all observers as part of their termination.
Unlike exit messages, down messages are always treated like any other ordinary message.
An actor will receive one down message for each time it called \lstinline^self->monitor(...)^, even if it adds a monitor to the same actor multiple times.
\begin{lstlisting}
actor_ptr worker = ...;
// monitor spawned actor
self->monitor(worker);
// wait until worker exited
receive (
on(atom("DOWN"), exit_reason::normal) >> [] {
// worker finished computation
},
on(atom("DOWN"), arg_match) >> [](std::uint32_t reason) {
// worker died unexpectedly
}
);
\end{lstlisting}
\subsection{Error Codes}
All error codes are defined in the namespace \lstinline^cppa::exit_reason^.
To obtain a string representation of an error code, use \lstinline^cppa::exit_reason::as_string(uint32_t)^.
\begin{tabular*}{\textwidth}{m{0.35\textwidth}m{0.08\textwidth}m{0.5\textwidth}}
\hline
\lstinline^normal^ & 1 & Actor finished execution without error \\
\hline
\lstinline^unhandled_exception^ & 2 & Actor was killed due to an unhandled exception \\
\hline
\lstinline^unallowed_function_call^ & 3 & Indicates that an event-based actor tried to use blocking receive calls \\
\hline
\lstinline^unhandled_sync_failure^ & 4 & Actor was killed due to an unexpected synchronous response message \\
\hline
\lstinline^unhandled_sync_timeout^ & 5 & Actor was killed, because no timeout handler was set and a synchronous message timed out \\
\hline
\lstinline^remote_link_unreachable^ & 257 & Indicates that a remote actor became unreachable, e.g., due to connection error \\
\hline
\lstinline^user_defined^ & 65536 & Minimum value for user-defined exit codes \\
\hline
\end{tabular*}
\subsection{Attach Cleanup Code to an Actor}
Actors can attach cleanup code to other actors.
This code is executed immediately if the actor has already exited.
Keep in mind that \lstinline^self^ refers to the currently running actor.
Thus, \lstinline^self^ refers to the terminating actor and not to the actor that attached a functor to it.
\begin{lstlisting}
auto worker = spawn(...);
actor_ptr observer = self;
// "monitor" spawned actor
worker->attach_functor([observer](std::uint32_t reason) {
// this callback is invoked from worker
send(observer, atom("DONE"));
});
// wait until worker exited
become (
on(atom("DONE")) >> [] {
// worker terminated
}
);
\end{lstlisting}
\textbf{Note}: It is possible to attach code to remote actors, but the cleanup code will run on the local machine.
\section{Actors}
\libcppa provides several actor implementations, each covering a particular use case.
The class \lstinline^local_actor^ is the base class for all implementations, except for (remote) proxy actors.
Hence, \lstinline^local_actor^ provides a common interface for actor operations like trapping exit messages or finishing execution.
The default actor implementation in \libcppa is event-based.
Event-based actors have a very small memory footprint and are thus very lightweight and scalable.
Context-switching actors are used for actors that make use of the blocking API (see Section \ref{Sec::BlockingAPI}), but do not need to run in a separate thread.
Context-switching and event-based actors are scheduled cooperatively in a thread pool.
Thread-mapped actors can be used to opt-out of this cooperative scheduling.
%\subsection{Local Actors}
%The class \lstinline^local_actor^ describes a local running actor.
%It provides a common interface for actor operations like trapping exit messages or finishing execution.
\subsection{The ``Keyword'' \texttt{self}}
The \lstinline^self^ pointer is an essential ingredient of our design.
It identifies the running actor similar to the implicit \lstinline^this^ pointer identifying an object within a member function.
Unlike \lstinline^this^, though, \lstinline^self^ is not limited to a particular scope.
The \lstinline^self^ pointer is used implicitly, whenever an actor calls functions like \lstinline^send^ or \lstinline^become^, but can be accessed to use more advanced actor operations such as linking to another actor, e.g., by calling \lstinline^self->link_to(other)^.
The \lstinline^self^ pointer is convertible to \lstinline^actor_ptr^ and \lstinline^local_actor*^, but it is neither copyable nor assignable.
Thus, \lstinline^auto s = self^ will cause a compiler error, while \lstinline^actor_ptr s = self^ works as expected.
A thread that accesses \lstinline^self^ is converted on-the-fly to an actor if needed.
Hence, ``everything is an actor'' in \libcppa.
However, automatically converted actors use an implementation based on the blocking API, which behaves slightly different than the default, i.e., event-based, implementation.
\clearpage
\subsection{Interface}
\begin{lstlisting}
class local_actor;
\end{lstlisting}
{\small
\begin{tabular*}{\textwidth}{m{0.45\textwidth}m{0.5\textwidth}}
\multicolumn{2}{m{\linewidth}}{\large{\textbf{Member functions}}\vspace{3pt}} \\
\\
\hline
\lstinline^quit(uint32_t reason = normal)^ & Finishes execution of this actor \\
\hline
\\
\multicolumn{2}{l}{\textbf{Observers}\vspace{3pt}} \\
\hline
\lstinline^bool trap_exit()^ & Checks whether this actor traps exit messages \\
\hline
\lstinline^bool chaining()^ & Checks whether this actor uses the ``chained send'' optimization (see Section \ref{Sec::Send::ChainedSend}) \\
\hline
\lstinline^any_tuple last_dequeued()^ & Returns the last message that was dequeued from the actor's mailbox\newline\textbf{Note}: Only set during callback invocation \\
\hline
\lstinline^actor_ptr last_sender()^ & Returns the sender of the last dequeued message\newline\textbf{Note$_{1}$}: Only set during callback invocation\newline\textbf{Note$_{2}$}: Used by the function \lstinline^reply^ (see Section \ref{Sec::Send::Reply}) \\
\hline
\lstinline^vector<group_ptr> joined_groups()^ & Returns all subscribed groups \\
\hline
\\
\multicolumn{2}{l}{\textbf{Modifiers}\vspace{3pt}} \\
\hline
\lstinline^void trap_exit(bool enabled)^ & Enables or disables trapping of exit messages \\
\hline
\lstinline^void chaining(bool enabled)^ & Enables or disables chained send \\
\hline
\lstinline^void join(const group_ptr& g)^ & Subscribes to group \lstinline^g^ \\
\hline
\lstinline^void leave(const group_ptr& g)^ & Unsubscribes group \lstinline^g^ \\
\hline
\lstinline^auto make_response_handle()^ & Creates a handle that can be used to respond to the last received message later on, e.g., after receiving another message \\
\hline
\lstinline^void on_sync_failure(auto fun)^ & Sets a handler, i.e., a functor taking no arguments, for unexpected synchronous response messages (default action is to kill the actor for reason \lstinline^unhandled_sync_failure^) \\
\hline
\lstinline^void on_sync_timeout(auto fun)^ & Sets a handler, i.e., a functor taking no arguments, for \lstinline^timed_sync_send^ timeout messages (default action is to kill the actor for reason \lstinline^unhandled_sync_timeout^) \\
\hline
\lstinline^void monitor(actor_ptr whom)^ & Adds a unidirectional monitor to \lstinline^whom^ (see Section \ref{Sec::Management::Monitors}) \\
\hline
\lstinline^void demonitor(actor_ptr whom)^ & Removes a monitor from \lstinline^whom^ \\
\hline
\lstinline^void exec_behavior_stack()^ & Executes an actor's behavior stack until it is empty \\
\hline
\lstinline^bool has_sync_failure_handler()^ & Checks wheter this actor has a user-defined sync failure handler \\
\hline
\end{tabular*}
}
\section{Appendix}
\subsection{Class \texttt{option}}
\label{Appendix::Option}
Defined in header \lstinline^"cppa/option.hpp"^.
\begin{lstlisting}
template<typename T>
class option;
\end{lstlisting}
Represents an optional value.
{\small
\begin{tabular*}{\textwidth}{m{0.5\linewidth}m{0.45\linewidth}}
\multicolumn{2}{l}{\large{\textbf{Member types}}\vspace{3pt}} \\
\hline
\textbf{Member type} & \textbf{Definition} \\
\hline
\lstinline^type^ & \lstinline^T^ \\
\hline
\\
\multicolumn{2}{l}{\large{\textbf{Member functions}}\vspace{3pt}} \\
\hline
\lstinline^option()^ & Constructs an empty option \\
\hline
\lstinline^option(T value)^ & Initializes \lstinline^this^ with \lstinline^value^ \\
\hline
\lstinline^option(const option&)^\newline\lstinline^option(option&&)^ & Copy/move construction \\
\hline
\lstinline^option& operator=(const option&)^\newline\lstinline^option& operator=(option&&)^ & Copy/move assignment \\
\hline
\\
\multicolumn{2}{l}{\textbf{Observers}\vspace{3pt}} \\
\hline
\lstinline^bool valid()^\newline\lstinline^explicit operator bool()^ & Returns \lstinline^true^ if \lstinline^this^ has a value \\
\hline
\lstinline^bool empty()^\newline\lstinline^bool operator!()^ & Returns \lstinline^true^ if \lstinline^this^ does \textbf{not} has a value \\
\hline
\lstinline^const T& get()^\newline\lstinline^const T& operator*()^ & Access stored value \\
\hline
\lstinline^const T& get_or_else(const T& x)^ & Returns \lstinline^get()^ if valid, \lstinline^x^ otherwise \\
\hline
\\
\multicolumn{2}{l}{\textbf{Modifiers}\vspace{3pt}} \\
\hline
\lstinline^T& get()^\newline\lstinline^T& operator*()^ & Access stored value \\
\hline
\end{tabular*}
}
\clearpage
\subsection{Using \texttt{aout} -- A Concurrency-safe Wrapper for \texttt{cout}}
When using \lstinline^cout^ from multiple actors, output often appears interleaved.
Moreover, using \lstinline^cout^ from multiple actors -- and thus multiple threads -- in parallel should be avoided, since the standard does not guarantee a thread-safe implementation.
By replacing \texttt{std::cout} with \texttt{cppa::aout}, actors can achieve a concurrency-safe text output.
The header \lstinline^cppa/cppa.hpp^ also defines overloads for \texttt{std::endl} and \texttt{std::flush} for \lstinline^aout^, but does not support the full range of ostream operations (yet).
Each write operation to \texttt{aout} sends a message to a `hidden' actor (keep in mind, sending messages from actor constructors is not safe).
This actor only prints lines, unless output is forced using \lstinline^flush^.
\begin{lstlisting}
#include <chrono>
#include <cstdlib>
#include "cppa/cppa.hpp"
using namespace cppa;
using std::endl;
int main() {
std::srand(std::time(0));
for (int i = 1; i <= 50; ++i) {
spawn([i] {
aout << "Hi there! This is actor nr. " << i << "!" << endl;
std::chrono::milliseconds tout{std::rand() % 1000};
delayed_send(self, tout, atom("done"));
receive(others() >> [i] {
aout << "Actor nr. " << i << " says goodbye!" << endl;
});
});
}
// wait until all other actors we've spawned are done
await_all_others_done();
// done
shutdown();
return 0;
}
\end{lstlisting}
\ No newline at end of file
\section{Blocking API}
\label{Sec::BlockingAPI}
Besides event-based actors (the default implementation), \libcppa also provides context-switching and thread-mapped actors that can make use of the blocking API.
Those actor implementations are intended to ease migration of existing applications or to implement actors that need to have access to blocking receive primitives for other reasons.
Event-based actors differ in receiving messages from context-switching and thread-mapped actors: the former define their behavior as a message handler that is invoked whenever a new messages arrives in the actor's mailbox (by using \lstinline^become^), whereas the latter use an explicit, blocking receive function.
\subsection{Receiving Messages}
The function \lstinline^receive^ sequentially iterates over all elements in the mailbox beginning with the first.
It takes a partial function that is applied to the elements in the mailbox until an element was matched by the partial function.
An actor calling \lstinline^receive^ is blocked until it successfully dequeued a message from its mailbox or an optional timeout occurs.
\begin{lstlisting}
receive (
on<int>().when(_x1 > 0) >> // ...
);
\end{lstlisting}
The code snippet above illustrates the use of \lstinline^receive^.
Note that the partial function passed to \lstinline^receive^ is a temporary object at runtime.
Hence, using receive inside a loop would cause creation of a new partial function on each iteration.
\libcppa provides three predefined receive loops to provide a more efficient but yet convenient way of defining receive loops.
\begin{tabular*}{\textwidth}{p{0.47\textwidth}|p{0.47\textwidth}}
\lstinline^// DON'T^ & \lstinline^// DO^ \\
\begin{lstlisting}
for (;;) {
receive (
// ...
);
}
\end{lstlisting} & %
\begin{lstlisting}
receive_loop (
// ...
);
\end{lstlisting} \\
\begin{lstlisting}
std::vector<int> results;
for (size_t i = 0; i < 10; ++i) {
receive (
on<int>() >> [&](int value) {
results.push_back(value);
}
);
}
\end{lstlisting} & %
\begin{lstlisting}
std::vector<int> results;
size_t i = 0;
receive_for(i, 10) (
on<int>() >> [&](int value) {
results.push_back(value);
}
);
\end{lstlisting} \\
\begin{lstlisting}
size_t received = 0;
do {
receive (
others() >> [&]() {
++received;
}
);
} while (received < 10);
\end{lstlisting} & %
\begin{lstlisting}
size_t received = 0;
do_receive (
others() >> [&]() {
++received;
}
).until(gref(received) >= 10);
\end{lstlisting} \\
\end{tabular*}
The examples above illustrate the correct usage of the three loops \lstinline^receive_loop^, \lstinline^receive_for^ and \lstinline^do_receive(...).until^.
It is possible to nest receives and receive loops.
\begin{lstlisting}
receive_loop (
on<int>() >> [](int value1) {
receive (
on<float>() >> [&](float value2) {
cout << value1 << " => " << value2 << endl;
}
);
}
);
\end{lstlisting}
\clearpage
\subsection{Receiving Synchronous Responses}
\begin{lstlisting}
actor_ptr testee = ...; // replies with a string to 'get'
auto future = sync_send(testee, atom("get"));
receive_response (future) (
on_arg_match >> [&](const std::string& str) {
// handle str
},
after(std::chrono::seconds(30)) >> [&]() {
// handle error
}
);
// or:
sync_send(testee, atom("get")).await (
on_arg_match >> [&](const std::string& str) {
// handle str
},
after(std::chrono::seconds(30)) >> [&]() {
// handle error
}
);
\end{lstlisting}
\ No newline at end of file
\section{Common Pitfalls}
\label{Sec::Pitfalls}
\subsection{Event-Based API}
\begin{itemize}
\item The functions \lstinline^become^ and \lstinline^handle_response^ do not block, i.e., always return immediately.
Thus, you should \textit{always} capture by value in event-based actors, because all references on the stack will cause undefined behavior if a lambda is executed.
\end{itemize}
\subsection{Mixing Event-Based and Blocking API}
\begin{itemize}
\item Blocking \libcppa function such as \lstinline^receive^ will \emph{throw an exception} if accessed from an event-based actor.
%To catch as many errors as possible at compile-time, \libcppa will produce an error if \lstinline^receive^ is called and the \lstinline^this^ pointer is set and points to an event-based actor.
\item Context-switching and thread-mapped actors \emph{can} use the \lstinline^become^ API.
Whenever a non-event-based actor calls \lstinline^become()^ for the first time, it will create a behavior stack and execute it until the behavior stack is empty.
Thus, the \textit{initial} \lstinline^become^ blocks until the behavior stack is empty, whereas all subsequent calls to \lstinline^become^ will return immediately.
Related functions, e.g., \lstinline^sync_send(...).then(...)^, behave the same, as they manipulate the behavior stack as well.
\end{itemize}
\subsection{Synchronous Messages}
\begin{itemize}
\item
\lstinline^send(self->last_sender(), ...)^ is \textbf{not} equal to \lstinline^reply(...)^.
The two functions \lstinline^receive_response^ and \lstinline^handle_response^ will only recognize messages send via either \lstinline^reply^ or \lstinline^reply_tuple^.
\item
A handle returned by \lstinline^sync_send^ represents \emph{exactly one} response message.
Therefore, it is not possible to receive more than one response message.
Calling \lstinline^reply^ more than once will result in lost messages and calling \lstinline^handle_response^ or \lstinline^receive_response^ more than once on a future will throw an exception.
\item
The future returned by \lstinline^sync_send^ is bound to the calling actor.
It is not possible to transfer such a future to another actor.
Calling \lstinline^receive_response^ or \lstinline^handle_response^ for a future bound to another actor is undefined behavior.
\end{itemize}
\subsection{Sending Messages}
\begin{itemize}
\item
\lstinline^send(whom, ...)^ is syntactic sugar for \lstinline^whom << make_any_tuple(...)^.
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^any_tuple^ instance.
The correct way of forwarding messages is \lstinline^self->forward_to(whom)^.
\end{itemize}
\clearpage
\subsection{Sharing}
\begin{itemize}
\item It is strongly recommended to \textbf{not} share states between actors.
In particular, no actor shall ever access member variables or member functions of another actor.
Accessing shared memory segments concurrently can cause undefined behavior that is incredibly hard to find and debug.
However, sharing \textit{data} between actors is fine, as long as the data is \textit{immutable} and all actors access the data only via smart pointers such as \lstinline^std::shared_ptr^.
Nevertheless, the recommended way of sharing informations is message passing.
Sending data to multiple actors does \textit{not} result in copying the data several times.
Read Section \ref{Sec::Tuples} to learn more about \libcppa's copy-on-write optimization for tuples.
\end{itemize}
\subsection{Constructors of Class-based Actors}
\begin{itemize}
\item During constructor invocation, \lstinline^self^ does \textbf{not} point to \lstinline^this^. It points to the invoking actor instead.
\item You should \textbf{not} send or receive messages in a constructor or destructor.
\end{itemize}
\section{Copy-On-Write Tuples}
\label{Sec::Tuples}
The message passing implementation of \libcppa uses tuples with call-by-value semantic.
Hence, it is not necessary to declare message types, though, \libcppa allows users to use user-defined types in messages (see Section \ref{Sec::TypeSystem::UserDefined}).
A call-by-value semantic would cause multiple copies of a tuple if it is send to multiple actors.
To avoid unnecessary copying overhead, \libcppa uses a copy-on-write tuple implementation.
A tuple is implicitly shared between any number of actors, as long as all actors demand only read access.
Whenever an actor demands write access, it has to copy the data first if more than one reference to it exists.
Thus, race conditions cannot occur and each tuple is copied only if necessary.
The interface of \lstinline^cow_tuple^ strictly distinguishes between const and non-const access.
The template function \lstinline^get^ returns an element as immutable value, while \lstinline^get_ref^ explicitly returns a mutable reference to the required value and detaches the tuple if needed.
We do not provide a const overload for \lstinline^get^, because this would cause to unintended, and thus unnecessary, copying overhead.
\begin{lstlisting}
auto x1 = make_cow_tuple(1, 2, 3); // cow_tuple<int, int, int>
auto x2 = x1; // cow_tuple<int, int, int>
assert(&get<0>(x1) == &get<0>(x2)); // point to the same data
get_ref<0>(x1) = 10; // detaches x1 from x2
//get<0>(x1) = 10; // compiler error
assert(get<0>(x1) == 10); // x1 is now {10, 2, 3}
assert(get<0>(x2) == 1); // x2 is still {1, 2, 3}
assert(&get<0>(x1) != &get<0>(x2)); // no longer the same
\end{lstlisting}
\subsection{Dynamically Typed Tuples}
\label{Sec::Tuples::DynamicallyTypedTuples}
The class \lstinline^any_tuple^ represents a tuple without static type information.
All messages send between actors use this tuple type.
The type information can be either explicitly accessed for each element or the original tuple, or a subtuple of it, can be restored using \lstinline^tuple_cast^.
Users of \libcppa usually do not need to know about
\lstinline^any_tuple^, since it is used ``behind the scenes''.
However, \lstinline^any_tuple^ can be created from a \lstinline^cow_tuple^
or by using \lstinline^make_any_tuple^, as shown below.
\begin{lstlisting}
auto x1 = make_cow_tuple(1, 2, 3); // cow_tuple<int, int, int>
any_tuple x2 = x1; // any_tuple
any_tuple x3 = make_cow_tuple(10, 20); // any_tuple
auto x4 = make_any_tuple(42); // any_tuple
\end{lstlisting}
\clearpage
\subsection{Casting Tuples}
The function \lstinline^tuple_cast^ restores static type information
from an \lstinline^any_tuple^ object.
It returns an \lstinline^option^ (see Section \ref{Appendix::Option})
for a \lstinline^cow_tuple^ of the requested types.
\begin{lstlisting}
auto x1 = make_any_tuple(1, 2, 3);
auto x2_opt = tuple_cast<int, int, int>(x1);
assert(x2_opt.valid());
auto x2 = *x2_opt;
assert(get<0>(x2) == 1);
assert(get<1>(x2) == 2);
assert(get<2>(x2) == 3);
\end{lstlisting}
The function \lstinline^tuple_cast^ can be used with wildcards (see Section \ref{Sec::PatternMatching::Wildcards}) to create a view to a subset of the original data.
No elements are copied, unless the tuple becomes detached.
\begin{lstlisting}
auto x1 = make_cow_tuple(1, 2, 3);
any_tuple x2 = x1;
auto x3_opt = tuple_cast<int, anything, int>(x2);
assert(x3_opt.valid());
auto x3 = *x3_opt;
assert(get<0>(x3) == 1);
assert(get<1>(x3) == 3);
assert(&get<0>(x3) == &get<0>(x1));
assert(&get<1>(x3) == &get<2>(x1));
\end{lstlisting}
\section{First Steps}
%\subsection{Why Actors?}
%\subsection{Some Terminology}
To compile \libcppa, you will need CMake and a C++11 compiler. To get and compile the sources, open a terminal (on Linux or Mac OS X) and type:
\begin{verbatim}
git clone git://github.com/Neverlord/libcppa.git
cd libcppa
./configure
make
make install [as root, optional]
\end{verbatim}
It is recommended to run the unit tests as well:
\begin{verbatim}
make test
\end{verbatim}
Please submit a bug report that includes (a) your compiler version, (b) your OS, and (c) the content of the file \texttt{build/Testing/Temporary/LastTest.log} if an error occurs.
\subsection{Features Overview}
\begin{itemize*}
\item Lightweight, fast and efficient actor implementations
\item Network transparent messaging
\item Error handling based on Erlang's failure model
\item Pattern matching for messages as internal DSL to ease development
\item Thread-mapped actors and on-the-fly conversions for soft migration of existing applications
\item Publish/subscribe group communication
\end{itemize*}
\subsection{Supported Compilers}
\begin{itemize*}
\item GCC $\ge$ 4.7
\item Clang $\ge$ 3.2
\end{itemize*}
\subsection{Supported Operating Systems}
\begin{itemize*}
\item Linux
\item Mac OS X
\item \textit{Note for MS Windows}:
\libcppa relies on C++11 features such as variadic templates.
We will support this platform as soon as Microsoft's compiler implements all required C++11 features.
\end{itemize*}
\clearpage
\subsection{Hello World Example}
\begin{lstlisting}
#include <string>
#include <iostream>
#include "cppa/cppa.hpp"
using namespace std;
using namespace cppa;
void mirror() {
// wait for messages
become (
// invoke this lambda expression if we receive a string
on_arg_match >> [](const string& what) {
// prints "Hello World!" via aout (thread-safe cout wrapper)
aout << what << endl;
// replies "!dlroW olleH"
reply(string(what.rbegin(), what.rend()));
// terminates this actor ('become' otherwise loops forever)
self->quit();
}
);
}
void hello_world(const actor_ptr& buddy) {
// send "Hello World!" to our buddy ...
sync_send(buddy, "Hello World!").then(
// ... and wait for a response
on_arg_match >> [](const string& what) {
// prints "!dlroW olleH"
aout << what << endl;
}
);
}
int main() {
// create a new actor that calls 'mirror()'
auto mirror_actor = spawn(mirror);
// create another actor that calls 'hello_world(mirror_actor)'
spawn(hello_world, mirror_actor);
// wait until all other actors we have spawned are done
await_all_others_done();
// run cleanup code before exiting main
shutdown();
}
\end{lstlisting}
\section{Group Communication}
\label{Sec::Group}
\libcppa supports publish/subscribe-based group communication.
Actors can join and leave groups and send messages to groups.
\begin{lstlisting}
std::string group_module = ...;
std::string group_id = ...;
auto grp = group::get(group_module, group_id);
self->join(grp);
send(grp, atom("test"));
self->leave(grp);
\end{lstlisting}
\subsection{Anonymous Groups}
\label{Sec::Group::Anonymous}
Groups created on-the-fly with \lstinline^group::anonymous()^ can be used to coordinate a set of workers.
Each call to \lstinline^group::anonymous()^ returns a new, unique group instance.
\subsection{Local Groups}
\label{Sec::Group::Local}
The \lstinline^"local"^ group module creates groups for in-process communication.
For example, a group for GUI related events could be identified by \lstinline^group::get("local", "GUI events")^.
The group ID \lstinline^"GUI events"^ uniquely identifies a singleton group instance of the module \lstinline^"local"^.
\subsection{Spawn Actors in Groups}
\label{Sec::Group::Spawn}
The function \lstinline^spawn_in_group^ can be used to create actors as members of a group.
The function causes the newly created actors to call \lstinline^self->join(...)^ immediately and before \lstinline^spawn_in_group^ returns.
The usage of \lstinline^spawn_in_group^ is equal to \lstinline^spawn^, except for an additional group argument.
The group handle is always the first argument, as shown in the examples below.
\begin{lstlisting}
void fun1();
void fun2(int, float);
class my_actor1 : event_based_actor { /* ... */ };
class my_actor2 : event_based_actor {
// ...
my_actor2(const std::string& str) { /* ... */ }
};
// ...
auto grp = group::get(...);
auto a1 = spawn_in_group(grp, fun1);
auto a2 = spawn_in_group(grp, fun2, 1, 2.0f);
auto a3 = spawn_in_group<my_actor1>(grp);
auto a4 = spawn_in_group<my_actor2>(grp, "hello my_actor2!");
\end{lstlisting}
DIRS := build-html build-pdf
SOURCES = ActorManagement.tex Actors.tex Appendix.tex CommonPitfalls.tex CopyOnWriteTuples.tex FirstSteps.tex GroupCommunication.tex MessagePriorities.tex NetworkTransparency.tex PatternMatching.tex ReceivingMessages.tex SendingMessages.tex StronglyTypedActors.tex SpawningActors.tex SynchronousMessages.tex TypeSystem.tex manual.tex
all: pdf html
pdf: manual.pdf
html: manual.html
clean:
@for i in $(DIRS); do $(MAKE) -C $$i $@; done
rm -f manual.pdf
rm -f manual.html
manual.pdf: $(SOURCES)
$(MAKE) -C build-pdf && cp build-pdf/manual.pdf manual.pdf
manual.html: $(SOURCES)
$(MAKE) -C build-html && cp build-html/manual.html manual.html
.PHONY: all clean
\section{Message Priorities}
By default, all messages have the same priority and actors ignore priority flags.
Actors that should evaluate priorities must be spawned using the \lstinline^priority_aware^ flag.
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}
void testee() {
// send 'b' with normal priority
send(self, atom("b"));
// send 'a' with high priority
send({self, message_priority::high}, atom("a"));
// terminate after receiving a 'b'
become (
on(atom("b")) >> [] {
aout << "received 'b' => quit" << endl;
self->quit();
},
on(atom("a")) >> [] {
aout << "received 'a'" << endl;
},
);
}
int main() {
// will print "received 'b' => quit"
spawn(testee);
await_all_others_done();
// will print "received 'a'" and then "received 'b' => quit"
spawn<priority_aware>(testee);
await_all_others_done();
shutdown();
}
\end{lstlisting}
\section{Network Transparency}
All actor operations as well as sending messages are network transparent.
Remote actors are represented by actor proxies that forward all messages.
\subsection{Publishing of Actors}
\begin{lstlisting}
void publish(actor_ptr whom, std::uint16_t port, const char* addr = 0)
\end{lstlisting}
The function \lstinline^publish^ binds an actor to a given port.
It throws \lstinline^network_error^ if socket related errors occur or \lstinline^bind_failure^ if the specified port is already in use.
The optional \lstinline^addr^ parameter can be used to listen only to the given IP address.
Otherwise, the actor accepts all incoming connections (\lstinline^INADDR_ANY^).
\begin{lstlisting}
publish(self, 4242);
become (
on(atom("ping"), arg_match) >> [](int i) {
reply(atom("pong"), i);
}
);
\end{lstlisting}
\subsection{Connecting to Remote Actors}
\begin{lstlisting}
actor_ptr remote_actor(const char* host, std::uint16_t port)
\end{lstlisting}
The function \lstinline^remote_actor^ connects to the actor at given host and port.
A \lstinline^network_error^ is thrown if the connection failed.
\begin{lstlisting}
auto pong = remote_actor("localhost", 4242);
send(pong, atom("ping"), 0);
become (
on(atom("pong"), 10) >> [] {
self->quit();
},
on(atom("pong"), arg_match) >> [](int i) {
reply(atom("ping"), i+1);
}
);
\end{lstlisting}
\section{OpenCL-based Actors}
\libcppa supports transparent integration of OpenCL functions.
\begin{lstlisting}
// opencl kernel for matrix multiplication;
// last parameter is, by convention, the output parameter
constexpr const char* kernel_source = R"__(
__kernel void matrix_mult(__global float* matrix1,
__global float* matrix2,
__global float* output) {
// we only use square matrices, hence: width == height
size_t size = get_global_size(0); // == get_global_size_(1);
size_t x = get_global_id(0);
size_t y = get_global_id(1);
float result = 0;
for (size_t idx = 0; idx < size; ++idx)
result += matrix1[idx + y * size] * matrix2[x + idx * size];
output[x + y * size] = result;
}
)__";
\end{lstlisting}
This diff is collapsed.
\section{Receiving Messages}
\label{Sec::Receive}
The current \textit{behavior} of an actor is its response to the \textit{next} incoming message and includes (a) sending messages to other actors, (b) creation of more actors, and (c) setting a new behavior.
An event-based actor, i.e., the default implementation in \libcppa, uses \lstinline^become^ to set its behavior.
The given behavior is then executed until it is replaced by another call to \lstinline^become^ or the actor finishes execution.
\subsection{Class-based actors}
A class-based actor is a subtype of \lstinline^event_based_actor^ and must implement the pure virtual member function \lstinline^init^.
An implementation of \lstinline^init^ shall set an initial behavior by using \lstinline^become^.
\begin{lstlisting}
class printer : public event_based_actor {
void init() {
become (
others() >> [] {
cout << to_string(self->last_received()) << endl;
}
);
}
};
\end{lstlisting}
Another way to implement class-based actors is provided by the class \lstinline^sb_actor^ (``State-Based Actor'').
This base class calls \lstinline^become(init_state)^ in its \lstinline^init^ member function.
Hence, a subclass must only provide a member of type \lstinline^behavior^ named \lstinline^init_state^.
\begin{lstlisting}
struct printer : sb_actor<printer> {
behavior init_state = (
others() >> [] {
cout << to_string(self->last_received()) << endl;
}
);
};
\end{lstlisting}
Note that \lstinline^sb_actor^ uses the Curiously Recurring Template Pattern. Thus, the derived class must be given as template parameter.
This technique allows \lstinline^sb_actor^ to access the \lstinline^init_state^ member of a derived class.
The following example illustrates a more advanced state-based actor that implements a stack with a fixed maximum number of elements.
Note that this example uses non-static member initialization and thus might not compile with some compilers.
\clearpage
\begin{lstlisting}
class fixed_stack : public sb_actor<fixed_stack> {
// grant access to the private init_state member
friend class sb_actor<fixed_stack>;
static constexpr size_t max_size = 10;
std::vector<int> data;
behavior empty = (
on(atom("push"), arg_match) >> [=](int what) {
data.push_back(what);
become(filled);
},
on(atom("pop")) >> [=]() {
reply(atom("failure"));
}
);
behavior filled = (
on(atom("push"), arg_match) >> [=](int what) {
data.push_back(what);
if (data.size() == max_size)
become(full);
},
on(atom("pop")) >> [=]() {
reply(atom("ok"), data.back());
data.pop_back();
if (data.empty())
become(empty);
}
);
behavior full = (
on(atom("push"), arg_match) >> [=](int) { },
on(atom("pop")) >> [=]() {
reply(atom("ok"), data.back());
data.pop_back();
become(filled);
}
);
behavior& init_state = empty;
};
\end{lstlisting}
\clearpage
\subsection{Nesting Receives Using \lstinline^become/unbecome^}
Since \lstinline^become^ does not block, an actor has to manipulate its behavior stack to achieve nested receive operations.
An actor can set a new behavior by calling \lstinline^become^ with the \lstinline^keep_behavior^ policy to be able to return to its previous behavior later on by calling \lstinline^unbecome^, as shown in the example below.
\begin{lstlisting}
// receives {int, float} sequences
void testee() {
become (
on_arg_match >> [=](int value1) {
become (
// the keep_behavior policy stores the current behavior
// on the behavior stack to be able to return to this
// behavior later on by calling unbecome()
keep_behavior,
on_arg_match >> [=](float value2) {
cout << value1 << " => " << value2 << endl;
// restore previous behavior
unbecome();
}
);
}
);
}
\end{lstlisting}
An event-based actor finishes execution with normal exit reason if the behavior stack is empty after calling \lstinline^unbecome^.
The default policy of \lstinline^become^ is \lstinline^discard_behavior^ that causes an actor to override its current behavior.
The policy flag must be the first argument of \lstinline^become^.
\textbf{Note}: the message handling in \libcppa is consistent among all actor implementations: unmatched messages are \textit{never} implicitly discarded if no suitable handler was found.
Hence, the order of arrival is not important in the example above.
This is unlike other event-based implementations of the actor model such as Akka for instance.
\clearpage
\subsection{Timeouts}
\label{Sec::Receive::Timeouts}
A behavior set by \lstinline^become^ is invoked whenever a new messages arrives.
If no message ever arrives, the actor would wait forever.
This might be desirable if the actor only provides a service and should not do anything else.
But often, we need to be able to recover if an expected messages does not arrive within a certain time period. The following examples illustrates the usage of \lstinline^after^ to define a timeout.
\begin{lstlisting}
#include <chrono>
#include <iostream>
#include "cppa/cppa.hpp"
using std::endl;
void eager_actor() {
become (
on_arg_match >> [](int i) { /* ... */ },
on_arg_match >> [](float i) { /* ... */ },
others() >> [] { /* ... */ },
after(std::chrono::seconds(10)) >> []() {
aout << "received nothing within 10 seconds..." << endl;
// ...
}
);
}
\end{lstlisting}
Callbacks given as timeout handler must have zero arguments.
Any number of patterns can precede the timeout definition, but ``\lstinline^after^'' must always be the final statement.
Using a zero-duration timeout causes the actor to scan its mailbox once and then invoke the timeout immediately if no matching message was found.
\libcppa supports timeouts using \lstinline^minutes^, \lstinline^seconds^, \lstinline^milliseconds^ and \lstinline^microseconds^.
However, note that the precision depends on the operating system and your local work load.
Thus, you should not depend on a certain clock resolution.
\clearpage
\subsection{Skipping Messages}
Unmatched messages are skipped automatically by \libcppa's runtime system.
This is true for \textit{all} actor implementations.
To allow actors to skip messages manually, \lstinline^skip_message^ can be used.
This is in particular useful whenever an actor switches between behaviors, but wants to use a default rule created by \lstinline^others()^ to filter messages that are not handled by any of its behaviors.
The following example illustrates a simple server actor that dispatches requests to workers.
After receiving an \lstinline^'idle'^ message, it awaits a request that is then forwarded to the idle worker.
Afterwards, the server returns to its initial behavior, i.e., awaits the next \lstinline^'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}
void server() {
auto die = [=] { self->quit(exit_reason::user_defined); };
become (
on(atom("idle")) >> [=] {
auto worker = last_sender();
become (
keep_behavior,
on(atom("request")) >> [=] {
// forward request to idle worker
forward_to(worker);
// await next idle message
unbecome();
},
on(atom("idle")) >> skip_message,
others() >> die
);
},
on(atom("request")) >> skip_message,
others() >> die
);
}
\end{lstlisting}
\section{Sending Messages}
\label{Sec::Send}
Messages can be sent by using \lstinline^send^, \lstinline^send_tuple^, or \lstinline^operator<<^. The variadic template function \lstinline^send^ has the following signature.
\begin{lstlisting}
template<typename... Args>
void send(actor_ptr whom, Args&&... what);
\end{lstlisting}
The variadic template pack \lstinline^what...^ is converted to a dynamically typed tuple (see Section \ref{Sec::Tuples::DynamicallyTypedTuples}) and then enqueued to the mailbox of \lstinline^whom^.
The following example shows two equal sends, one using \lstinline^send^ and the other using \lstinline^operator<<^.
\begin{lstlisting}
actor_ptr other = spawn(...);
send(other, 1, 2, 3);
other << make_any_tuple(1, 2, 3);
\end{lstlisting}
Using the function \lstinline^send^ is more compact, but does not have any other benefit.
However, note that you should not use \lstinline^send^ if you already have an instance of \lstinline^any_tuple^, because it creates a new tuple containing the old one.
\begin{lstlisting}
actor_ptr other = spawn(...);
auto msg = make_any_tuple(1, 2, 3);
send(other, msg); // oops, creates a new tuple that contains msg
send_tuple(other, msg); // ok
other << msg; // ok
\end{lstlisting}
The function \lstinline^send_tuple^ is equal to \lstinline^operator<<^.
Choosing one or the other is merely a matter of personal preferences.
\clearpage
\subsection{Replying to Messages}
\label{Sec::Send::Reply}
During callback invokation, \lstinline^self->last_sender()^ is set.
This identifies the sender of the received message and is used implicitly by the functions \lstinline^reply^ and \lstinline^reply_tuple^.
Using \lstinline^reply(...)^ is \textbf{not} equal to \lstinline^send(self->last_sender(), ...)^.
The function \lstinline^send^ always uses asynchronous message passing, whereas \lstinline^reply^ will send a synchronous response message if the received message was a synchronous request (see Section \ref{Sec::Sync}).
%Note that you cannot reply more than once.
To delay a response, i.e., reply to a message after receiving another message, actors can use \lstinline^self->make_response_handle()^.
The functions \lstinline^reply_to^ and \lstinline^reply_tuple_to^ then can be used to reply the the original request, as shown in the example below.
\begin{lstlisting}
void broker(const actor_ptr& master) {
become (
on("foo", arg_match) >> [=](const std::string& request) {
auto hdl = make_response_handle();
sync_send(master, atom("bar"), request).then(
on_arg_match >> [=](const std::string& response) {
reply_to(hdl, response);
}
);
}
);
};
\end{lstlisting}
In any case, do never reply than more than once.
Additional (synchronous) response message will be ignored by the receiver.
\clearpage
\subsection{Chaining}
\label{Sec::Send::ChainedSend}
Sending a message to a cooperatively scheduled actor usually causes the receiving actor to be put into the scheduler's job queue if it is currently blocked, i.e., is waiting for a new message.
This job queue is accessed by worker threads.
The \textit{chaining} optimization does not cause the receiver to be put into the scheduler's job queue if it is currently blocked.
The receiver is stored as successor of the currently running actor instead.
Hence, the active worker thread does not need to access the job queue, which significantly speeds up execution.
However, this optimization can be inefficient if an actor first sends a message and then starts computation.
\begin{lstlisting}
void foo(actor_ptr other) {
send(other, ...);
very_long_computation();
// ...
}
int main() {
// ...
auto a = spawn(...);
auto b = spawn(foo, a);
// ...
}
\end{lstlisting}
The example above illustrates an inefficient work flow.
The actor \lstinline^other^ is marked as successor of the \lstinline^foo^ actor but its execution is delayed until \lstinline^very_long_computation()^ is done.
In general, actors should follow the work flow \lstinline^receive^ $\Rightarrow$\lstinline^compute^ $\Rightarrow$ \lstinline^send results^.
However, this optimization can be disabled by calling \lstinline^self->chaining(false)^ if an actor does not match this work flow.
\begin{lstlisting}
void foo(actor_ptr other) {
self->chaining(false); // disable chaining optimization
send(other, ...); // not delayed by very_long_compuation
very_long_computation();
// ...
}
\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^.
\begin{lstlisting}
delayed_send(self, std::chrono::seconds(1), atom("poll"));
become (
on(atom("poll")) >> []() {
// poll a resource...
// schedule next polling
delayed_send(self, std::chrono::seconds(1), atom("poll"));
}
);
\end{lstlisting}
\clearpage
\subsection{Forwarding Messages}
The function \lstinline^forward_to^ forwards the last dequeued message to an other actor.
Forwarding a synchronous message will also transfer responsibility for the request, i.e., the receiver of the forwarded message can reply as usual and the original sender of the message will receive the response.
The following diagram illustrates forwarding of a synchronous message from actor \texttt{B} to actor \texttt{C}.
\begin{footnotesize}
\begin{verbatim}
A B C
| | |
| --(sync_send)--> | |
| | --(forward_to)-> |
| X |---\
| | | compute
| | | result
| |<--/
| <-------------(reply)-------------- |
| X
|---\
| | handle
| | response
|<--/
|
X
\end{verbatim}
\end{footnotesize}
The forwarding is completely transparent to actor \texttt{C}, since it will see actor \texttt{A} as sender of the message.
However, actor \texttt{A} will see actor \texttt{C} as sender of the response message instead of actor \texttt{B} and thus could recognize the forwarding by evaluating \lstinline^self->last_sender()^.
\ No newline at end of file
\section{Spawning Actors}
Actors are created using the function \lstinline^spawn^.
%The arguments passed to \lstinline^spawn^ depend on the actor's implementation.
%\subsection{Using \lstinline^spawn^ to Create Actors from Functors or Classes}
The easiest way to implement actors is to use functors, e.g., a free function or lambda expression.
The arguments to the functor are passed to \lstinline^spawn^ as additional arguments.
The function \lstinline^spawn^ also takes optional flags as template paremeter.
%The optional template parameter of \lstinline^spawn^ decides whether an actor should run in its own thread or takes place in the cooperative scheduling.
The flag \lstinline^detached^ causes \lstinline^spawn^ to create a thread-mapped actor (opt-out of the cooperative scheduling), the flag \lstinline^linked^ links the newly created actor to its parent, and the flag \lstinline^monitored^ automatically adds a monitor to the new actor.
Actors that make use of the blocking API (see Section \ref{Sec::BlockingAPI}) must be spawned using the flag \lstinline^blocking_api^.
Flags are concatenated using the operator \lstinline^+^, as shown in the examples below.
\begin{lstlisting}
#include "cppa/cppa.hpp"
using namespace cppa;
void my_actor1();
void my_actor2(int arg1, const std::string& arg2);
void ugly_duckling();
class my_actor3 : public event_based_actor { /* ... */ };
class my_actor4 : public sb_actor<my_actor4> {
public: my_actor4(int some_value) { /* ... */ }
/* ... */
};
int main() {
// spawn function-based actors
auto a0 = spawn(my_actor1);
auto a1 = spawn<linked>(my_actor2, 42, "hello actor");
auto a2 = spawn<monitored>([] { /* ... */ });
auto a3 = spawn([](int) { /* ... */ }, 42);
// spawn thread-mapped actors
auto a4 = spawn<detached>(my_actor1);
auto a5 = spawn<detached + linked>([] { /* ... */ });
auto a6 = spawn<detached>(my_actor2, 0, "zero");
// spawn class-based actors
auto a7 = spawn<my_actor3>();
auto a8 = spawn<my_actor4, monitored>(42);
// spawn thread-mapped actors using a class
auto a9 = spawn<my_actor4, detached>(42);
// spawn actors that need access to the blocking API
auto b0 = spawn<blocking_api>(ugly_duckling);
}
\end{lstlisting}
\textbf{Note}: \lstinline^spawn(fun, arg0, ...)^ is \textbf{not} equal to \lstinline^spawn(std::bind(fun, arg0, ...))^!
For example, a call to \lstinline^spawn(fun, self, ...)^ will pass a pointer to the calling actor to the newly created actor, as expected, whereas \lstinline^spawn(std::bind(fun, self, ...))^ wraps the type of \lstinline^self^ into the function wrapper and evaluates \lstinline^self^ on function invocation.
Thus, the actor will end up having a pointer \emph{to itself} rather than a pointer to its parent.
\section{Strongly Typed Actors}
\section{Synchronous Communication}
\label{Sec::Sync}
\libcppa uses a future-based API for synchronous communication.
The functions \lstinline^sync_send^ and \lstinline^sync_send_tuple^ send synchronous request messages to the receiver and return a future to the response message.
Note that the returned future is \textit{actor-local}, i.e., only the actor that has send the corresponding request message is able to receive the response identified by such a future.
\begin{lstlisting}
template<typename... Args>
message_future sync_send(actor_ptr whom, Args&&... what);
message_future sync_send_tuple(actor_ptr whom, any_tuple what);
template<typename Duration, typename... Args>
message_future timed_sync_send(actor_ptr whom,
Duration timeout,
Args&&... what);
template<typename Duration, typename... Args>
message_future timed_sync_send_tuple(actor_ptr whom,
Duration timeout,
any_tuple what);
\end{lstlisting}
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}).
When using \lstinline^timed_sync_send^ function, \lstinline^after(...)^ statements are ignored and the actor will receive a \lstinline^'TIMEOUT'^ message after the given duration instead.
\subsection{Error Messages}
When using synchronous messaging, \libcppa's runtime environment will send ...
\begin{itemize}
\item \lstinline^{'EXITED', uint32_t exit_reason}^ if the receiver is not alive
\item \lstinline^{'VOID'}^ if the receiver handled the message but did not call \lstinline^reply^
\item \lstinline^{'TIMEOUT'}^ if a message send by \lstinline^timed_sync_send^ timed out
\end{itemize}
\clearpage
\subsection{Receive Response Messages}
The function \lstinline^handle_response^ can be used to set a one-shot handler receiving the response message send by \lstinline^sync_send^.
\begin{lstlisting}
actor_ptr testee = ...; // replies with a string to 'get'
// "handle_response" usage example
auto handle = sync_send(testee, atom("get"));
handle_response (handle) (
on_arg_match >> [=](const std::string& str) {
// handle str
},
after(std::chrono::seconds(30)) >> [=]() {
// handle error
}
);
\end{lstlisting}
Similar to \lstinline^become^, the function \lstinline^handle_response^ modifies an actor's behavior stack.
However, it is used as ``one-shot handler'' and automatically returns the previous actor behavior afterwards.
It is possible to ``stack'' multiple \lstinline^handle_response^ calls.
Each response handler is executed once and then automatically discarded.
\subsection{Synchronous Failures and Error Handlers}
An unexpected response message, i.e., a message that is not handled by given behavior, will invoke the actor's \lstinline^on_sync_failure^ handler.
The default handler kills the actor by calling \lstinline^self->quit(exit_reason::unhandled_sync_failure)^.
The handler can be overridden by calling \lstinline^self->on_sync_failure(/*...*/)^.
Unhandled \lstinline^'TIMEOUT'^ messages trigger the \lstinline^on_sync_timeout^ handler.
The default handler kills the actor for reason \lstinline^exit_reason::unhandled_sync_failure^.
It is possible set both error handlers by calling \lstinline^self->on_sync_timeout_or_failure(/*...*)^.
\clearpage
\subsection{Using \lstinline^then^ to Receive a Response}
Often, an actor sends a synchronous message and then wants to wait for the response.
In this case, using either \lstinline^handle_response^ is quite verbose.
To allow for a more compact code, \lstinline^message_future^ provides the member function \lstinline^then^.
Using this member function is equal to using \lstinline^handle_response^, as illustrated by the following example.
\begin{lstlisting}
actor_ptr testee = ...; // replies with a string to 'get'
// set handler for unexpected messages
self->on_sync_failure = [] {
aout << "received: " << to_string(self->last_dequeued()) << endl;
};
// set handler for timeouts
self->on_sync_timeout = [] {
aout << "timeout occured" << endl;
};
// set response handler by using "then"
timed_sync_send(testee, std::chrono::seconds(30), atom("get")).then(
on_arg_match >> [=](const std::string& str) { /* handle str */ }
);
\end{lstlisting}
\subsubsection{Using Functors without Patterns}
To reduce verbosity, \libcppa supports synchronous response handlers without patterns.
In this case, the pattern is automatically deduced by the functor's signature.
\begin{lstlisting}
actor_ptr testee = ...; // replies with a string to 'get'
// (1) functor only usage
sync_send(testee, atom("get")).then(
[=](const std::string& str) { /*...*/ }
);
// statement (1) is equal to:
sync_send(testee, atom("get")).then(
on(any_vals, arg_match) >> [=](const std::string& str) { /*...*/ }
);
\end{lstlisting}
\subsubsection{Continuations for Event-based Actors}
\libcppa supports continuations to enable chaining of send/receive statements.
The functions \lstinline^handle_response^ and \lstinline^message_future::then^ both return a helper object offering \lstinline^continue_with^, which takes a functor $f$ without arguments.
After receiving a message, $f$ is invoked if and only if the received messages was handled successfully, i.e., neither \lstinline^sync_failure^ nor \lstinline^sync_timeout^ occurred.
\begin{lstlisting}
actor_ptr d_or_s = ...; // replies with either a double or a string
sync_send(d_or_s, atom("get")).then(
[=](double value) { /* functor f1 */ },
[=](const string& value) { /* functor f2*/ }
).continue_with([=] {
// this continuation is invoked in both cases
// *after* f1 or f2 is done, but *not* in case
// of sync_failure or sync_timeout
});
\end{lstlisting}
\section{Platform-Independent Type System}
\label{Sec::TypeSystem}
\libcppa provides a fully network transparent communication between actors.
Thus, \libcppa needs to serialize and deserialize messages.
Unfortunately, this is not possible using the RTTI system of C++.
\libcppa uses its own RTTI based on the class \lstinline^uniform_type_info^, since it is not possible to extend \lstinline^std::type_info^.
Unlike \lstinline^std::type_info::name()^, \lstinline^uniform_type_info::name()^ is guaranteed to return the same name on all supported platforms. Furthermore, it allows to create an instance of a type by name.
\begin{lstlisting}
// creates a signed, 32 bit integer
cppa::object i = cppa::uniform_typeid<int>()->create();
\end{lstlisting}
However, you should rarely if ever need to use \lstinline^object^ or \lstinline^uniform_type_info^.
\subsection{User-Defined Data Types in Messages}
\label{Sec::TypeSystem::UserDefined}
All user-defined types must be explicitly ``announced'' so that \libcppa can (de)serialize them correctly, as shown in the example below.
\begin{lstlisting}
#include "cppa/cppa.hpp"
using namespace cppa;
struct foo { int a; int b; };
int main() {
announce<foo>(&foo::a, &foo::b);
send(self, foo{1,2});
return 0;
}
\end{lstlisting}
Without the \lstinline^announce^ function call, the example program would terminate with an exception, because \libcppa rejects all types without available runtime type information.
\lstinline^announce()^ takes the class as template parameter and pointers to all members (or getter/setter pairs) as arguments.
This works for all primitive data types and STL compliant containers.
See the announce examples 1 -- 4 of the standard distribution for more details.
Obviously, there are limitations.
You have to implement serialize/deserialize by yourself if your class does implement an unsupported data structure.
See \lstinline^announce_example_5.cpp^ in the examples folder.
\ No newline at end of file
HEVEA=hevea
HEVEA_ARGS=-I ..
all:
$(HEVEA) $(HEVEA_ARGS) manual.tex
$(HEVEA) $(HEVEA_ARGS) manual.tex
$(HEVEA) $(HEVEA_ARGS) manual.tex
clean:
rm -f *.haux *.html *.htoc
.PHONY: all clean
PDFLATEX="pdflatex"
all:
@TEXINPUTS="..:" $(PDFLATEX) manual.tex
@TEXINPUTS="..:" $(PDFLATEX) manual.tex
@TEXINPUTS="..:" $(PDFLATEX) manual.tex
clean:
rm -f *.aux *.toc *.pdf *.log *.out
.PHONY: all clean
%%
%% This is file `cmbright.sty',
%% generated with the docstrip utility.
%%
%% The original source files were:
%%
%% cmbright.dtx (with options: `package')
%%
%% IMPORTANT NOTICE:
%%
%% For the copyright see the source file.
%%
%% Any modified versions of this file must be renamed
%% with new filenames distinct from cmbright.sty.
%%
%% For distribution of the original source see the terms
%% for copying and modification in the file cmbright.dtx.
%%
%% This generated file may be distributed as long as the
%% original source files, as listed above, are part of the
%% same distribution. (The sources need not necessarily be
%% in the same archive or directory.)
\ProvidesPackage{cmbright}
[2005/04/13 v8.1 (WaS)]
\NeedsTeXFormat{LaTeX2e}[1995/06/01]
\renewcommand{\familydefault}{\sfdefault}
\renewcommand{\sfdefault}{cmbr}
\renewcommand{\ttdefault}{cmtl}
\DeclareSymbolFont {operators} {OT1}{cmbr}{m}{n}
\DeclareSymbolFont {letters} {OML}{cmbrm}{m}{it}
\SetSymbolFont {letters}{bold} {OML}{cmbrm}{b}{it}
\DeclareSymbolFont {symbols} {OMS}{cmbrs}{m}{n}
\DeclareMathAlphabet{\mathit} {OT1}{cmbr}{m}{sl}
\DeclareMathAlphabet{\mathbf} {OT1}{cmbr}{bx}{n}
\DeclareMathAlphabet{\mathtt} {OT1}{cmtl}{m}{n}
\DeclareMathAlphabet{\mathbold}{OML}{cmbrm}{b}{it}
\DeclareMathSymbol{\alpha}{\mathalpha}{letters}{11}
\DeclareMathSymbol{\beta}{\mathalpha}{letters}{12}
\DeclareMathSymbol{\gamma}{\mathalpha}{letters}{13}
\DeclareMathSymbol{\delta}{\mathalpha}{letters}{14}
\DeclareMathSymbol{\epsilon}{\mathalpha}{letters}{15}
\DeclareMathSymbol{\zeta}{\mathalpha}{letters}{16}
\DeclareMathSymbol{\eta}{\mathalpha}{letters}{17}
\DeclareMathSymbol{\theta}{\mathalpha}{letters}{18}
\DeclareMathSymbol{\iota}{\mathalpha}{letters}{19}
\DeclareMathSymbol{\kappa}{\mathalpha}{letters}{20}
\DeclareMathSymbol{\lambda}{\mathalpha}{letters}{21}
\DeclareMathSymbol{\mu}{\mathalpha}{letters}{22}
\DeclareMathSymbol{\nu}{\mathalpha}{letters}{23}
\DeclareMathSymbol{\xi}{\mathalpha}{letters}{24}
\DeclareMathSymbol{\pi}{\mathalpha}{letters}{25}
\DeclareMathSymbol{\rho}{\mathalpha}{letters}{26}
\DeclareMathSymbol{\sigma}{\mathalpha}{letters}{27}
\DeclareMathSymbol{\tau}{\mathalpha}{letters}{28}
\DeclareMathSymbol{\upsilon}{\mathalpha}{letters}{29}
\DeclareMathSymbol{\phi}{\mathalpha}{letters}{30}
\DeclareMathSymbol{\chi}{\mathalpha}{letters}{31}
\DeclareMathSymbol{\psi}{\mathalpha}{letters}{32}
\DeclareMathSymbol{\omega}{\mathalpha}{letters}{33}
\DeclareMathSymbol{\varepsilon}{\mathalpha}{letters}{34}
\DeclareMathSymbol{\vartheta}{\mathalpha}{letters}{35}
\DeclareMathSymbol{\varpi}{\mathalpha}{letters}{36}
\DeclareMathSymbol{\varrho}{\mathalpha}{letters}{37}
\DeclareMathSymbol{\varsigma}{\mathalpha}{letters}{38}
\DeclareMathSymbol{\varphi}{\mathalpha}{letters}{39}
\DeclareOption{slantedGreek}{%
\DeclareMathSymbol{\Gamma}{\mathalpha}{letters}{0}
\DeclareMathSymbol{\Delta}{\mathalpha}{letters}{1}
\DeclareMathSymbol{\Theta}{\mathalpha}{letters}{2}
\DeclareMathSymbol{\Lambda}{\mathalpha}{letters}{3}
\DeclareMathSymbol{\Xi}{\mathalpha}{letters}{4}
\DeclareMathSymbol{\Pi}{\mathalpha}{letters}{5}
\DeclareMathSymbol{\Sigma}{\mathalpha}{letters}{6}
\DeclareMathSymbol{\Upsilon}{\mathalpha}{letters}{7}
\DeclareMathSymbol{\Phi}{\mathalpha}{letters}{8}
\DeclareMathSymbol{\Psi}{\mathalpha}{letters}{9}
\DeclareMathSymbol{\Omega}{\mathalpha}{letters}{10}
}
\let\upDelta\Delta
\let\upOmega\Omega
\let\upGamma\Gamma
\let\upTheta\Theta
\let\upLambda\Lambda
\let\upXi\Xi
\let\upPi\Pi
\let\upSigma\Sigma
\let\upUpsilon\Upsilon
\let\upPhi\Phi
\let\upPsi\Psi
\def\bright@baselineskip@table
{<\@viiipt>10<\@ixpt>11.25<\@xpt>12.5<\@xipt>13.7<\@xiipt>15}
\def\bright@setfontsize#1#2#3%
{\edef\@tempa{\def\noexpand\@tempb####1<#2}%
\@tempa>##2<##3\@nil{\def\bright@baselineskip@value{##2}}%
\edef\@tempa{\noexpand\@tempb\bright@baselineskip@table<#2}%
\@tempa><\@nil
\ifx\bright@baselineskip@value\@empty
\def\bright@baselineskip@value{#3}%
\fi
\old@setfontsize{#1}{#2}\bright@baselineskip@value}
\let\old@setfontsize=\@setfontsize
\DeclareOption{enlarged-baselineskips}{%
\let\@setfontsize=\bright@setfontsize}
\DeclareOption{standard-baselineskips}{%
\let\@setfontsize=\old@setfontsize}
\DeclareTextCommand{\textsterling}{OT1}{{%
\ifdim \fontdimen\@ne\font >\z@
\fontfamily{\rmdefault}\fontshape{it}\selectfont
\else
\fontfamily{\rmdefault}\fontshape{ui}\selectfont
\fi
\char`\$}}
\def\mathsterling{\textsl{\textsterling}}
\AtBeginDocument{%
\DeclareFontFamily{U}{msa}{}
\DeclareFontShape{U}{msa}{m}{n}{%
<-9>cmbras8%
<9-10>cmbras9%
<10->cmbras10%
}{}
\DeclareFontFamily{U}{msb}{}
\DeclareFontShape{U}{msb}{m}{n}{%
<-9>cmbrbs8%
<9-10>cmbrbs9%
<10->cmbrbs10%
}{}
}
\def\TeX{T\kern-.19em\lower.5ex\hbox{E}\kern-.05emX\@}
\DeclareRobustCommand{\LaTeX}{L\kern-.3em%
{\sbox\z@ T%
\vbox to\ht\z@{\hbox{\check@mathfonts
\fontsize\sf@size\z@
\math@fontsfalse\selectfont
A}%
\vss}%
}%
\kern-.15em%
\TeX}
\DeclareRobustCommand{\LaTeXe}{\mbox{\m@th
\if b\expandafter\@car\f@series\@nil\boldmath\fi
\LaTeX\kern.15em2$_{\textstyle\varepsilon}$}}
\ExecuteOptions{enlarged-baselineskips}
\ProcessOptions\relax
\normalfont\normalsize
\endinput
%%
%% End of file `cmbright.sty'.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Comment.sty version 3.0, 3 September 1992
% selectively in/exclude pieces of text: the user can define new
% comment versions, and each is controlled separately.
% Special comments can be defined where the user specifies the
% action that is to be taken with each comment line.
%
% This style can be used with plain TeX or LaTeX, and probably
% most other packages too.
%
% Author
% Victor Eijkhout
% Department of Computer Science
% University Tennessee at Knoxville
% 104 Ayres Hall
% Knoxville, TN 37996
% USA
%
% eijkhout@cs.utk.edu
%
% Usage: all text included in between
% \comment ... \endcomment
% or \begin{comment} ... \end{comment}
% is discarded. The closing command should appear on a line
% of its own. No starting spaces, nothing after it.
% This environment should work with arbitrary amounts
% of comment.
%
% Other 'comment' environments are defined by
% and are selected/deselected with
% \includecomment{versiona}
% \excludecoment{versionb}
%
% These environments are used as
% \versiona ... \endversiona
% or \begin{versiona} ... \end{versiona}
% with the closing command again on a line of its own.
%
% Special comments are defined as
% \specialcomment{name}{before commands}{after commands}
% where the second and third arguments are executed before
% and after each comment. By defining a control sequence
% \Thiscomment##1{...} in the before commands the user can
% specify what is to be done which each comment line.
%
% Basic approach:
% to comment something out, scoop up every line in verbatim mode
% as macro argument, then throw it away.
% For inclusions, both the opening and closing comands
% are defined as noop
\def\makeinnocent#1{\catcode`#1=12 }
\def\csarg#1#2{\expandafter#1\csname#2\endcsname}
\def\TreatAsComment#1{\begingroup
\def\CurrentComment{#1}%
\let\do\makeinnocent \dospecials
\makeinnocent\^^L% and whatever other special cases
\endlinechar`\^^M \catcode`\^^M=12 \xComment}
{\catcode`\^^M=12 \endlinechar=-1 %
\gdef\xComment#1^^M{\def\test{#1}
\csarg\ifx{PlainEnd\CurrentComment Test}\test
\def\next{\endgroup\AfterComment}%
\else \csarg\ifx{LolliEnd\CurrentComment Test}\test
\def\next{\endgroup\AfterComment}%
\else \csarg\ifx{LaLaEnd\CurrentComment Test}\test
\edef\next{\endgroup\noexpand\AfterComment
\noexpand\end{\CurrentComment}}
\else \ThisComment{#1}\let\next\xComment
\fi \fi \fi \next}
}
\def\includecomment
#1{\message{Including comment '#1'}%
\expandafter\def\csname#1\endcsname{}%
\expandafter\def\csname end#1\endcsname{}}
\def\excludecomment
#1{\message{Excluding comment '#1'}%
\csarg\def{#1}{\let\AfterComment\relax
\def\ThisComment####1{}\TreatAsComment{#1}}%
{\escapechar=-1\relax
\csarg\xdef{PlainEnd#1Test}{\string\\end#1}%
\csarg\xdef{LolliEnd#1Test}{\string\\#1Stop}%
\csarg\xdef{LaLaEnd#1Test}{\string\\end\string\{#1\string\}}%
}}
\long\def\specialcomment
#1#2#3{\message{Special comment '#1'}%
\csarg\def{#1}{\def\ThisComment{}\def\AfterComment{#3}#2%
\TreatAsComment{#1}}%
{\escapechar=-1\relax
\csarg\xdef{PlainEnd#1Test}{\string\\end#1}%
\csarg\xdef{LolliEnd#1Test}{\string\\#1Stop}%
\csarg\xdef{LaLaEnd#1Test}{\string\\end\string\{#1\string\}}%
}}
\excludecomment{comment}
\endinput
% hevea : hevea.sty
% This is a very basic style file for latex document to be processed
% with hevea. It contains definitions of LaTeX environment which are
% processed in a special way by the translator.
% Mostly :
% - latexonly, not processed by hevea, processed by latex.
% - htmlonly , the reverse.
% - rawhtml, to include raw HTML in hevea output.
% - toimage, to send text to the image file.
% The package also provides hevea logos, html related commands (ahref
% etc.), void cutting and image commands.
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{hevea}[2002/01/11]
\RequirePackage{comment}
\newif\ifhevea\heveafalse
\@ifundefined{ifimagen}{\newif\ifimagen\imagenfalse}
\makeatletter%
\newcommand{\heveasmup}[2]{%
\raise #1\hbox{$\m@th$%
\csname S@\f@size\endcsname
\fontsize\sf@size 0%
\math@fontsfalse\selectfont
#2%
}}%
\DeclareRobustCommand{\hevea}{H\kern-.15em\heveasmup{.2ex}{E}\kern-.15emV\kern-.15em\heveasmup{.2ex}{E}\kern-.15emA}%
\DeclareRobustCommand{\hacha}{H\kern-.15em\heveasmup{.2ex}{A}\kern-.15emC\kern-.1em\heveasmup{.2ex}{H}\kern-.15emA}%
\DeclareRobustCommand{\html}{\protect\heveasmup{0.ex}{HTML}}
%%%%%%%%% Hyperlinks hevea style
\newcommand{\ahref}[2]{{#2}}
\newcommand{\ahrefloc}[2]{{#2}}
\newcommand{\aname}[2]{{#2}}
\newcommand{\ahrefurl}[1]{\texttt{#1}}
\newcommand{\footahref}[2]{#2\footnote{\texttt{#1}}}
\newcommand{\mailto}[1]{\texttt{#1}}
\newcommand{\imgsrc}[2][]{}
\newcommand{\home}[1]{\protect\raisebox{-.75ex}{\char126}#1}
\AtBeginDocument
{\@ifundefined{url}
{%url package is not loaded
\let\url\ahref\let\oneurl\ahrefurl\let\footurl\footahref}
{}}
%% Void cutting instructions
\newcounter{cuttingdepth}
\newcommand{\tocnumber}{}
\newcommand{\notocnumber}{}
\newcommand{\cuttingunit}{}
\newcommand{\cutdef}[2][]{}
\newcommand{\cuthere}[2]{}
\newcommand{\cutend}{}
\newcommand{\htmlhead}[1]{}
\newcommand{\htmlfoot}[1]{}
\newcommand{\htmlprefix}[1]{}
\newenvironment{cutflow}[1]{}{}
\newcommand{\cutname}[1]{}
\newcommand{\toplinks}[3]{}
\newcommand{\setlinkstext}[3]{}
\newcommand{\flushdef}[1]{}
\newcommand{\footnoteflush}[1]{}
%%%% Html only
\excludecomment{rawhtml}
\newcommand{\rawhtmlinput}[1]{}
\excludecomment{htmlonly}
%%%% Latex only
\newenvironment{latexonly}{}{}
\newenvironment{verblatex}{}{}
%%%% Image file stuff
\def\toimage{\endgroup}
\def\endtoimage{\begingroup\def\@currenvir{toimage}}
\def\verbimage{\endgroup}
\def\endverbimage{\begingroup\def\@currenvir{verbimage}}
\newcommand{\imageflush}[1][]{}
%%% Bgcolor definition
\newsavebox{\@bgcolorbin}
\newenvironment{bgcolor}[2][]
{\newcommand{\@mycolor}{#2}\begin{lrbox}{\@bgcolorbin}\vbox\bgroup}
{\egroup\end{lrbox}%
\begin{flushleft}%
\colorbox{\@mycolor}{\usebox{\@bgcolorbin}}%
\end{flushleft}}
%%% Style sheets macros, defined as no-ops
\newcommand{\newstyle}[2]{}
\newcommand{\addstyle}[1]{}
\newcommand{\setenvclass}[2]{}
\newcommand{\getenvclass}[1]{}
\newcommand{\loadcssfile}[1]{}
\newenvironment{divstyle}[1]{}{}
\newenvironment{cellstyle}[2]{}{}
\newif\ifexternalcss
%%% Postlude
\makeatother
\documentclass[%
a4paper,% % DIN A4
oneside,% % einseitiger Druck
12pt,% % 12pt Schriftgröße
]{article}
%\usepackage{ifpdf}
%\usepackage[english]{babel}
% UTF8 input
\usepackage[utf8]{inputenc}
% grafics
%\usepackage{graphicx}
%\usepackage{picinpar}
% others
%\usepackage{parcolumns}
%\usepackage[font=footnotesize,format=plain,labelfont=bf]{caption}
%\usepackage{paralist}
\usepackage{url}
\usepackage{array}
%\usepackage{tocloft}
\usepackage{color}
\usepackage{listings}
\usepackage{xspace}
\usepackage{tabularx}
\usepackage{hyperref}
\usepackage{fancyhdr}
\usepackage{multicol}
\usepackage{hevea}
\usepackage{cmbright}
\usepackage{txfonts}
\usepackage[scaled=.90]{helvet}
\usepackage{courier}
%\usepackage{natbib}
%\usepackage{lmodern}
%\usepackage{newcent}
%\renewcommand{\ttdefault}{lmtt}
%\usepackage{fontspec}
%\defaultfontfeatures{Mapping=tex-text} % For archaic input (e.g. convert -- to en-dash)
%\setmainfont{Times New Roman} % Computer Modern Unicode font
%\setmonofont{Anonymous Pro}
%\setsansfont{Times New Roman}
% par. settings
\parindent 0pt
\parskip 8pt
\definecolor{blue}{rgb}{0,0,1}
\definecolor{violet}{rgb}{0.5,0,0.5}
\definecolor{darkred}{rgb}{0.5,0,0}
\definecolor{darkblue}{rgb}{0,0,0.5}
\definecolor{darkgreen}{rgb}{0,0.5,0}
\newcommand{\libcppa}{\textit{libcppa}\xspace}
\pagenumbering{arabic}
\title{%
%BEGIN LATEX
\texttt{\huge{\textbf{libcppa}}}\\~\\A C++ library for actor programming\\~\\~\\~\\%
%END LATEX
User Manual\\\normalsize{\texttt{libcppa} version 0.8}\vfill}
\author{Dominik Charousset}
\date{\today}
% page setup
\setlength{\voffset}{-0.5in}
\setlength{\hoffset}{-0.5in}
\addtolength{\textwidth}{1in}
\addtolength{\textheight}{1.5in}
\setlength{\headheight}{15pt}
% some HEVEA / HTML style sheets
\newstyle{body}{width:600px;margin:auto;padding-top:20px;text-align: justify;}
\newenvironment{itemize*}%
{\begin{itemize}%
\setlength{\itemsep}{0pt}%
\setlength{\parskip}{0pt}}%
{\end{itemize}}
\begin{document}
%\fontfamily{ptm}\selectfont
%BEGIN LATEX
\fancypagestyle{plain}{%
\fancyhf{} % clear all header and footer fields
\renewcommand{\headrulewidth}{0pt}
\renewcommand{\footrulewidth}{0pt}
}
%END LATEX
\maketitle
\clearpage
\pagestyle{empty}
\tableofcontents
\clearpage
%BEGIN LATEX
\setcounter{page}{1}
\pagenumbering{arabic}
\pagestyle{fancy}
\fancyhead[L,R]{}
\fancyhead[C]{\leftmark}
\renewcommand{\sectionmark}[1]{%
\markboth{\MakeUppercase{#1}}{}%
}
%END LATEX
%{\parskip=0mm \tableofcontents}
% basic setup for listings
\lstset{%
language=C++,%
morekeywords={constexpr,nullptr,size_t,uint32_t,assert},%
basicstyle=\ttfamily\small,%
sensitive=true,%
keywordstyle=\color{blue},%
stringstyle=\color{darkgreen},%
commentstyle=\color{violet},%
showstringspaces=false,%
tabsize=4,%
numberstyle=\footnotesize%
}
\include{FirstSteps}
\include{CopyOnWriteTuples}
\include{PatternMatching}
\include{Actors}
\include{SendingMessages}
\include{ReceivingMessages}
\include{SynchronousMessages}
\include{ActorManagement}
\include{SpawningActors}
\include{MessagePriorities}
\include{StronglyTypedActors}
\include{NetworkTransparency}
\include{GroupCommunication}
\include{ActorCompanions}
\include{TypeSystem}
\include{BlockingAPI}
%\include{OpenCL}
\include{CommonPitfalls}
\include{Appendix}
%\clearpage
%\bibliographystyle{dinat}
%\bibliographystyle{apalike}
%\bibliography{/bib/programming,/bib/rfcs}
%\clearpage
%{\parskip=0mm \listoffigures}
%\clearpage
\end{document}
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