On creating an asynchronous message-based c++ framework; part 1

This is the first post in a series on the creation of an asynchronous message-based C++ application framework. The series will in particular show the use of several parts of the excellent Boost C++ libraries to achieve this, and the application of several design patterns in a real-world context. I will also show the evolution of this framework during the series, so you can understand the decisions I made and see the problems I came up against, rather than just a polished end-result.

Requirements

Firstly, then, a few requirements and design considerations. I want my framework to:

  • Implement an asynchronous message-based notification system to enable the decoupling of data consumers from data producers. This decoupling will help to keep the design modular, and makes unit testing easier.
  • Provide the facility to monitor for read/write readiness of files (including regular files, pipes, sockets, and hardware device).
  • Provide the facility to schedule timed events (ignoring latency induced by processing and the scheduler).

The first piece: a storable observer type

We will start off with the observer pattern, since much of the rest of the functionality hinges on this and it will form the core of the message delivery mechanism. It is a common pattern that also crops up as a subset of other well-known patterns, so hopefully it will be familiar to the majority of you.

The subject – the object being observed – will need to be able to store a set of observer references. As I will want an object to observe more than 1 subject, we need to be able to register different methods of different classes as observers.

To store pointers-to-members of different classes in the same type with type-safety, both classes would need to derive from a common base; we could then store a pointer-to-member of either in a void (base::*)() pointer. We would also have to store a reference to each registered observer instance. This is doable, but it involves some dull typing, and excludes the following from being observers:

  • Classes I cannot change (e.g. third-party/legacy code)
  • Free functions
  • Static member functions

Instead, I elected to use boost::function, since it provides the following benefits:

  • It can wrap pointers to free functions, static and non-static member functions, and functors (function objects)
  • It can wrap any member function without need to modify the class definition
  • It is easy to use with boost::bind, so binding an instance to a method is a no-brainer, with the added bonus that we can bind additional parameters too without modifying the subject.

Let’s define our observer type, and then we can define the type of a container of observers too. We’ll make each observer take some ‘message’ type which can provide information about the notification.

typedef boost::function<void (const message&)> observer;
typedef std::vector<observer*> observer_set;

Subjects and their observers

Implementing that behind the typical interface for an observable subject, we can create a base class for subjects like so:

struct subject
{
   virtual ~subject() {}

   void registerObserver(observer& o) {
      observers.push_back(&o);
   }

   // unregisterObserver unimplemented for now...

   void notifyObservers(const message& m) {
      BOOST_FOREACH (observer* o, observers)
         (*o)(m);
   }

private:
   typedef std::vector<observer*> observer_set;
   observer_set observers;
};

And a complete test program:

#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/foreach.hpp>
#include <iostream>
#include <vector>
using namespace std;

typedef int message;
// simple for now: each message is an event type identifier (like windows messages)
typedef boost::function<void (const message&)> observer;

struct subject
{
    virtual ~subject() {}

    void registerObserver(observer& o) {
        observers.push_back(&o);
    }

   // unregisterObserver unimplemented for now...

    void notifyObservers(const message& m) {
        BOOST_FOREACH (observer* o, observers)
            (*o)(m);
    }

private:
    typedef std::vector<observer*> observer_set;

    observer_set observers;
};

void notify(const message& m)
{
    cout << "notify: got message " << m << endl;
}

struct MyObserver
{
    void notify(const message& m, const char* name) {
        cout << "MyObserver::notify [" << name << "] got message " << m << endl;
    }
};

int main()
{
    subject s;
    MyObserver mo;

    observer oFree(&notify);
    char name[] = "bobs";
    observer oMember(boost::bind(&MyObserver::notify, &mo, _1, name));

    s.registerObserver(oFree);
    s.registerObserver(oMember);
    s.notify(12);
}

The last word…

Now that we have the primary building block of the framework – the types for subjects and observers – I’ll be looking next at how to implement a message type hierarchy and will apply the decorator pattern in doing so. Part 2 will trundle along sometime in the next fortnight, so thanks for reading and in the meantime please leave any comments or suggestions below.

Advertisements
This entry was posted in Uncategorized and tagged , , . Bookmark the permalink.

8 Responses to On creating an asynchronous message-based c++ framework; part 1

  1. Prabhakar says:

    Hi Rob,

    I suppose you are planning to implement a observer pattern with a single thread. If not how are you planning to take care of the situation with observers in multiple tasks. I am sorry I illiterate in boost.

    Regards,
    Prabhakar

    • robdesbois says:

      Hi Prabhakar,

      We’ve not yet needed messages to be able to cross thread boundaries, but a comment on this from a LinkedIn user was that a library called boost::lockfree would be a firm basis for cross-threaded observers. Whilst I haven’t tried it or even looked in depth at that library, it sounds good in principle.

      In our framework we tend to keep all of the observers in a single thread; since the framework is asynchronous all I/O is also asynchronous (implemented with select() rather than non-blocking I/O), and any computationally intensive work we give its own worker thread. That’s particular to the way we’re doing things though, and doesn’t mean it’s the ‘right’ way.

      Boost is a great library – I’ve found it to enable me to write much more expressive code – i.e. code which reads like my intentions – than was possible without; in particular, boost::{function,bind,lexical_cast} and BOOST_FOREACH are great assets I use most of the time. I can recommend it well 🙂

  2. Michal Mocny says:

    Just out of curiosity, have you looked into boost::asio?

    • robdesbois says:

      Hi Michal, I glanced over it briefly a few years back when it first arrived in Boost, but dismissed it at the time as the project I was working on used synchronous I/O exclusively and threads to prevent operations from blocking each other.
      When it came to developing the I/O parts of this framework (which I’ll cover in later posts,) I was working with networking I/O functionality that already existed in one of our own libraries so didn’t consider it then.
      Having had a new look at the overview, it’s a nice looking library; I may have a play and cover it in later posts; thanks for the reminder 🙂

      • Ahmed says:

        Rob,
        also you may have a look at Push Framework.
        Like Boost asio, that was already suggested, PF handles IO events asynchronously (using IOCP in Windows and two epoll queues in Linux).

        The abstract notion of “subject” that you were talking about coincides with the notion of Broadcasting channel in PF.

        Further more, if for a particular observer (the client) there are many “subjects” he is subscribed to, then you can prioritize between “subjects” using rules of QoS : http://www.pushframework.com/?page_id=435

  3. robdesbois says:

    A comment on LinkedIn for this post stated that using inheritance is not a good idea – no additional info yet, but I’ll paste my initial response:

    Your point on inheritance could be right, but it would be useful if you could back it up with additional information as to why, and perhaps suggest an improved design.

    Public inheritance isn’t ideal for importing implementation, but in this case the intended part of the inheritance relationship is to inherit subject’s interface. (I should’ve made subject::notifyObservers protected scope really.)

    I could’ve forwarded the implementation of registerObserver() and notifyObservers on to a member object encapsulating those responsibilities, hence separating the interface inheritance and implementation import into different classes — in this simple case I think it clouds the issue more than it helps design. Thoughts?

  4. Pingback: WL-6 « evetro

  5. Martin says:

    You are overthinking it. Consider looking into “game coding complete”. It has a very powerfull single thread process system.

    You can also implement an async framework and then let your processes wait on conditions (“semaphores”) each task can of course only wait on a single condition at a time. So it’s simple to implement. Then your tasks process events through a state/event handler table. For implementation have a look at how a state machine is implemented in C using a function pointer table that binds actions to events and states.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s