Simple message pump implementation

08 Aug 2010 . Edited: 09 Aug 2010

The use of messages to signal events occurring is a fairly common (if not ubiquitous) practise in the GUI world. In a project I'm working on at the moment, I found that the easiest way to implement what I needed was via a simple message pump, allowing several independent pieces of code to work together without needing special synchronisation, and especially without needing to know the implementation of each other.

I present the implementation I came up with below. I would welcome any feedback regarding improving this (or fixing any oversights on my part). Particularly if anyone wishes to use this I would be very glad to hear and may publish as a library once it is sufficiently stable.

 

message_pump.h

#include <map>


#define MSG_TYPE int

struct Message
{
    MSG_TYPE msg_type;
    int value;
    void *content_ptr;
};

typedef void (*HANDLER_FUNC)(Message *);


extern void add_message_handler(MSG_TYPE msg_type, HANDLER_FUNC handler);
extern void add_message(Message *message);
extern void message_pump();

extern std::map<MSG_TYPE, HANDLER_FUNC> handlers;

 

message_pump.cpp

#include <deque>
#include <map>
#include <memory>


std::deque<Message> messages;
std::map<MSG_TYPE, HANDLER_FUNC> handlers;


void add_message_handler(MSG_TYPE msg_type, HANDLER_FUNC handler)
{
    handlers[msg_type] = handler;
}


void add_message(Message *message)
{
    messages.push_back(*message);
}


void message_pump()
{
    if (messages.size() > 0)
    {
        std::auto_ptr<Message> message(new Message(messages.front()));
        messages.pop_front();
        
        // We handle deleting the message object, but the handler function needs
        // to delete anything pointed to by content_ptr
        handlers[message->msg_type](message.get());
    }
}


Example user code

#include "mbed.h"
#include "TextLCD.h"
#include "message_pump.h"


InterruptIn button(p12);
unsigned int count = 0;
#define PRESSED_BUTTON 100
TextLCD lcd(p23, p24, p25, p26, p27, p28, TextLCD::LCD16x2);


void press_button()
{
    Message message;
    message.msg_type = PRESSED_BUTTON;
    message.value = 50;
    message.content_ptr = NULL;
    add_message(&message);
}


void handle_button(Message *message)
{
    lcd.cls();
    lcd.printf("%u", count + message->value);
    ++count;
 }


int main() {
    button.rise(&press_button);
    
    add_message_handler(PRESSED_BUTTON, &handle_button);

    while (1)
    {
        message_pump();
    }
}

The example code above is a very simple example which add the value1 member of the message to the count variable and displays it on an attached LCD. Upon pressing the button you should see the count begin at 50. This is probably not a very realistic example of use, but I think it serves the purpose of demonstrating the code. One advantage here is that as long as only one thread calls message_pump, the handler functions don't need to be re-entrant.

One outstanding todo item I know about is that the add_message function needs to be made thread safe.

09 Aug 2010 . Edited: 09 Aug 2010

Accidental quote while editing.