Introduction.md 4.0 KB

Intoduction

Modeling your applications with actors, you can get two benefits: messaging and supervising between actors.

Actor is a reactive entity with a state, which can receive and send messages; actor state is usually changed with new messages. Every message has destination (one or more actors) and user-defined payload. Messaging is send with fire-and-forget approach, i.e. sender does not care about further delivery and processing of the message, like with UDP protocol.

The message delivery is asynchronous, as the message is put into the queue, and will be delivered some time later.

With all that properties it is possible to assemble concurrent programs.

Supervising is more about proper actor initialization order, synchronization and failure handling. Synchronization makes it sure that starting sending messages to actors is performed when actors are ready. Failure handling allows to use different restart strategies of a failing actor, or group of actors, or even escalate locally unresolvable problem into upper layers... upto restarting the whole board restart.

rotor-light is platform-neutral framework, i.e. it can be build and run on any plaform, which conforms the requirements (C++17, basically).

rotor and rotor-light

There is a successful C++ actor microframework rotor, when a few colleagues of mine asked me to have something similar for embedded systems.

The following table highlight the differences

rotor light rotor
max. number of actors 64 unlimited
max. number of messages compile-time defined unlimited
thread-safety no yes
message priorities yes no
request-response pattern no yes
actors discovery & linking no yes
multiple I/O backends no (1) yes
timers yes (1) yes
non-intrusiveness (2) yes yes
dynamic allocations no yes
C++ standard C++17 C++17
dependencies no (except, stdlib++) boost, event-loops
multiple addresses per actor no yes
multiple recipients yes, via broadcasting yes
uses RTTI no yes

(1) rotor-light needs only "now" function from timer, the time point and time interval are abstract notions, have to be defined by end-user of the library.

(2) Non-intrusiveness means, that a framework does not owns execution thread: when all messages have been processed, it just exits as there is nothing to do. That way it is possible to integrate a framework with other event-loops or enter into power-save mode for MCU or even let it go into sleep and wakeup on external event (interrupt).

There are a lot of useful patterns and explanations in rotor documentation, it is worth familiarize self with it to get some insights.

building

rotor-light uses cmake build system. It has no dependencies, except C++17 core libraries (e.g. <tuple>,<type_traits> etc.). Basically, the framework can be build via

mkdir build
cd build
cmake ..
make -j4

There are few customization options:

  • ROTOR_LIGHT_TIMEPOINT defines the type to be used as timepoint. The default value is int64_t

  • ROTOR_LIGHT_DURATION defines the type to be used as time interval. The default value is int32_t

Usage example:

cmake -DROTOR_LIGHT_TIMEPOINT=int32_t ..