libcppa
An implementation of the Actor Model for C++.
Tuesday, May 21, 2013
Version 0.7.1 released
Version 0.7.1 of libcppa has just been released. This release fixes some bugs and improves compatibility with GCC 4.8.
Monday, May 13, 2013
Version 0.7 released
Version 0.7 of libcppa has just been released. For the first time in an official release, this version breaks code compatibility with earlier versions (this was not an easy step and caused some discussion). When calling spawn with a function, the new default implementation is event-based. Hence, your actor should set its behavior using become and not use functions like receive. However, it is pretty easy to port your existing code. To opt-in to the "old" behavior, use spawn<blocking_api>(fun_name).
Among improvements and optimizations, this version includes a few new functions as well:
Please note that the manual has received a huge update due to the changed default behavior of spawn and has not caught up to the new features yet.
Among improvements and optimizations, this version includes a few new functions as well:
- Priority-aware messaging (opt-in feature)
- OpenCL-based actors (must be enabled using '--with-opencl')
Please note that the manual has received a huge update due to the changed default behavior of spawn and has not caught up to the new features yet.
Friday, February 22, 2013
Version 0.6 released
Version 0.6 of libcppa has just been released. This release brings several improvements to the synchronous messaging API. Please read more about features like functor-only usage and continuations in the revamped Section 7 of the manual.
Among several smaller improvements, this release also includes:
Among several smaller improvements, this release also includes:
- manual skipping of messages
- Boost 1.53 support thanks to GitHub user abigagli
- a new quit_actor function to send 'EXIT' messages to actors
Monday, January 7, 2013
Actor Companions
In the previous post about actors with Qt, we have already briefly discussed the concept of actor companions, but this post presents the general approach.
The code shown above is the actual code from cppa/qtsupport/actor_widget_mixin.hpp. As you can see, it is Qt specific, but straightforward. Our "derived mixin" has no constructor arguments and only forwards all arguments to the base constructor (line 11).
The crucial point of this implementation is to convert libcppa messages to Qt events in the implementation of new_message (line 35). The runtime system of Qt will then call the event member function (line 22) later on from inside the event loop. All our implementation has to do is to unwrap the message_pointer and pass it to handle_message.
Once we have called handle_message, our message handler gets invoked – with self pointing to the companion. This way, we can use send and reply as usual in the handler. Even though the code is Qt specific, it should be straightforward to implement a comparable mixin to support your framework of choice.
What is it Good For?
libcppa automatically converts threads to actors if needed (using thread-local storage), whenever a thread uses a message passing primitive such as send(). However, sometimes this conversion is too coarse-grained. Simply put, whenever several independent entities share a thread, but should be addressed individually as actors, we need actor companions. The classical example is a widget. The thread is owned by the event loop, which manages any number of widgets, why we cannot rely on libcppa's automatic thread conversion. If you need to support a library wich internally schedules its entities (perhaps based on green threads or coroutines) - or if you just want to learn more about libcppa, this post is for you.Background
If you want to mix libcppa with an other framework, multiple inheritance is not an option. Usually, each framework manages its entities in an incompatible way. For example, Qt uses hierarchical object ownership by default. This obviously interferes with the reference counting strategy of libcppa. Even if the framework uses reference counts, you will end up having two reference counts in your object. Instead of using multiple inheritance, we use co-existing objects (companions), which serve as gateway. The companion implements the actor interface of libcppa but does not have a mailbox. It forwards all messages it receives to its parent.Mixing in a Solution
Actor companions are enabled by the mixin actor_companion_mixin. The mixin provides the member functions actor_ptr as_actor(), void set_message_handler(...), and void handle_message(const message_pointer&). It also has one pure virtual member function: void new_message(message_pointer). This function must be implemented in a thread-safe way. The type message_pointer is a smart pointer holding a tuple along with meta data such as sender information. There is no need to interact with a message_pointer, as the message handler does everything necessary.A Working Example
template<typename Base, int EventId = static_cast<int>(QEvent::User + 31337)>
class actor_widget_mixin : public actor_companion_mixin<Base> {
typedef actor_companion_mixin<Base> super;
typedef typename super::message_pointer message_pointer;
public:
template<typename... Args>
actor_widget_mixin(Args&&... args) : super(std::forward<Args>(args)...) { }
struct event_type : public QEvent {
message_pointer msg;
event_type(message_pointer mptr)
: QEvent(static_cast<QEvent::Type>(EventId)), msg(std::move(mptr)) { }
};
virtual bool event(QEvent* event) {
if (event->type() == static_cast<QEvent::Type>(EventId)) {
auto ptr = dynamic_cast<event_type*>(event);
if (ptr) {
this->handle_message(ptr->msg);
return true;
}
}
return super::event(event);
}
protected:
virtual void new_message(message_pointer ptr) {
qApp->postEvent(this, new event_type(std::move(ptr)));
}
};
The code shown above is the actual code from cppa/qtsupport/actor_widget_mixin.hpp. As you can see, it is Qt specific, but straightforward. Our "derived mixin" has no constructor arguments and only forwards all arguments to the base constructor (line 11).
The crucial point of this implementation is to convert libcppa messages to Qt events in the implementation of new_message (line 35). The runtime system of Qt will then call the event member function (line 22) later on from inside the event loop. All our implementation has to do is to unwrap the message_pointer and pass it to handle_message.
Once we have called handle_message, our message handler gets invoked – with self pointing to the companion. This way, we can use send and reply as usual in the handler. Even though the code is Qt specific, it should be straightforward to implement a comparable mixin to support your framework of choice.
Version 0.5.5 released
Version 0.5.5 of libcppa has just been released. This release brings several bugfixes and performance improvements as well as aout – A Thread-Safe Wrapper for std::cout.
Wednesday, November 14, 2012
Using Actors with Qt
Actor programming is nice and makes our lives easier, but at some point, we have to display the output of our program to the user. Not everything is a command line tool. Hence, we have to use some sort of GUI library, which raises the question how we pass messages from actors - safely! - to the GUI at runtime. Well, what if we could send an ordinary message to the GUI as if it's an actor? What if the GUI can send us ordinary messages whenever the user pushes some buttons? Briefly speaking, can we treat GUI elements as actors? Luckily, the answer is yes! We have to write some gluecode, but in fact, you can treat everything as an actor with libcppa.
The following class implements a simple group-based chat widget with a QTextEdit for text output and a QLineEdit for user input (chat messages). The full source code can be found in the examples folder in the Git repository.
The second thing to note is that you should never use self outside the message handler. This includes using functions such as send, becauseself is internally used to determine the sender of a message. The reason to this limitation is that libcppa's self "pointer" is thread-local. Using self would therefore convert the Qt thread your widget runs in to an actor, but it wouldn't address your widget's companion.
To send a message from outside of your handler, you have to tell libcppa who is the sender of the message by hand:
Have fun!
Getting Started
In this article, we will focus on the Qt library, as it is the open source GUI library of choice for C++ developers. In the next article, we will have a look at the general concept of actor companions. An actor companion is an actor that co-exists with another object. In our case, this object is a QWidget-base class. The companion is used to receive and send messages, but it does not have any behavior itself. All it takes to enable a class to have such a companion is to use the actor_widget_mixin.The following class implements a simple group-based chat widget with a QTextEdit for text output and a QLineEdit for user input (chat messages). The full source code can be found in the examples folder in the Git repository.
#include <QWidget>
#include "cppa/qtsupport/actor_widget_mixin.hpp"
class ChatWidget : public cppa::actor_widget_mixin<QWidget> {
Q_OBJECT
typedef cppa::actor_widget_mixin<QWidget> super;
// ...
public:
ChatWidget(QWidget* parent = nullptr, Qt::WindowFlags f = 0);
// ...
private:
std::string m_name;
cppa::group_ptr m_chatroom;
};
The mixin adds the following member functions to ChatWidget:
- actor_ptr as_actor()
returns the companion of this widget - set_message_handler
sets the partial function for message processing
Handle Messages to the Widget
In our example, the widget should handle 'join', 'setName', and 'quit' messages as well as display chat messages (received as std::string). We encode our message handling directly into the constructor of ChatWidget:
ChatWidget::ChatWidget(QWidget* parent, Qt::WindowFlags f) : super(parent, f) {
set_message_handler (
on(atom("join"), arg_match) >> [=](const group_ptr& what) {
if (m_chatroom) {
send(m_chatroom, m_name + " has left the chatroom");
self->leave(m_chatroom);
}
self->join(what);
print(("*** joined " + to_string(what)).c_str());
m_chatroom = what;
send(what, m_name + " has entered the chatroom");
},
on(atom("setName"), arg_match) >> [=](string& name) {
send(m_chatroom, m_name + " is now known as " + name);
m_name = std::move(name);
print("*** changed name to "
+ QString::fromUtf8(m_name.c_str()));
},
on(atom("quit")) >> [=] {
close(); // close widget
},
on<string>() >> [=](const string& txt) {
// don't print own messages
if (self != self->last_sender()) {
print(QString::fromUtf8(txt.c_str()));
}
}
);
}
Pitfalls & Things to Know
The code is pretty straight forward if you are already familiar with libcppa, but there is one important thing to note: Unhandled messages are lost. Although the widget is able to handle libcppa messages now, it does not have a mailbox. Messages are delivered to the widget as QEvent objects that are disposed afterwards.The second thing to note is that you should never use self outside the message handler. This includes using functions such as send, because
To send a message from outside of your handler, you have to tell libcppa who is the sender of the message by hand:
send_as(as_actor(), m_chatroom, "hello world!");
Have fun!
Friday, October 26, 2012
Version 0.5 released
Version 0.5 of libcppa has just been released. This release brings Log4j-like logfiles to libcppa developers (must be enabled at compile time), support for user-defined communication protocols, and actor companions.
Each class using the actor_companion_mixin has such an actor companion, which provides an easy way for active non-actor objects, i.e., objects with an own thread or event loop, to send messages to/as actor. The default use case for this feature is to treat GUI elements - widgets - as actors. A more specific mixin for Qt widgets is on its way.
By the way, libcppa now has more than a thousand commits on GitHub! :-)
Each class using the actor_companion_mixin has such an actor companion, which provides an easy way for active non-actor objects, i.e., objects with an own thread or event loop, to send messages to/as actor. The default use case for this feature is to treat GUI elements - widgets - as actors. A more specific mixin for Qt widgets is on its way.
By the way, libcppa now has more than a thousand commits on GitHub! :-)
Subscribe to:
Posts (Atom)