Here’s an abstraction of a class I’m having some fun with. In my own use:
- init() is called and a pointer to a listener (subclass of SomeClassListener) is passed in. The instance this pointer points to is what handles the callbacks.
- init() continues to start a socket and start a thread with threadLoop().
- threadLoop() receives data from the socket, grabs the header, and decides what callback to fire based on that header.
The following code demonstrates how Boost::bind allows the check for whether or not to multithread a callback can be done in one place for every single callback (see fireCallback()).
#include "SomeClassListener.h" class SomeClass { public: SomeClass(); int init(SomeClassListener* listener); bool isMultithreadingEnabled(); void setMultithreadedCallbacks(bool enabled); private: int threadLoop(); template <typename T> void fireCallback( T handler ); private: SomeClassListener *listener; bool isMultithreaded; enum { CALLBACK_TYPE_1 = 0, CALLBACK_TYPE_2, CALLBACK_TYPE_3, }; typedef struct DataType1 { float x; float y; float z; } DataType1; typedef struct DataType2 { char* foo; bool bar; } DataType1; }; /***************************/ SomeClass::SomeClass() { setMultithreadedCallbacks( false ); } int SomeClass::init(SomeClassListener* listener) { /* Various initialisations... */ this->listener = listener; new boost::thread(boost::bind(boost::mem_fn(&SomeClass::threadLoop), this)); return 0; } bool SomeClass::isMultithreadingEnabled() { return isMultithreaded; } void SomeClass::setMultithreadedCallbacks(bool enabled) { isMultithreaded = enabled; } template <typename T> void SomeClass::fireCallback( T handler ) { if ( isMultithreadingEnabled() ) new boost::thread(handler); else handler(); } int SomeClass::threadLoop() { printf("Thread starting...\n"); for ( ;; ) { // void* dataStart = recvSomeData(); /* Do something to present us with a decision, such as checking data headers. */ switch ( option ) { case CALLBACK_TYPE_1: { DataType1* d = (DataType1*)dataStart; // SomeClassListener::callback1( float, float, float ) fireCallback(boost::bind(boost::mem_fn(&SomeClassListener::callback1), listener, d->x, d->y, d->z )); break; } case CALLBACK_TYPE_2: { DataType2* d = (DataType2*)dataStart; // SomeClassListener::callback2( char*, bool ) // (you might want to memcpy() that char* if this will be multithreaded, // as once this thread receives more data, the buffer will be overwritten. fireCallback(boost::bind(boost::mem_fn(&SomeClassListener::callback2), listener, d->foo, d->bar )); break; } case CALLBACK_TYPE_3: { void* d = (void*)dataStart; // SomeClassListener::callback3( void* ) fireCallback(boost::bind(boost::mem_fn(&SomeClassListener::callback3), listener, d )); break; } default: printf("***ERROR***\n"); } } printf("Thread finished...\n"); return 0; }
