SVN is now set up for the FYP. The Trac page is live from Skynet. As I update my code/content/reports they’ll go in there.
Usually I never make any code I do publicly visible but an experiment with the FYP is to make everything visible as I work on it. As with the blog, which is effectively my journal to help me compile my final report, knowing that people are (or may be) watching is proving to be a great motivator.
Any and all input on the project’s code, content, documents, or blog-commentary is welcome.
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,
};
typedefstruct DataType1 {float x;
float y;
float z;
} DataType1;
typedefstruct 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));
return0;
}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");
return0;
}
After spending half the day trying to figure out why my application was crashing randomly while processing the accelerometer data, I fixed it at 00:00 on the dot.
I kept getting random crashes once the callback for accelerometer data receipt was fired a few dozen times. The errors I was getting were so totally random I knew it had to be a memory trashing problem, but I couldn’t figure out where it was. All my code looked great, but of course, I wasn’t fully taking multithreading into account, and I’m multithreading this thing like you can’t imagine.
All the callback was doing was drawing a vector to the screen… how could that possibly cause a problem? Well it suddenly hit me that I was using the Ogre scene-manager to draw the vector, and since Ogre’s main loop was working away in another thread, it was very likely that I was mucking things up by throwing in a new line without waiting my turn on the scene manager data.
To fix it, I created a mutex, locked the Ogre world in the frameStarted() callback and unlocked in the frameEnded() callback. I also locked and unlocked the mutex within the scope of my accelerometerUpdated() callback. And it works!
It was horrible trying to fix such an tricky bug for so long but getting it solved is really rewarding. In fact, to celebrate, I’m going to watch more B’z videos. Here’s OH! GIRL. This involves the guitarist playing back-to-back with a chick playing a Keytar: