Jan
28
2009

FYP Technology: Optional Multithreaded Callbacks with Boost

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;
}
Written by in: University |

No Comments »

RSS feed for comments on this post. TrackBack URL


Leave a Reply

Powered by WordPress | Theme: Aeros 2.0 by TheBuckmaker.com