Commit f15f5afc authored by Dominik Charousset's avatar Dominik Charousset

Convert manual to reStructuredText

(cherry picked from commit 5c274689)
parent 4e96bbf2
This diff is collapsed.
This diff is collapsed.
\section{Common Pitfalls} .. _pitfalls:
\label{pitfalls}
Common Pitfalls
===============
This Section highlights common mistakes or C++ subtleties that can show up when This Section highlights common mistakes or C++ subtleties that can show up when
programming in CAF. programming in CAF.
\subsection{Defining Message Handlers} Defining Message Handlers
-------------------------
C++ evaluates comma-separated expressions from left-to-right, using only the C++ evaluates comma-separated expressions from left-to-right, using only the
last element as return type of the whole expression. This means that message last element as return type of the whole expression. This means that message
handlers and behaviors must \emph{not} be initialized like this: handlers and behaviors must *not* be initialized like this:
.. code-block:: C++
\begin{lstlisting} message_handler wrong = (
message_handler wrong = ( [](int i) { /*...*/ },
[](int i) { /*...*/ }, [](float f) { /*...*/ }
[](float f) { /*...*/ } );
);
\end{lstlisting}
The correct way to initialize message handlers and behaviors is to either The correct way to initialize message handlers and behaviors is to either
use the constructor or the member function \lstinline^assign^: use the constructor or the member function ``assign``:
\begin{lstlisting} .. code-block:: C++
message_handler ok1{
[](int i) { /*...*/ }, message_handler ok1{
[](float f) { /*...*/ } [](int i) { /*...*/ },
}; [](float f) { /*...*/ }
};
message_handler ok2;
// some place later message_handler ok2;
ok2.assign( // some place later
[](int i) { /*...*/ }, ok2.assign(
[](float f) { /*...*/ } [](int i) { /*...*/ },
); [](float f) { /*...*/ }
\end{lstlisting} );
\subsection{Event-Based API} Event-Based API
---------------
The member function \lstinline^become^ does not block, i.e., always returns
immediately. Thus, lambda expressions should \textit{always} capture by value. The member function ``become`` does not block, i.e., always returns
immediately. Thus, lambda expressions should *always* capture by value.
Otherwise, all references on the stack will cause undefined behavior if the Otherwise, all references on the stack will cause undefined behavior if the
lambda expression is executed. lambda expression is executed.
\subsection{Requests} Requests
--------
A handle returned by \lstinline^request^ represents \emph{exactly one} response A handle returned by ``request`` represents *exactly one* response
message. It is not possible to receive more than one response message. message. It is not possible to receive more than one response message.
The handle returned by \lstinline^request^ is bound to the calling actor. It is The handle returned by ``request`` is bound to the calling actor. It is
not possible to transfer a handle to a response to another actor. not possible to transfer a handle to a response to another actor.
\clearpage Sharing
\subsection{Sharing} -------
It is strongly recommended to \textbf{not} share states between actors. In It is strongly recommended to **not** share states between actors. In
particular, no actor shall ever access member variables or member functions of particular, no actor shall ever access member variables or member functions of
another actor. Accessing shared memory segments concurrently can cause undefined another actor. Accessing shared memory segments concurrently can cause undefined
behavior that is incredibly hard to find and debug. However, sharing 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} *data* between actors is fine, as long as the data is *immutable*
and its lifetime is guaranteed to outlive all actors. The simplest way to meet and its lifetime is guaranteed to outlive all actors. The simplest way to meet
the lifetime guarantee is by storing the data in smart pointers such as the lifetime guarantee is by storing the data in smart pointers such as
\lstinline^std::shared_ptr^. Nevertheless, the recommended way of sharing ``std::shared_ptr``. Nevertheless, the recommended way of sharing
informations is message passing. Sending the same message to multiple actors information is message passing. Sending the same message to multiple actors
does not result in copying the data several times. does not result in copying the data several times.
This diff is collapsed.
\section{Errors} .. _error:
\label{error}
Errors
Errors in CAF have a code and a category, similar to ======
\lstinline^std::error_code^ and \lstinline^std::error_condition^. Unlike its
counterparts from the C++ standard library, \lstinline^error^ is Errors in CAF have a code and a category, similar to ``std::error_code`` and
plattform-neutral and serializable. Instead of using category singletons, CAF ``std::error_condition``. Unlike its counterparts from the C++ standard library,
stores categories as atoms~\see{atom}. Errors can also include a message to ``error`` is plattform-neutral and serializable. Instead of using category
provide additional context information. singletons, CAF stores categories as atoms (see :ref:`atom`). Errors can also
include a message to provide additional context information.
\subsection{Class Interface}
Class Interface
\begin{center} ---------------
\begin{tabular}{ll}
\textbf{Constructors} & ~ \\ +-----------------------------------------+--------------------------------------------------------------------+
\hline | **Constructors** | |
\lstinline^(Enum x)^ & Construct error by calling \lstinline^make_error(x)^ \\ +-----------------------------------------+--------------------------------------------------------------------+
\hline | ``(Enum x)`` | Construct error by calling ``make_error(x)`` |
\lstinline^(uint8_t x, atom_value y)^ & Construct error with code \lstinline^x^ and category \lstinline^y^ \\ +-----------------------------------------+--------------------------------------------------------------------+
\hline | ``(uint8_t x, atom_value y)`` | Construct error with code ``x`` and category ``y`` |
\lstinline^(uint8_t x, atom_value y, message z)^ & Construct error with code \lstinline^x^, category \lstinline^y^, and context \lstinline^z^ \\ +-----------------------------------------+--------------------------------------------------------------------+
\hline | ``(uint8_t x, atom_value y, message z)``| Construct error with code ``x``, category ``y``, and context ``z`` |
~ & ~ \\ \textbf{Observers} & ~ \\ +-----------------------------------------+--------------------------------------------------------------------+
\hline | | |
\lstinline^uint8_t code()^ & Returns the error code \\ +-----------------------------------------+--------------------------------------------------------------------+
\hline | **Observers** | |
\lstinline^atom_value category()^ & Returns the error category \\ +-----------------------------------------+--------------------------------------------------------------------+
\hline | ``uint8_t code()`` | Returns the error code |
\lstinline^message context()^ & Returns additional context information \\ +-----------------------------------------+--------------------------------------------------------------------+
\hline | ``atom_value category()`` | Returns the error category |
\lstinline^explicit operator bool()^ & Returns \lstinline^code() != 0^ \\ +-----------------------------------------+--------------------------------------------------------------------+
\hline | ``message context()`` | Returns additional context information |
\end{tabular} +-----------------------------------------+--------------------------------------------------------------------+
\end{center} | ``explicit operator bool()`` | Returns ``code() != 0`` |
+-----------------------------------------+--------------------------------------------------------------------+
\subsection{Add Custom Error Categories}
\label{custom-error} .. _custom-error:
Adding custom error categories requires three steps: (1)~declare an enum class Add Custom Error Categories
of type \lstinline^uint8_t^ with the first value starting at 1, (2)~implement a ---------------------------
free function \lstinline^make_error^ that converts the enum to an
\lstinline^error^ object, (3)~add the custom category to the actor system with Adding custom error categories requires three steps: (1) declare an enum class
a render function. The last step is optional to allow users to retrieve a of type ``uint8_t`` with the first value starting at 1, (2) specialize
better string representation from \lstinline^system.render(x)^ than ``error_category`` to give your type a custom ID (value 0-99 are
\lstinline^to_string(x)^ can offer. Note that any error code with value 0 is reserved by CAF), and (3) add your error category to the actor system config.
interpreted as \emph{not-an-error}. The following example adds a custom error The following example adds custom error codes for math errors.
category by performing the first two steps.
.. literalinclude:: /examples/message_passing/divider.cpp
\cppexample[19-34]{message_passing/divider} :language: C++
:lines: 17-47
The implementation of \lstinline^to_string(error)^ is unable to call string
conversions for custom error categories. Hence, .. _sec:
\lstinline^to_string(make_error(math_error::division_by_zero))^ returns
\lstinline^"error(1, math)"^. System Error Codes
------------------
The following code adds a rendering function to the actor system to provide a
more satisfactory string conversion. System Error Codes (SECs) use the error category ``"system"``. They
\cppexample[50-58]{message_passing/divider}
With the custom rendering function,
\lstinline^system.render(make_error(math_error::division_by_zero))^ returns
\lstinline^"math_error(division_by_zero)"^.
\clearpage
\subsection{System Error Codes}
\label{sec}
System Error Codes (SECs) use the error category \lstinline^"system"^. They
represent errors in the actor system or one of its modules and are defined as represent errors in the actor system or one of its modules and are defined as
follows. follows.
\sourcefile[32-117]{libcaf_core/caf/sec.hpp} .. literalinclude:: /libcaf_core/caf/sec.hpp
:language: C++
:lines: 32-117
%\clearpage .. _exit-reason:
\subsection{Default Exit Reasons}
\label{exit-reason}
CAF uses the error category \lstinline^"exit"^ for default exit reasons. These Default Exit Reasons
errors are usually fail states set by the actor system itself. The two --------------------
exceptions are \lstinline^exit_reason::user_shutdown^ and
\lstinline^exit_reason::kill^. The former is used in CAF to signalize orderly, CAF uses the error category ``"exit"`` for default exit reasons. These errors
user-requested shutdown and can be used by programmers in the same way. The are usually fail states set by the actor system itself. The two exceptions are
latter terminates an actor unconditionally when used in \lstinline^send_exit^, ``exit_reason::user_shutdown`` and ``exit_reason::kill``. The former is used in
even if the default handler for exit messages~\see{exit-message} is overridden. CAF to signalize orderly, user-requested shutdown and can be used by programmers
in the same way. The latter terminates an actor unconditionally when used in
``send_exit``, even if the default handler for exit messages (see
:ref:`exit-message`) is overridden.
.. literalinclude:: /libcaf_core/caf/exit_reason.hpp
:language: C++
:lines: 29-49
\sourcefile[29-49]{libcaf_core/caf/exit_reason.hpp}
\section{Frequently Asked Questions} .. _faq:
\label{faq}
Frequently Asked Questions
==========================
This Section is a compilation of the most common questions via GitHub, chat, This Section is a compilation of the most common questions via GitHub, chat,
and mailing list. and mailing list.
\subsection{Can I Encrypt CAF Communication?} Can I Encrypt CAF Communication?
--------------------------------
Yes, by using the OpenSSL module~\see{free-remoting-functions}. Yes, by using the OpenSSL module (see :ref:`free-remoting-functions`).
\subsection{Can I Create Messages Dynamically?} Can I Create Messages Dynamically?
----------------------------------
Yes. Yes.
Usually, messages are created implicitly when sending messages but can also be Usually, messages are created implicitly when sending messages but can also be
created explicitly using \lstinline^make_message^. In both cases, types and created explicitly using ``make_message``. In both cases, types and number of
number of elements are known at compile time. To allow for fully dynamic elements are known at compile time. To allow for fully dynamic message
message generation, CAF also offers \lstinline^message_builder^: generation, CAF also offers ``message_builder``:
\begin{lstlisting} .. code-block:: C++
message_builder mb;
// prefix message with some atom message_builder mb;
mb.append(strings_atom::value); // prefix message with some atom
// fill message with some strings mb.append(strings_atom::value);
std::vector<std::string> strings{/*...*/}; // fill message with some strings
for (auto& str : strings) std::vector<std::string> strings{/*...*/};
mb.append(str); for (auto& str : strings)
// create the message mb.append(str);
message msg = mb.to_message(); // create the message
\end{lstlisting} message msg = mb.to_message();
\subsection{What Debugging Tools Exist?} What Debugging Tools Exist?
---------------------------
The \lstinline^scripts/^ and \lstinline^tools/^ directories contain some useful
tools to aid in development and debugging. The ``scripts/`` and ``tools/`` directories contain some useful tools to aid in
development and debugging.
\lstinline^scripts/atom.py^ converts integer atom values back into strings.
``scripts/atom.py`` converts integer atom values back into strings.
\lstinline^scripts/demystify.py^ replaces cryptic \lstinline^typed_mpi<...>^
templates with \lstinline^replies_to<...>::with<...>^ and ``scripts/demystify.py`` replaces cryptic ``typed_mpi<...>``
\lstinline^atom_constant<...>^ with a human-readable representation of the templates with ``replies_to<...>::with<...>`` and
``atom_constant<...>`` with a human-readable representation of the
actual atom. actual atom.
\lstinline^scripts/caf-prof^ is an R script that generates plots from CAF ``scripts/caf-prof`` is an R script that generates plots from CAF
profiler output. profiler output.
\lstinline^caf-vec^ is a (highly) experimental tool that annotates CAF logs ``caf-vec`` is a (highly) experimental tool that annotates CAF logs
with vector timestamps. It gives you happens-before relations and a nice with vector timestamps. It gives you happens-before relations and a nice
visualization via \href{https://bestchai.bitbucket.io/shiviz/}{ShiViz}. visualization via `ShiViz <https://bestchai.bitbucket.io/shiviz/>`_.
\section{Group Communication} .. _groups:
\label{groups}
Group Communication
===================
CAF supports publish/subscribe-based group communication. Dynamically typed CAF supports publish/subscribe-based group communication. Dynamically typed
actors can join and leave groups and send messages to groups. The following actors can join and leave groups and send messages to groups. The following
example showcases the basic API for retrieving a group from a module by its example showcases the basic API for retrieving a group from a module by its
name, joining, and leaving. name, joining, and leaving.
\begin{lstlisting} .. code-block:: C++
std::string module = "local";
std::string id = "foo"; std::string module = "local";
auto expected_grp = system.groups().get(module, id); std::string id = "foo";
if (! expected_grp) { auto expected_grp = system.groups().get(module, id);
std::cerr << "*** cannot load group: " if (! expected_grp) {
<< system.render(expected_grp.error()) << std::endl; std::cerr << "*** cannot load group: "
return; << system.render(expected_grp.error()) << std::endl;
} return;
auto grp = std::move(*expected_grp); }
scoped_actor self{system}; auto grp = std::move(*expected_grp);
self->join(grp); scoped_actor self{system};
self->send(grp, "test"); self->join(grp);
self->receive( self->send(grp, "test");
[](const std::string& str) { self->receive(
assert(str == "test"); [](const std::string& str) {
} assert(str == "test");
); }
self->leave(grp); );
\end{lstlisting} self->leave(grp);
It is worth mentioning that the module \lstinline`"local"` is guaranteed to It is worth mentioning that the module ``"local"`` is guaranteed to
never return an error. The example above uses the general API for retrieving never return an error. The example above uses the general API for retrieving
the group. However, local modules can be easier accessed by calling the group. However, local modules can be easier accessed by calling
\lstinline`system.groups().get_local(id)`, which returns \lstinline`group` ``system.groups().get_local(id)``, which returns ``group``
instead of \lstinline`expected<group>`. instead of ``expected<group>``.
.. _anonymous-group:
\subsection{Anonymous Groups} Anonymous Groups
\label{anonymous-group} ----------------
Groups created on-the-fly with \lstinline^system.groups().anonymous()^ can be Groups created on-the-fly with ``system.groups().anonymous()`` can be
used to coordinate a set of workers. Each call to this function returns a new, used to coordinate a set of workers. Each call to this function returns a new,
unique group instance. unique group instance.
\subsection{Local Groups} .. _local-group:
\label{local-group}
The \lstinline^"local"^ group module creates groups for in-process Local Groups
------------
The ``"local"`` group module creates groups for in-process
communication. For example, a group for GUI related events could be identified communication. For example, a group for GUI related events could be identified
by \lstinline^system.groups().get_local("GUI events")^. The group ID by ``system.groups().get_local("GUI events")``. The group ID
\lstinline^"GUI events"^ uniquely identifies a singleton group instance of the ``"GUI events"`` uniquely identifies a singleton group instance of the
module \lstinline^"local"^. module ``"local"``.
.. _remote-group:
\subsection{Remote Groups} Remote Groups
\label{remote-group} -------------
Calling\lstinline^system.middleman().publish_local_groups(port, addr)^ makes Calling``system.middleman().publish_local_groups(port, addr)`` makes
all local groups available to other nodes in the network. The first argument all local groups available to other nodes in the network. The first argument
denotes the port, while the second (optional) parameter can be used to denotes the port, while the second (optional) parameter can be used to
whitelist IP addresses. whitelist IP addresses.
After publishing the group at one node (the server), other nodes (the clients) After publishing the group at one node (the server), other nodes (the clients)
can get a handle for that group by using the ``remote'' module: can get a handle for that group by using the ``remote'' module:
\lstinline^system.groups().get("remote", "<group>@<host>:<port>")^. This ``system.groups().get("remote", "<group>@<host>:<port>")``. This
implementation uses N-times unicast underneath and the group is only available implementation uses N-times unicast underneath and the group is only available
as long as the hosting server is alive. as long as the hosting server is alive.
\section{Introduction} Introduction
============
Before diving into the API of CAF, we discuss the concepts behind it and Before diving into the API of CAF, we discuss the concepts behind it and
explain the terminology used in this manual. explain the terminology used in this manual.
\subsection{Actor Model} Actor Model
-----------
The actor model describes concurrent entities---actors---that do not share The actor model describes concurrent entities---actors---that do not share
state and communicate only via asynchronous message passing. Decoupling state and communicate only via asynchronous message passing. Decoupling
...@@ -27,10 +29,11 @@ and from one node to many nodes. However, the actor model has not yet been ...@@ -27,10 +29,11 @@ and from one node to many nodes. However, the actor model has not yet been
widely adopted in the native programming domain. With CAF, we contribute a widely adopted in the native programming domain. With CAF, we contribute a
library for actor programming in C++ as open-source software to ease native library for actor programming in C++ as open-source software to ease native
development of concurrent as well as distributed systems. In this regard, CAF development of concurrent as well as distributed systems. In this regard, CAF
follows the C++ philosophy ``building the highest abstraction possible without follows the C++ philosophy *building the highest abstraction possible
sacrificing performance''. without sacrificing performance*.
\subsection{Terminology} Terminology
-----------
CAF is inspired by other implementations based on the actor model such as CAF is inspired by other implementations based on the actor model such as
Erlang or Akka. It aims to provide a modern C++ API allowing for type-safe as Erlang or Akka. It aims to provide a modern C++ API allowing for type-safe as
...@@ -38,7 +41,8 @@ well as dynamically typed messaging. While there are similarities to other ...@@ -38,7 +41,8 @@ well as dynamically typed messaging. While there are similarities to other
implementations, we made many different design decisions that lead to slight implementations, we made many different design decisions that lead to slight
differences when comparing CAF to other actor frameworks. differences when comparing CAF to other actor frameworks.
\subsubsection{Dynamically Typed Actor} Dynamically Typed Actor
~~~~~~~~~~~~~~~~~~~~~~~
A dynamically typed actor accepts any kind of message and dispatches on its A dynamically typed actor accepts any kind of message and dispatches on its
content dynamically at the receiver. This is the ``traditional'' messaging content dynamically at the receiver. This is the ``traditional'' messaging
...@@ -46,7 +50,8 @@ style found in implementations like Erlang or Akka. The upside of this approach ...@@ -46,7 +50,8 @@ style found in implementations like Erlang or Akka. The upside of this approach
is (usually) faster prototyping and less code. This comes at the cost of is (usually) faster prototyping and less code. This comes at the cost of
requiring excessive testing. requiring excessive testing.
\subsubsection{Statically Typed Actor} Statically Typed Actor
~~~~~~~~~~~~~~~~~~~~~~
CAF achieves static type-checking for actors by defining abstract messaging CAF achieves static type-checking for actors by defining abstract messaging
interfaces. Since interfaces define both input and output types, CAF is able to interfaces. Since interfaces define both input and output types, CAF is able to
...@@ -55,75 +60,87 @@ higher robustness to code changes and fewer possible runtime errors. This comes ...@@ -55,75 +60,87 @@ higher robustness to code changes and fewer possible runtime errors. This comes
at an increase in required source code, as developers have to define and use at an increase in required source code, as developers have to define and use
messaging interfaces. messaging interfaces.
\subsubsection{Actor References} .. _actor-reference:
\label{actor-reference}
Actor References
~~~~~~~~~~~~~~~~
CAF uses reference counting for actors. The three ways to store a reference to CAF uses reference counting for actors. The three ways to store a reference to
an actor are addresses, handles, and pointers. Note that \emph{address} does an actor are addresses, handles, and pointers. Note that *address* does
not refer to a \emph{memory region} in this context. not refer to a *memory region* in this context.
.. _actor-address:
\paragraph{Address} Address
\label{actor-address} +++++++
Each actor has a (network-wide) unique logical address. This identifier is Each actor has a (network-wide) unique logical address. This identifier is
represented by \lstinline^actor_addr^, which allows to identify and monitor an represented by ``actor_addr``, which allows to identify and monitor an actor.
actor. Unlike other actor frameworks, CAF does \emph{not} allow users to send Unlike other actor frameworks, CAF does *not* allow users to send messages to
messages to addresses. This limitation is due to the fact that the address does addresses. This limitation is due to the fact that the address does not contain
not contain any type information. Hence, it would not be safe to send it a any type information. Hence, it would not be safe to send it a message, because
message, because the receiving actor might use a statically typed interface the receiving actor might use a statically typed interface that does not accept
that does not accept the given message. Because an \lstinline^actor_addr^ fills the given message. Because an ``actor_addr`` fills the role of an identifier, it
the role of an identifier, it has \emph{weak reference semantics} has *weak reference semantics* (see :ref:`reference-counting`).
\see{reference-counting}.
.. _actor-handle:
\paragraph{Handle}
\label{actor-handle} Handle
++++++
An actor handle contains the address of an actor along with its type
information and is required for sending messages to actors. The distinction An actor handle contains the address of an actor along with its type information
between handles and addresses---which is unique to CAF when comparing it to and is required for sending messages to actors. The distinction between handles
other actor systems---is a consequence of the design decision to enforce static and addresses---which is unique to CAF when comparing it to other actor
type checking for all messages. Dynamically typed actors use \lstinline^actor^ systems---is a consequence of the design decision to enforce static type
handles, while statically typed actors use \lstinline^typed_actor<...>^ checking for all messages. Dynamically typed actors use ``actor`` handles, while
handles. Both types have \emph{strong reference semantics} statically typed actors use ``typed_actor<...>`` handles. Both types have
\see{reference-counting}. *strong reference semantics* (see :ref:`reference-counting`).
\paragraph{Pointer} .. _actor-pointer:
\label{actor-pointer}
Pointer
In a few instances, CAF uses \lstinline^strong_actor_ptr^ to refer to an actor +++++++
using \emph{strong reference semantics} \see{reference-counting} without
knowing the proper handle type. Pointers must be converted to a handle via In a few instances, CAF uses ``strong_actor_ptr`` to refer to an actor using
\lstinline^actor_cast^ \see{actor-cast} prior to sending messages. A *strong reference semantics* (see :ref:`reference-counting`) without knowing the
\lstinline^strong_actor_ptr^ can be \emph{null}. proper handle type. Pointers must be converted to a handle via ``actor_cast``
(see :ref:`actor-cast`) prior to sending messages. A ``strong_actor_ptr`` can be
\subsubsection{Spawning} *null*.
\emph{Spawning} an actor means to create and run a new actor. Spawning
~~~~~~~~
\subsubsection{Monitor}
\label{monitor} *Spawning* an actor means to create and run a new actor.
A monitored actor sends a down message~\see{down-message} to all actors .. _monitor:
Monitor
~~~~~~~
A monitored actor sends a down message (see :ref:`down-message`) to all actors
monitoring it as part of its termination. This allows actors to supervise other monitoring it as part of its termination. This allows actors to supervise other
actors and to take actions when one of the supervised actors fails, i.e., actors and to take actions when one of the supervised actors fails, i.e.,
terminates with a non-normal exit reason. terminates with a non-normal exit reason.
\subsubsection{Link} .. _link:
\label{link}
Link
~~~~
A link is a bidirectional connection between two actors. Each actor sends an A link is a bidirectional connection between two actors. Each actor sends an
exit message~\see{exit-message} to all of its links as part of its termination. exit message (see :ref:`exit-message`) to all of its links as part of its
Unlike down messages, exit messages cause the receiving actor to terminate as termination. Unlike down messages, exit messages cause the receiving actor to
well when receiving a non-normal exit reason per default. This allows terminate as well when receiving a non-normal exit reason per default. This
developers to create a set of actors with the guarantee that either all or no allows developers to create a set of actors with the guarantee that either all
actors are alive. Actors can override the default handler to implement error or no actors are alive. Actors can override the default handler to implement
recovery strategies. error recovery strategies.
\subsection{Experimental Features} Experimental Features
---------------------
Sections that discuss experimental features are highlighted with \experimental.
The API of such features is not stable. This means even minor updates to CAF Sections that discuss experimental features are highlighted with
can come with breaking changes to the API or even remove a feature completely. :sup:`experimental`. The API of such features is not stable. This means even
However, we encourage developers to extensively test such features and to start minor updates to CAF can come with breaking changes to the API or even remove a
discussions to uncover flaws, report bugs, or tweaking the API in order to feature completely. However, we encourage developers to extensively test such
improve a feature or streamline it to cover certain use cases. features and to start discussions to uncover flaws, report bugs, or tweaking the
API in order to improve a feature or streamline it to cover certain use cases.
\section{Managing Groups of Workers \experimental} .. _worker-groups:
\label{worker-groups}
Managing Groups of Workers :sup:`experimental`
===============================================
When managing a set of workers, a central actor often dispatches requests to a When managing a set of workers, a central actor often dispatches requests to a
set of workers. For this purpose, the class \lstinline^actor_pool^ implements a set of workers. For this purpose, the class ``actor_pool`` implements a
lightweight abstraction for managing a set of workers using a dispatching lightweight abstraction for managing a set of workers using a dispatching
policy. Unlike groups, pools usually own their workers. policy. Unlike groups, pools usually own their workers.
Pools are created using the static member function \lstinline^make^, which Pools are created using the static member function ``make``, which
takes either one argument (the policy) or three (number of workers, factory takes either one argument (the policy) or three (number of workers, factory
function for workers, and dispatching policy). After construction, one can add function for workers, and dispatching policy). After construction, one can add
new workers via messages of the form \texttt{('SYS', 'PUT', worker)}, remove new workers via messages of the form ``('SYS', 'PUT', worker)``, remove
workers with \texttt{('SYS', 'DELETE', worker)}, and retrieve the set of workers with ``('SYS', 'DELETE', worker)``, and retrieve the set of
workers as \lstinline^vector<actor>^ via \texttt{('SYS', 'GET')}. workers as ``vector<actor>`` via ``('SYS', 'GET')``.
An actor pool takes ownership of its workers. When forced to quit, it sends an An actor pool takes ownership of its workers. When forced to quit, it sends an
exit messages to all of its workers, forcing them to quit as well. The pool exit messages to all of its workers, forcing them to quit as well. The pool
...@@ -22,61 +24,62 @@ Consequently, a terminating worker loses all unprocessed messages. For more ...@@ -22,61 +24,62 @@ Consequently, a terminating worker loses all unprocessed messages. For more
advanced caching strategies, such as reliable message delivery, users can advanced caching strategies, such as reliable message delivery, users can
implement their own dispatching policies. implement their own dispatching policies.
\subsection{Dispatching Policies} Dispatching Policies
--------------------
A dispatching policy is a functor with the following signature: A dispatching policy is a functor with the following signature:
\begin{lstlisting} .. code-block:: C++
using uplock = upgrade_lock<detail::shared_spinlock>;
using policy = std::function<void (actor_system& sys, using uplock = upgrade_lock<detail::shared_spinlock>;
uplock& guard, using policy = std::function<void (actor_system& sys,
const actor_vec& workers, uplock& guard,
mailbox_element_ptr& ptr, const actor_vec& workers,
execution_unit* host)>; mailbox_element_ptr& ptr,
\end{lstlisting} execution_unit* host)>;
The argument \lstinline^guard^ is a shared lock that can be upgraded for unique The argument ``guard`` is a shared lock that can be upgraded for unique
access if the policy includes a critical section. The second argument is a access if the policy includes a critical section. The second argument is a
vector containing all workers managed by the pool. The argument \lstinline^ptr^ vector containing all workers managed by the pool. The argument ``ptr``
contains the full message as received by the pool. Finally, \lstinline^host^ is contains the full message as received by the pool. Finally, ``host`` is
the current scheduler context that can be used to enqueue workers into the the current scheduler context that can be used to enqueue workers into the
corresponding job queue. corresponding job queue.
The actor pool class comes with a set predefined policies, accessible via The actor pool class comes with a set predefined policies, accessible via
factory functions, for convenience. factory functions, for convenience.
\begin{lstlisting} .. code-block:: C++
actor_pool::policy actor_pool::round_robin();
\end{lstlisting} actor_pool::policy actor_pool::round_robin();
This policy forwards incoming requests in a round-robin manner to workers. This policy forwards incoming requests in a round-robin manner to workers.
There is no guarantee that messages are consumed, i.e., work items are lost if There is no guarantee that messages are consumed, i.e., work items are lost if
the worker exits before processing all of its messages. the worker exits before processing all of its messages.
\begin{lstlisting} .. code-block:: C++
actor_pool::policy actor_pool::broadcast();
\end{lstlisting}
This policy forwards \emph{each} message to \emph{all} workers. Synchronous actor_pool::policy actor_pool::broadcast();
This policy forwards *each* message to *all* workers. Synchronous
messages to the pool will be received by all workers, but the client will only messages to the pool will be received by all workers, but the client will only
recognize the first arriving response message---or error---and discard recognize the first arriving response message---or error---and discard
subsequent messages. Note that this is not caused by the policy itself, but a subsequent messages. Note that this is not caused by the policy itself, but a
consequence of forwarding synchronous messages to more than one actor. consequence of forwarding synchronous messages to more than one actor.
\begin{lstlisting} .. code-block:: C++
actor_pool::policy actor_pool::random();
\end{lstlisting} actor_pool::policy actor_pool::random();
This policy forwards incoming requests to one worker from the pool chosen This policy forwards incoming requests to one worker from the pool chosen
uniformly at random. Analogous to \lstinline^round_robin^, this policy does not uniformly at random. Analogous to ``round_robin``, this policy does not
cache or redispatch messages. cache or redispatch messages.
\begin{lstlisting} .. code-block:: C++
using join = function<void (T&, message&)>;
using split = function<void (vector<pair<actor, message>>&, message&)>; using join = function<void (T&, message&)>;
template <class T> using split = function<void (vector<pair<actor, message>>&, message&)>;
static policy split_join(join jf, split sf = ..., T init = T()); template <class T>
\end{lstlisting} static policy split_join(join jf, split sf = ..., T init = T());
This policy models split/join or scatter/gather work flows, where a work item This policy models split/join or scatter/gather work flows, where a work item
is split into as many tasks as workers are available and then the individuals is split into as many tasks as workers are available and then the individuals
...@@ -84,7 +87,7 @@ results are joined together before sending the full result back to the client. ...@@ -84,7 +87,7 @@ results are joined together before sending the full result back to the client.
The join function is responsible for ``glueing'' all result messages together The join function is responsible for ``glueing'' all result messages together
to create a single result. The function is called with the result object to create a single result. The function is called with the result object
(initialed using \lstinline^init^) and the current result messages from a (initialed using ``init``) and the current result messages from a
worker. worker.
The first argument of a split function is a mapping from actors (workers) to The first argument of a split function is a mapping from actors (workers) to
......
\section{Message Handlers} .. _message-handler:
\label{message-handler}
Message Handlers
================
Actors can store a set of callbacks---usually implemented as lambda Actors can store a set of callbacks---usually implemented as lambda
expressions---using either \lstinline^behavior^ or \lstinline^message_handler^. expressions---using either ``behavior`` or ``message_handler``.
The former stores an optional timeout, while the latter is composable. The former stores an optional timeout, while the latter is composable.
\subsection{Definition and Composition} Definition and Composition
--------------------------
As the name implies, a \lstinline^behavior^ defines the response of an actor to As the name implies, a ``behavior`` defines the response of an actor to
messages it receives. The optional timeout allows an actor to dynamically messages it receives. The optional timeout allows an actor to dynamically
change its behavior when not receiving message after a certain amount of time. change its behavior when not receiving message after a certain amount of time.
\begin{lstlisting} .. code-block:: C++
message_handler x1{
[](int i) { /*...*/ }, message_handler x1{
[](double db) { /*...*/ }, [](int i) { /*...*/ },
[](int a, int b, int c) { /*...*/ } [](double db) { /*...*/ },
}; [](int a, int b, int c) { /*...*/ }
\end{lstlisting} };
In our first example, \lstinline^x1^ models a behavior accepting messages that In our first example, ``x1`` models a behavior accepting messages that consist
consist of either exactly one \lstinline^int^, or one \lstinline^double^, or of either exactly one ``int``, or one ``double``, or three ``int`` values. Any
three \lstinline^int^ values. Any other message is not matched and gets other message is not matched and gets forwarded to the default handler (see
forwarded to the default handler \see{default-handler}. :ref:`default-handler`).
\begin{lstlisting} .. code-block:: C++
message_handler x2{
[](double db) { /*...*/ }, message_handler x2{
[](double db) { /* - unreachable - */ } [](double db) { /*...*/ },
}; [](double db) { /* - unreachable - */ }
\end{lstlisting} };
Our second example illustrates an important characteristic of the matching Our second example illustrates an important characteristic of the matching
mechanism. Each message is matched against the callbacks in the order they are mechanism. Each message is matched against the callbacks in the order they are
defined. The algorithm stops at the first match. Hence, the second callback in defined. The algorithm stops at the first match. Hence, the second callback in
\lstinline^x2^ is unreachable. ``x2`` is unreachable.
.. code-block:: C++
\begin{lstlisting} message_handler x3 = x1.or_else(x2);
message_handler x3 = x1.or_else(x2); message_handler x4 = x2.or_else(x1);
message_handler x4 = x2.or_else(x1);
\end{lstlisting}
Message handlers can be combined using \lstinline^or_else^. This composition is Message handlers can be combined using ``or_else``. This composition is
not commutative, as our third examples illustrates. The resulting message not commutative, as our third examples illustrates. The resulting message
handler will first try to handle a message using the left-hand operand and will handler will first try to handle a message using the left-hand operand and will
fall back to the right-hand operand if the former did not match. Thus, fall back to the right-hand operand if the former did not match. Thus,
\lstinline^x3^ behaves exactly like \lstinline^x1^. This is because the second ``x3`` behaves exactly like ``x1``. This is because the second
callback in \lstinline^x1^ will consume any message with a single callback in ``x1`` will consume any message with a single
\lstinline^double^ and both callbacks in \lstinline^x2^ are thus unreachable. ``double`` and both callbacks in ``x2`` are thus unreachable.
The handler \lstinline^x4^ will consume messages with a single The handler ``x4`` will consume messages with a single
\lstinline^double^ using the first callback in \lstinline^x2^, essentially ``double`` using the first callback in ``x2``, essentially
overriding the second callback in \lstinline^x1^. overriding the second callback in ``x1``.
\clearpage .. _atom:
\subsection{Atoms}
\label{atom} Atoms
-----
Defining message handlers in terms of callbacks is convenient, but requires a Defining message handlers in terms of callbacks is convenient, but requires a
simple way to annotate messages with meta data. Imagine an actor that provides simple way to annotate messages with meta data. Imagine an actor that provides
...@@ -63,51 +67,51 @@ user-defined operation and returns the result. Without additional context, the ...@@ -63,51 +67,51 @@ user-defined operation and returns the result. Without additional context, the
actor cannot decide whether it should multiply or add the integers. Thus, the actor cannot decide whether it should multiply or add the integers. Thus, the
operation must be encoded into the message. The Erlang programming language operation must be encoded into the message. The Erlang programming language
introduced an approach to use non-numerical constants, so-called introduced an approach to use non-numerical constants, so-called
\textit{atoms}, which have an unambiguous, special-purpose type and do not have *atoms*, which have an unambiguous, special-purpose type and do not have
the runtime overhead of string constants. the runtime overhead of string constants.
Atoms in CAF are mapped to integer values at compile time. This mapping is Atoms in CAF are mapped to integer values at compile time. This mapping is
guaranteed to be collision-free and invertible, but limits atom literals to ten guaranteed to be collision-free and invertible, but limits atom literals to ten
characters and prohibits special characters. Legal characters are characters and prohibits special characters. Legal characters are
\lstinline^_0-9A-Za-z^ and the whitespace character. Atoms are created using ``_0-9A-Za-z`` and the whitespace character. Atoms are created using
the \lstinline^constexpr^ function \lstinline^atom^, as the following example the ``constexpr`` function ``atom``, as the following example
illustrates. illustrates.
\begin{lstlisting} .. code-block:: C++
atom_value a1 = atom("add");
atom_value a2 = atom("multiply"); atom_value a1 = atom("add");
\end{lstlisting} atom_value a2 = atom("multiply");
\textbf{Warning}: The compiler cannot enforce the restrictions at compile time, **Warning**: The compiler cannot enforce the restrictions at compile time,
except for a length check. The assertion \lstinline^atom("!?") != atom("?!")^ except for a length check. The assertion ``atom("!?") != atom("?!")``
is not true, because each invalid character translates to a whitespace is not true, because each invalid character translates to a whitespace
character. character.
While the \lstinline^atom_value^ is computed at compile time, it is not While the ``atom_value`` is computed at compile time, it is not
uniquely typed and thus cannot be used in the signature of a callback. To uniquely typed and thus cannot be used in the signature of a callback. To
accomplish this, CAF offers compile-time \emph{atom constants}. accomplish this, CAF offers compile-time *atom constants*.
.. code-block:: C++
\begin{lstlisting} using add_atom = atom_constant<atom("add")>;
using add_atom = atom_constant<atom("add")>; using multiply_atom = atom_constant<atom("multiply")>;
using multiply_atom = atom_constant<atom("multiply")>;
\end{lstlisting}
Using these constants, we can now define message passing interfaces in a Using these constants, we can now define message passing interfaces in a
convenient way: convenient way:
\begin{lstlisting} .. code-block:: C++
behavior do_math{
[](add_atom, int a, int b) { behavior do_math{
return a + b; [](add_atom, int a, int b) {
}, return a + b;
[](multiply_atom, int a, int b) { },
return a * b; [](multiply_atom, int a, int b) {
} return a * b;
}; }
};
// caller side: send(math_actor, add_atom::value, 1, 2)
\end{lstlisting} // caller side: send(math_actor, add_atom::value, 1, 2)
Atom constants define a static member \lstinline^value^. Please note that this Atom constants define a static member ``value``. Please note that this
static \lstinline^value^ member does \emph{not} have the type static ``value`` member does *not* have the type
\lstinline^atom_value^, unlike \lstinline^std::integral_constant^ for example. ``atom_value``, unlike ``std::integral_constant`` for example.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
\section{Overview} Overview
========
Compiling CAF requires CMake and a C++11-compatible compiler. To get and Compiling CAF requires CMake and a C++11-compatible compiler. To get and
compile the sources on UNIX-like systems, type the following in a terminal: compile the sources on UNIX-like systems, type the following in a terminal:
\begin{verbatim} .. ::
git clone https://github.com/actor-framework/actor-framework
cd actor-framework git clone https://github.com/actor-framework/actor-framework
./configure cd actor-framework
make ./configure
make install [as root, optional] make
\end{verbatim} make install [as root, optional]
We recommended to run the unit tests as well: We recommended to run the unit tests as well:
\begin{verbatim} .. ::
make test
\end{verbatim} make test
If the output indicates an error, please submit a bug report that includes (a) If the output indicates an error, please submit a bug report that includes (a)
your compiler version, (b) your OS, and (c) the content of the file your compiler version, (b) your OS, and (c) the content of the file
\texttt{build/Testing/Temporary/LastTest.log}. ``build/Testing/Temporary/LastTest.log``.
\subsection{Features} Features
--------
\begin{itemize} * Lightweight, fast and efficient actor implementations
\item Lightweight, fast and efficient actor implementations * Network transparent messaging
\item Network transparent messaging * Error handling based on Erlang's failure model
\item Error handling based on Erlang's failure model * Pattern matching for messages as internal DSL to ease development
\item Pattern matching for messages as internal DSL to ease development * Thread-mapped actors for soft migration of existing applications
\item Thread-mapped actors for soft migration of existing applications * Publish/subscribe group communication
\item Publish/subscribe group communication
\end{itemize}
Minimal Compiler Versions
-------------------------
\subsection{Minimal Compiler Versions} * GCC 4.8
* Clang 3.4
* Visual Studio 2015, Update 3
\begin{itemize} Supported Operating Systems
\item GCC 4.8 ---------------------------
\item Clang 3.4
\item Visual Studio 2015, Update 3
\end{itemize}
\subsection{Supported Operating Systems} * Linux
* Mac OS X
* Windows (static library only)
\begin{itemize} Hello World Example
\item Linux -------------------
\item Mac OS X
\item Windows (static library only)
\end{itemize}
\clearpage .. literalinclude:: /examples/hello_world.cpp
\subsection{Hello World Example} :language: C++
\cppexample{hello_world}
This diff is collapsed.
This diff is collapsed.
\section{Remote Spawning of Actors \experimental} .. _remote-spawn:
\label{remote-spawn}
Remote Spawning of Actors :sup:`experimental`
==============================================
Remote spawning is an extension of the dynamic spawn using run-time type names Remote spawning is an extension of the dynamic spawn using run-time type names
\see{add-custom-actor-type}. The following example assumes a typed actor handle (see :ref:`add-custom-actor-type`). The following example assumes a typed actor
named \lstinline^calculator^ with an actor implementing this messaging handle named ``calculator`` with an actor implementing this messaging interface
interface named "calculator". named "calculator".
\cppexample[125-143]{remoting/remote_spawn} .. literalinclude:: /examples/remoting/remote_spawn.cpp
:language: C++
:lines: 123-137
We first connect to a CAF node with \lstinline^middleman().connect(...)^. On We first connect to a CAF node with ``middleman().connect(...)``. On success,
success, \lstinline^connect^ returns the node ID we need for ``connect`` returns the node ID we need for ``remote_spawn``. This requires the
\lstinline^remote_spawn^. This requires the server to open a port with server to open a port with ``middleman().open(...)`` or
\lstinline^middleman().open(...)^ or \lstinline^middleman().publish(...)^. ``middleman().publish(...)``. Alternatively, we can obtain the node ID from an
Alternatively, we can obtain the node ID from an already existing remote actor already existing remote actor handle---returned from ``remote_actor`` for
handle---returned from \lstinline^remote_actor^ for example---via example---via ``hdl->node()``. After connecting to the server, we can use
\lstinline^hdl->node()^. After connecting to the server, we can use ``middleman().remote_spawn<...>(...)`` to create actors remotely.
\lstinline^middleman().remote_spawn<...>(...)^ to create actors remotely.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
\section{Using \texttt{aout} -- A Concurrency-safe Wrapper for \texttt{cout}} Using ``aout`` -- A Concurrency-safe Wrapper for ``cout``
=========================================================
When using \lstinline^cout^ from multiple actors, output often appears When using ``cout`` from multiple actors, output often appears
interleaved. Moreover, using \lstinline^cout^ from multiple actors -- and thus interleaved. Moreover, using ``cout`` from multiple actors -- and thus
from multiple threads -- in parallel should be avoided regardless, since the from multiple threads -- in parallel should be avoided regardless, since the
standard does not guarantee a thread-safe implementation. standard does not guarantee a thread-safe implementation.
By replacing \texttt{std::cout} with \texttt{caf::aout}, actors can achieve a By replacing ``std::cout`` with ``caf::aout``, actors can achieve a
concurrency-safe text output. The header \lstinline^caf/all.hpp^ also defines concurrency-safe text output. The header ``caf/all.hpp`` also defines overloads
overloads for \texttt{std::endl} and \texttt{std::flush} for \lstinline^aout^, for ``std::endl`` and ``std::flush`` for ``aout``, but does not support the full
but does not support the full range of ostream operations (yet). Each write range of ostream operations (yet). Each write operation to ``aout`` sends a
operation to \texttt{aout} sends a message to a `hidden' actor. This actor only message to a "hidden" actor. This actor only prints lines, unless output is
prints lines, unless output is forced using \lstinline^flush^. The example forced using ``flush``. The example below illustrates printing of lines of text
below illustrates printing of lines of text from multiple actors (in random from multiple actors (in random order).
order).
.. literalinclude:: /examples/aout.cpp
:language: C++
\cppexample{aout}
This diff is collapsed.
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