0% found this document useful (0 votes)
26 views45 pages

CAF Presentation

The document discusses the C++ Actor Framework (CAF), which provides tools for building distributed, concurrent applications using the actor model. CAF offers different actor implementations that can be statically or dynamically typed as well as event-based or blocking. Actors communicate asynchronously by message passing and have features like message handlers, spawning, and monitoring other actors.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as ODP, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
26 views45 pages

CAF Presentation

The document discusses the C++ Actor Framework (CAF), which provides tools for building distributed, concurrent applications using the actor model. CAF offers different actor implementations that can be statically or dynamically typed as well as event-based or blocking. Actors communicate asynchronously by message passing and have features like message handlers, spawning, and monitoring other actors.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as ODP, PDF, TXT or read online on Scribd
You are on page 1/ 45

C++ Actor Framework

Muhammad Usman
Actor Model
Conceptual Model of concurrent computation.
Actor:
Fundamental unit of computation (computation has three
elements). So, actor should embody three things:
1. Processing (to get something done)
2. Storage (to remember things)
3. communication
Basic Operations of Actors

1)Create another actor


2)Send Message
3)Designate how to handle next message
Properties of actors
• Has Address (to communicate with other actors)
• Run locally or remotely on other machines
• Has own mailbox
• Has private state
• Have different behaviors on receiving message,
• Isolated from each other and do not share memory
• Communicate with each other only through messages
• Handle one message at a time
• Work asynchronously
Pros and Cons
Pros:

Easy to scale

Fault tolerance

Geographical distribution

No shared state
Cons:

Actors susceptible to deadlocks

Actors mailbox overflowing
Actor References
Address:
Each actor has a (network-wide) unique logical address. This identifier is
represented by actor_addr, which allows to identify and monitor an actor.CAF
does not allow users to send messages to addresses.
Handler:
An actor handle contains the address of an actor along with its type information
and is required for sending messages to actors.
Pointer:
In a few instances, CAF uses strong_actor_ptr to refer to an actor using strong
reference semantics without knowing the proper handle type. Pointers must be
converted to a handle via actor_cast prior to sending messages.
Introduction
CAF offers a high-level programming environment
based on the Actor Model of computation combined
with an efficient, native runtime environment that
lets you build scalable applications. For example,
software for molecular research, communication
backends for distributed network security monitoring
or even massive multiplayer online games.
Dependencies

1.CMake (for building CAF)


2. OpenSSL (only when building the OpenSSL
module)
Supported Platforms
1.Linux
2.Windows
3.MacOS
4.FreeBDS
Message Handlers
Actors can store a set of callbacks—usually
implemented as lambda expressions—using either
behavior or message_handler.

Behavior defines the response of an actor to


messages it receives. The optional timeout allows an
actor to dynamically change its behavior when not
receiving message after a certain amount of time.
Composition
message_handler x1{
[](int32_t i) { /*...*/ },
[](double db) { /*...*/ },
[](int32_t a, int32_t b, int32_t c) { /*...*/ }
};
Composition

message_handler x2{
[](double db) { /*...*/ },
[](double db) { /* - unreachable - */ }
};
Composition
message_handler x3 = x1.or_else(x2);
message_handler x4 = x2.or_else(x1);

Message handlers can be combined using or_else. This


composition is 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 fall
back to the right-hand operand if the former did not match.
Atom

The Erlang programming language introduced an


approach to use non-numerical constants, so-
called atoms, which have an unambiguous,
special-purpose type and do not have the runtime
overhead of string constants.
Actors
CAF provides several actor implementations, each covering a particular
use case. The available implementations differ in three characteristics:
(1) dynamically or statically typed,
(2) class-based or function-based, and
(3) using asynchronous event handlers or blocking receives.

These three characteristics can be combined freely, with one exception:


statically typed actors are always event-based.
Common Actor Base Types
Class local_actor
The class local_actor is the root type for all user-
defined actors in CAF. It defines all common
operations. However, users of the library usually
do not inherit from this class directly. Proper base
classes for user-defined actors are
event_based_actor or blocking_actor
Class scheduled_actor

All scheduled actors inherit from scheduled_actor.


This includes statically and dynamically typed
event-based actors as well as brokers.
Class blocking_actor
A blocking actor always lives in its own thread of
execution. They are not as lightweight as event-
based actors and thus do not scale up to large
numbers. The primary use case for blocking
actors is to use a scoped_actor for ad-hoc
communication to selected actors.
Messaging Interfaces
Statically typed actors require abstract messaging
interfaces to allow the compiler to type-check
actor communication. Interfaces in CAF are
defined using the variadic template
typed_actor<...>, which defines the proper actor
handle at the same time.
Messaging Interfaces
using calculator_actor
= typed_actor<result<int32_t>(add_atom, int32_t, int32_t),
result<int32_t>(sub_atom, int32_t, int32_t)>;

Interfaces have set semantics. This means the following two type aliases
i1 and i2 are considered equal by CAF:
using i1 = typed_actor<replies_to<A>::with<B>, replies_to<C>::with<D>>;
using i2 = typed_actor<replies_to<C>::with<D>, replies_to<A>::with<B>>;
Spawning Actors
Both statically and dynamically typed actors are
spawned from an actor_system using the member
function spawn. The function either takes a
function as first argument or a class as first
template parameter.
Spawning example
behavior calculator_fun(event_based_actor* self);
void blocking_calculator_fun(blocking_actor* self);
calculator_actor::behavior_type typed_calculator_fun();
class calculator;
class blocking_calculator;
class typed_calculator;
auto a1 = sys.spawn(calculator_fun);
auto a2 = sys.spawn(blocking_calculator_fun);
auto a3 = sys.spawn(typed_calculator_fun);
auto a4 = sys.spawn<calculator>();
auto a5 = sys.spawn<blocking_calculator>();
auto a6 = sys.spawn<typed_calculator>();
Function-based Actors
When using a function or function object to
implement an actor, the first argument can be
used to capture a pointer to the actor itself. The
type of this pointer is usually event_based_actor*
or blocking_actor*. The proper pointer type for any
typed_actor handle T can be obtained via
T::pointer
Class-based Actors
Implementing an actor using a class requires the following:

