\libcppa provides several actor implementations, each covering a particular use case.
\lib 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.
The default actor implementation in \lib 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.
...
...
@@ -53,9 +53,9 @@ class local_actor;
\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}) \\
\lstinline^void monitor(actor 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^\\
\lstinline^void demonitor(actor whom)^& Removes a monitor from \lstinline^whom^\\
\hline
\lstinline^bool has_sync_failure_handler()^& Checks wheter this actor has a user-defined sync failure handler \\
The guides in this section document all possibly breaking changes in the library for that last versions of \lib.
\subsubsection{0.8 $\Rightarrow$ 0.9}
\paragraph{\lstinline^self^ has been removed}
~
This is the biggest library change since the initial release.
The major problem with this keyword-like identifier is that it must have a single type as it's implemented as a thread-local variable.
Since there are so many different kinds of actors (event-based or blocking, untyped or typed), \lstinline^self^ needs to perform type erasure at some point, rendering it ultimately useless.
Instead of a thread-local pointer, you can now use the first argument in functor-based actors to "catch" the self pointer with proper type information.
\paragraph{\lstinline^actor_ptr^ has been replaced}
~
\lib now distinguishes between handles to actors, i.e., \lstinline^typed_actor<...>^ or simply \lstinline^actor^, and \emph{addresses} of actors, i.e., \lstinline^actor_addr^. The reason for this change is that each actor has a logical, (network-wide) unique address, which is used by the networking layer of \lib. Furthermore, for monitoring or linking, the address is all you need. However, the address is not sufficient for sending messages, because it doesn't have any type information. The function \lstinline^last_sender()^ now returns the \emph{address} of the sender.
This means that previously valid code such as \lstinline^send(last_sender(), ...)^ will cause a compiler error.
However, the recommended way of replying to messages is to return the result from the message handler.
\paragraph{The API for typed actors is now similar to the API for untyped actors}
~
The APIs of typed and untyped actors have been harmonized.
Typed actors can now be published in the network and also use all operations untyped actors can.
Besides event-based actors (the default implementation), \libcppa also provides context-switching and thread-mapped actors that can make use of the blocking API.
Besides event-based actors (the default implementation), \lib 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.
...
...
@@ -21,7 +21,7 @@ self->receive (
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.
\lib provides three predefined receive loops to provide a more efficient but yet convenient way of defining receive loops.
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}).
The message passing implementation of \lib uses tuples with call-by-value semantic.
Hence, it is not necessary to declare message types, though, \lib 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.
To avoid unnecessary copying overhead, \lib 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.
...
...
@@ -30,7 +30,7 @@ assert(&get<0>(x1) != &get<0>(x2)); // no longer the same
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
Users of \lib 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.
Before diving into the API of \libcppa, we would like to take the opportunity to discuss the concepts behind \libcppa and to explain the terminology used in this manual.
Before diving into the API of \lib, we would like to take the opportunity to discuss the concepts behind \lib and to explain the terminology used in this manual.
\subsection{Actor Model}
...
...
@@ -15,19 +15,19 @@ Additionally, mutex-based implementations can cause queueing and unmindful acces
The actor model has gained momentum over the last decade due to its high level of abstraction and its ability to make efficient use of multicore and multiprocessor machines.
However, the actor model has not yet been widely adopted in the native programming domain.
With \libcppa, we contribute a library for actor programming in C++ as open source software to ease native development of concurrent as well as distributed systems.
In this regard, \libcppa follows the C++ philosophy ``building the highest abstraction possible without sacrificing performance''.
With \lib, we contribute a library for actor programming in C++ as open source software to ease native development of concurrent as well as distributed systems.
In this regard, \lib follows the C++ philosophy ``building the highest abstraction possible without sacrificing performance''.
\subsection{Terminology}
You will find that \libcppa has not simply adopted exiting implementations based on the actor model such as Erlang or the Akka library.
Instead, \libcppa aims to provide a modern C++ API allowing for type-safe as well as dynamically typed messaging.
You will find that \lib has not simply adopted exiting implementations based on the actor model such as Erlang or the Akka library.
Instead, \lib aims to provide a modern C++ API allowing for type-safe as well as dynamically typed messaging.
Hence, most aspects of our system are familiar to developers having experience with other actor systems, but there are also slight differences in terminology.
However, neither \libcppa nor this manual require any foreknowledge.
However, neither \lib nor this manual require any foreknowledge.
\subsubsection{Actor Address}
In \libcppa, each actor has a (network-wide) unique logical address that can be used to identify and monitor it.
In \lib, each actor has a (network-wide) unique logical address that can be used to identify and monitor it.
However, the address can \emph{not} be used to send a message to an actor.
This limitation is due to the fact that the address does not contain any type information about the actor.
Hence, it would not be safe to send it any message, because the actor might use a strictly typed messaging interface not accepting the given message.
...
...
@@ -36,7 +36,7 @@ Hence, it would not be safe to send it any message, because the actor might use
An actor handle contains the address of an actor along with its type information.
In order to send an actor a message, one needs to have a handle to it -- the address alone is not sufficient.
The distinction between handles and addresses -- which is unique to \libcppa when comparing it to other actor systems -- is a consequence of the design decision to support both untyped and typed actors.
The distinction between handles and addresses -- which is unique to \lib when comparing it to other actor systems -- is a consequence of the design decision to support both untyped and typed actors.
\subsubsection{Untyped Actors}
...
...
@@ -67,4 +67,4 @@ Each actor sends an ``exit message'' to all of its links as part of its terminat
Unlike down messages (cf. \ref{sec:monitoring}), the default behavior for received exit messages causes the receiving actor to terminate for the same reason if the link has failed, i.e., terminated with a non-normal exit reason.
This allows developers to create a set of actors with the guarantee that either all or no actors are alive.
The default behavior can be overridden, i.e., exit message can be ``trapped''.
When trapping exit messages, they are received as any other ordinary message and can be handled by the actor.
\ No newline at end of file
When trapping exit messages, they are received as any other ordinary message and can be handled by the actor.
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.
An event-based actor, i.e., the default implementation in \lib, 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}
...
...
@@ -15,7 +15,7 @@ class printer : public event_based_actor {
behavior make_behavior() override {
return {
others() >> [] {
cout << to_string(last_received()) << endl;
cout << to_string(last_dequeued()) << endl;
}
};
}
...
...
@@ -29,7 +29,7 @@ This base class simply returns \lstinline^init_state^ (defined in the subclass)
struct printer : sb_actor<printer> {
behavior init_state {
others() >> [] {
cout << to_string(last_received()) << endl;
cout << to_string(last_dequeued()) << endl;
}
};
};
...
...
@@ -58,12 +58,14 @@ class fixed_stack : public sb_actor<fixed_stack> {
@@ -82,7 +84,8 @@ class fixed_stack : public sb_actor<fixed_stack> {
empty = (
on(atom("push"), arg_match) >> [=](int what) {
data.push_back(what);
become(filled);
if (data.size() == max_size) become(full);
else become(filled);
},
on(atom("pop")) >> [=] {
return atom("failure");
...
...
@@ -125,7 +128,7 @@ An event-based actor finishes execution with normal exit reason if the behavior
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.
\textbf{Note}: the message handling in \lib 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.
...
...
@@ -143,14 +146,14 @@ But often, we need to be able to recover if an expected messages does not arrive
#include <iostream>
#include "cppa/cppa.hpp"
using std::endl;
using endl;
behavior eager_actor(event_based_actor* self) {
return {
[](int i) { /* ... */ },
[](float i) { /* ... */ },
others() >> [] { /* ... */ },
after(std::chrono::seconds(10)) >> [] {
after(chrono::seconds(10)) >> [] {
aout(self) << "received nothing within 10 seconds..." << endl;
// ...
}
...
...
@@ -162,14 +165,14 @@ 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^.
\lib 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.
Unmatched messages are skipped automatically by \lib'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.
@@ -92,4 +92,4 @@ The following diagram illustrates forwarding of a synchronous message from actor
\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
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()^.
@@ -12,7 +12,7 @@ All functions for message passing, linking and monitoring are overloaded to acce
\label{sec:strong:spawn}
Typed actors are spawned using the function \lstinline^spawn_typed^.
The argument to this function call \emph{must} be a match expression as shown in the example below, because the runtime of libcppa needs to evaluate the signature of each message handler.
The argument to this function call \emph{must} be a match expression as shown in the example below, because the runtime of \lib needs to evaluate the signature of each message handler.
@@ -30,7 +30,7 @@ When using \lstinline^timed_sync_send^ function, \lstinline^after(...)^ statemen
\subsection{Error Messages}
When using synchronous messaging, \libcppa's runtime environment will send ...
When using synchronous messaging, \lib's runtime environment will send ...
\begin{itemize}
\item if the receiver is not alive:\newline\lstinline^sync_exited_msg { actor_addr source; std::uint32_t reason; };^
...
...
@@ -90,7 +90,7 @@ void foo(event_based_actor* self, actor testee) {
\clearpage
\subsubsection{Continuations for Event-based Actors}
\libcppa supports continuations to enable chaining of send/receive statements.
\lib supports continuations to enable chaining of send/receive statements.
The functions \lstinline^then^ returns a helper object offering the member function \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.
\libcppa provides a fully network transparent communication between actors.
Thus, \libcppa needs to serialize and deserialize messages.
\lib provides a fully network transparent communication between actors.
Thus, \lib 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^.
\lib 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.
...
...
@@ -18,7 +18,7 @@ However, you should rarely if ever need to use \lstinline^object^ or \lstinline^
\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.
All user-defined types must be explicitly ``announced'' so that \lib can (de)serialize them correctly, as shown in the example below.
\begin{lstlisting}
#include "cppa/cppa.hpp"
...
...
@@ -32,7 +32,7 @@ int main() {
}
\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.
Without the \lstinline^announce^ function call, the example program would terminate with an exception, because \lib 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.
...
...
@@ -40,4 +40,4 @@ 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
See \lstinline^announce_example_5.cpp^ in the examples folder.