Commit 25641451 authored by Dominik Charousset's avatar Dominik Charousset

manual update for upcoming 0.9 release

parent bbc45bc2
...@@ -9,23 +9,10 @@ Context-switching actors are used for actors that make use of the blocking API ( ...@@ -9,23 +9,10 @@ Context-switching actors are used for actors that make use of the blocking API (
Context-switching and event-based actors are scheduled cooperatively in a thread pool. 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. Thread-mapped actors can be used to opt-out of this cooperative scheduling.
%\subsection{Local Actors} \subsection{Implicit \texttt{self} Pointer}
%The class \lstinline^local_actor^ describes a local running actor. When using a function or functor to implement an actor, the first argument \emph{can} be used to capture a pointer to the actor itself.
%It provides a common interface for actor operations like trapping exit messages or finishing execution. The type of this pointer is \lstinline^event_based_actor^ or \lstinline^blocking_actor^ when using the \lstinline^blocking_api^ flag or their typed counterparts when dealing with typed actors.
\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 \clearpage
\subsection{Interface} \subsection{Interface}
......
...@@ -29,7 +29,7 @@ Please submit a bug report that includes (a) your compiler version, (b) your OS, ...@@ -29,7 +29,7 @@ Please submit a bug report that includes (a) your compiler version, (b) your OS,
\item Network transparent messaging \item Network transparent messaging
\item Error handling based on Erlang's failure model \item Error handling based on Erlang's failure model
\item Pattern matching for messages as internal DSL to ease development \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 Thread-mapped actors for soft migration of existing applications
\item Publish/subscribe group communication \item Publish/subscribe group communication
\end{itemize*} \end{itemize*}
...@@ -62,41 +62,42 @@ We will support this platform as soon as Microsoft's compiler implements all req ...@@ -62,41 +62,42 @@ We will support this platform as soon as Microsoft's compiler implements all req
using namespace std; using namespace std;
using namespace cppa; using namespace cppa;
void mirror() { behavior mirror(event_based_actor* self) {
// wait for messages // wait for messages
become ( return (
// invoke this lambda expression if we receive a string // invoke this lambda expression if we receive a string
on_arg_match >> [](const string& what) -> string { on_arg_match >> [=](const string& what) -> string {
// prints "Hello World!" via aout (thread-safe cout wrapper) // prints "Hello World!" via aout
aout << what << endl; // (a thread-safe cout wrapper)
// terminates this actor afterwards; aout(self) << what << endl;
// 'become' otherwise loops forever // terminates this actor
self->quit(); // ('become' otherwise loops forever)
// replies "!dlroW olleH" self->quit();
return string(what.rbegin(), what.rend()); // reply "!dlroW olleH"
} return string(what.rbegin(), what.rend());
); }
);
} }
void hello_world(const actor_ptr& buddy) { void hello_world(event_based_actor* self, const actor& buddy) {
// send "Hello World!" to our buddy ... // send "Hello World!" to our buddy ...
sync_send(buddy, "Hello World!").then( self->sync_send(buddy, "Hello World!").then(
// ... and wait for a response // ... and wait for a response
on_arg_match >> [](const string& what) { on_arg_match >> [=](const string& what) {
// prints "!dlroW olleH" // prints "!dlroW olleH"
aout << what << endl; aout(self) << what << endl;
} }
); );
} }
int main() { int main() {
// create a new actor that calls 'mirror()' // create a new actor that calls 'mirror()'
auto mirror_actor = spawn(mirror); auto mirror_actor = spawn(mirror);
// create another actor that calls 'hello_world(mirror_actor)' // create another actor that calls 'hello_world(mirror_actor)'
spawn(hello_world, mirror_actor); spawn(hello_world, mirror_actor);
// wait until all other actors we have spawned are done // wait until all other actors we have spawned are done
await_all_others_done(); await_all_actors_done();
// run cleanup code before exiting main // run cleanup code before exiting main
shutdown(); shutdown();
} }
\end{lstlisting} \end{lstlisting}
\section{Introduction}
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.
\subsection{Actor Model}
The actor model describes concurrent entities -- actors -- that do not share state and communicate only via message passing.
By decoupling concurrently running software components via message passing, the actor model avoids race conditions by design.
Actors can create -- ``spawn'' -- new actors and monitor each other to build fault-tolerant, hierarchical systems.
Since message passing is network transparent, the actor model applies to both concurrency and distribution.
When dealing with dozens of cores, mutexes, semaphores and thread primitives are the wrong level of abstraction.
Implementing applications on top of those primitives has proven challenging and error-prone.
Additionally, mutex-based implementations can cause queueing and unmindful sharing can lead to false sharing -- both decreasing performance significantly, up to the point that an application actually runs when adding more cores.
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 development of concurrent as well as distributed software 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 an modern C++ API allowing for type-safe messaging.
\subsubsection{Actor Address}
In \libcppa, 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.
\subsubsection{Actor Handle}
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.
\subsubsection{Spawning}
``Spawning'' an actor means to create and run a new actor.
\subsubsection{Monitoring}
\label{sec:monitoring}
A monitored actor sends a ``down message'' to all actors monitoring it as part of its termination.
This allows actors to supervise other actors and to take measures when one of the supervised actors failed, i.e., terminated with a non-normal exit reason.
\subsubsection{Links}
A link is bidirectional connection between two actors.
Each actor sends an ``exit message'' to all of its links as part of its termination.
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
...@@ -13,19 +13,18 @@ An implementation of \lstinline^init^ shall set an initial behavior by using \ls ...@@ -13,19 +13,18 @@ An implementation of \lstinline^init^ shall set an initial behavior by using \ls
\begin{lstlisting} \begin{lstlisting}
class printer : public event_based_actor { class printer : public event_based_actor {
void init() { behavior make_behavior() override {
become ( return {
others() >> [] { others() >> [] {
cout << to_string(self->last_received()) << endl; cout << to_string(self->last_received()) << endl;
} }
); };
} }
}; };
\end{lstlisting} \end{lstlisting}
Another way to implement class-based actors is provided by the class \lstinline^sb_actor^ (``State-Based Actor''). 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. This base class simply returns \lstinline^init_state^ (defined in the subclass) from its implementation for \lstinline^make_behavior^.
Hence, a subclass must only provide a member of type \lstinline^behavior^ named \lstinline^init_state^.
\begin{lstlisting} \begin{lstlisting}
struct printer : sb_actor<printer> { struct printer : sb_actor<printer> {
......
...@@ -5,14 +5,14 @@ Messages can be sent by using \lstinline^send^, \lstinline^send_tuple^, or \lsti ...@@ -5,14 +5,14 @@ Messages can be sent by using \lstinline^send^, \lstinline^send_tuple^, or \lsti
\begin{lstlisting} \begin{lstlisting}
template<typename... Args> template<typename... Args>
void send(actor_ptr whom, Args&&... what); void send(actor whom, Args&&... what);
\end{lstlisting} \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 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<<^. The following example shows two equal sends, one using \lstinline^send^ and the other using \lstinline^operator<<^.
\begin{lstlisting} \begin{lstlisting}
actor_ptr other = spawn(...); actor other = spawn(...);
send(other, 1, 2, 3); send(other, 1, 2, 3);
other << make_any_tuple(1, 2, 3); other << make_any_tuple(1, 2, 3);
\end{lstlisting} \end{lstlisting}
...@@ -21,7 +21,7 @@ Using the function \lstinline^send^ is more compact, but does not have any other ...@@ -21,7 +21,7 @@ Using the function \lstinline^send^ is more compact, but does not have any other
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. 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} \begin{lstlisting}
actor_ptr other = spawn(...); actor other = spawn(...);
auto msg = make_any_tuple(1, 2, 3); auto msg = make_any_tuple(1, 2, 3);
send(other, msg); // oops, creates a new tuple that contains msg send(other, msg); // oops, creates a new tuple that contains msg
send_tuple(other, msg); // ok send_tuple(other, msg); // ok
...@@ -36,12 +36,11 @@ Choosing one or the other is merely a matter of personal preferences. ...@@ -36,12 +36,11 @@ Choosing one or the other is merely a matter of personal preferences.
\label{Sec::Send::Reply} \label{Sec::Send::Reply}
The return value of a message handler is used as response message. The return value of a message handler is used as response message.
During callback invokation, \lstinline^self->last_sender()^ is set. During callback invocation, \lstinline^self->last_sender()^ is set to the address of the sender.
This identifies the sender of the received message and is used implicitly to reply to the correct sender. Actors can also use the result of a \lstinline^send^ to answer to a request, as shown below.
However, using \lstinline^send(self->last_sender(), ...)^ does \emph{not} reply to the message, i.e., synchronous messages will not recognize the message as response.
\begin{lstlisting} \begin{lstlisting}
void client(const actor_ptr& master) { void client(const actor& master) {
become ( become (
on("foo", arg_match) >> [=](const string& request) -> string { on("foo", arg_match) >> [=](const string& request) -> string {
return sync_send(master, atom("bar"), request).then( return sync_send(master, atom("bar"), request).then(
...@@ -54,46 +53,6 @@ void client(const actor_ptr& master) { ...@@ -54,46 +53,6 @@ void client(const actor_ptr& master) {
}; };
\end{lstlisting} \end{lstlisting}
\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} \subsection{Delaying Messages}
Messages can be delayed, e.g., to implement time-based polling strategies, by using one of \lstinline^delayed_send^, \lstinline^delayed_send_tuple^, \lstinline^delayed_reply^, or \lstinline^delayed_reply_tuple^. Messages can be delayed, 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^.
......
...@@ -45,7 +45,7 @@ ...@@ -45,7 +45,7 @@
%BEGIN LATEX %BEGIN LATEX
\texttt{\huge{\textbf{libcppa}}}\\~\\A C++ library for actor programming\\~\\~\\~\\% \texttt{\huge{\textbf{libcppa}}}\\~\\A C++ library for actor programming\\~\\~\\~\\%
%END LATEX %END LATEX
User Manual\\\normalsize{\texttt{libcppa} version 0.9.0}\vfill} User Manual\\\normalsize{\texttt{libcppa} version 0.9.0} BETA\vfill}
\author{Dominik Charousset} \author{Dominik Charousset}
...@@ -112,6 +112,7 @@ User Manual\\\normalsize{\texttt{libcppa} version 0.9.0}\vfill} ...@@ -112,6 +112,7 @@ User Manual\\\normalsize{\texttt{libcppa} version 0.9.0}\vfill}
} }
% content % content
\include{Introduction}
\include{FirstSteps} \include{FirstSteps}
\include{CopyOnWriteTuples} \include{CopyOnWriteTuples}
\include{PatternMatching} \include{PatternMatching}
......
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