Archive

Archive for February, 2011

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

February 25, 2011 7 comments

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.

Categories: Uncategorized Tags: , ,
Follow

Get every new post delivered to your Inbox.