Provide a constructor taking a reference of type
actor_config& as first argument, which is forwarded to the
base class. The config is passed implicitly to the
constructor when calling spawn, which also forwards any
number of additional arguments to the constructor.

Override make_behavior for event-based actors and act for
blocking actors.
Stateful Actors
The stateful actor API makes it easy to maintain state in
function-based actors. It is also safer than putting state in
member variables, because the state ceases to exist after an
actor is done and is not delayed until the destructor runs.
For example, if two actors hold a reference to each other via
member variables, they produce a cycle and neither will get
destroyed. Using stateful actors instead breaks the cycle,
because references are destroyed when an actor calls self-
>quit() (or is killed externally)
Message Passing
The messaging layer of CAF has three primitives
for sending messages: send, request, and delegate
Structure of Mailbox Elements
Default and System Message
Handlers
CAF has three system-level message types
(down_msg, exit_msg, and error) that all actors
should handle regardless of their current state.
Down Handler
Actors can monitor the lifetime of other actors by
calling self->monitor(other). This will cause the
runtime system of CAF to send a down_msg for other
if it dies. Actors drop down messages unless they
provide a custom handler via set_down_handler(f),
where f is a function object with signature void
(down_msg&) or void (scheduled_actor*,
down_msg&).
Exit Handler
Bidirectional monitoring with a strong lifetime coupling is
established by calling self->link_to(other). This will cause the
runtime to send an exit_msg if either this or other dies. Per default,
actors terminate after receiving an exit_msg unless the exit reason
is exit_reason::normal. This mechanism propagates failure states
in an actor system. Linked actors form a sub system in which an
error causes all actors to fail collectively. Actors can override the
default handler via set_exit_handler(f), where f is a function object
with signature void (exit_message&) or void (scheduled_actor*,
exit_message&).
Error Handler
Actors send error messages to others by returning
an error (see Errors) from a message handler.
Default Handler
The default handler is called whenever the behavior of an actor did
not match the input. Actors can change the default handler by
calling set_default_handler. The expected signature of the function
object is result<message> (scheduled_actor*, message_view&),
whereas the self pointer can again be omitted. The default handler
can return a response message or cause the runtime to skip the
input message to allow an actor to handle it in a later state. CAF
provides the following built-in implementations: reflect,
reflect_and_quit, print_and_drop, drop, and skip
Requests Message
Actors send request messages by calling
request(receiver, timeout, content...) . This function
returns an intermediate object that allows an actor
to set a one-shot handler for the response
message. Event-based actors can use either
request(...).then or request(...).await.
request(...).receive
Error Handling in Requests
CAF allows to add an error handler as optional
second parameter to then and await (this
parameter is mandatory for receive). If no such
handler is defined, the default error handler (see
Error Handler) is used as a fallback in scheduled
actors.
Delegating Messages
Response Promises
Scheduler
The CAF runtime maps N actors to M threads on the local machine.
Applications built with CAF scale by decomposing tasks into many
independent steps that are spawned as actors. In this way, sequential
computations performed by individual actors are small compared to the total
runtime of the application.
The performance of actor-based applications depends on the scheduling
algorithm in use and its configuration. Different application scenarios require
different trade-offs. For example, interactive applications such as shells or
GUIs want to stay responsive to user input at all times, while batch
processing applications demand only to perform a given task in the shortest
possible time.
Work Stealing
Work Stealing
Each worker dequeues work items from an individual queue until it is drained. Once
this happens, the worker becomes a thief. It picks one of the other workers—usually
at random—as a victim and tries to steal a work item. As a consequence, tasks
(actors) are bound to workers by default and only migrate between threads as a result
of stealing. This strategy minimizes communication between threads and maximizes
cache locality. Work stealing has become the algorithm of choice for many
frameworks.

CAF uses three polling intervals. Once a worker runs out of work items, it tries to
steal items from others. First, it uses the aggressive polling interval. It falls back to a
moderate interval after a predefined number of trials. After another predefined number
of trials, it will finally use a relaxed interval.
Registry
The actor registry in CAF keeps track of the number of running actors
and allows to map actors to their ID or a custom atom (see Atoms)
representing a name. The registry does not contain all actors. Actors
have to be stored in the registry explicitly. Users can access the
registry through an actor system by calling system.registry(). The registry
stores actors using strong_actor_ptr
Users can use the registry to make actors system-wide available by
name. The Middleman uses the registry to keep track of all actors
known to remote nodes in order to serialize and deserialize them.
Actors are removed automatically when they terminate.
Middleman
The middleman is the main component of the I/O module
and enables distribution. It transparently manages proxy
actor instances representing remote actors, maintains
connections to other nodes, and takes care of serialization
of messages. Applications install a middleman by loading
caf::io::middleman as module (see Configuring Actor
Applications). Users can include "caf/io/all.hpp" to get
access to all public classes of the I/O module.
Network I/O with Brokers
When communicating to other services in the network,
sometimes low-level socket I/O is inevitable. For this reason,
CAF provides brokers. A broker is an event-based actor
running in the middleman that multiplexes socket I/O. It can
maintain any number of acceptors and connections. Since the
broker runs in the middleman, implementations should be
careful to consume as little time as possible in message
handlers. Brokers should outsource any considerable amount
of work by spawning new actors or maintaining worker actors.

You might also like