YkdLockManager is an idea that had been bouncing around for a while but I threw it together today and it’s working well. (By the way, Ykd is the class prefix for YakumoDemo.)
My code has lots of threads everywhere, and that means that I need to lock a lot of objects a lot of the time. What would be really nice is if every object I’m using, from all five or so SDKs, had methods which allowed me to lock and unlock them. Since that’s not realistic, the solution I came up with was YkdLockManager, which is basically a wrapper around an std::map of void pointers and mutexes.
Here’s an abstraction of what the class definition looks like:
class YkdLockManager { public: void lock( void* object ); void unlock( void* object ); boost::mutex* getMutex(void* object); private: std::map<void*, boost::mutex*> mLockMap; boost::mutex mLockMapLock; };
I’ve taken away the singleton code to keep the expression of intention of the class clearer, but it does implement the singleton pattern so I can do something like the following from anywhere in code:
YkdLockManager::getSingleton().lock( this );
… and later unlock it in a similar fashion. So now every object in my code can be locked or unlocked, by passing its memory address into YkdLockManager.
All lock() and unlock() do is call getMutex() and then call lock() or unlock() respectively on the mutex that’s returned.
Here’s what getMutex() does:
boost::mutex* YkdLockManager::getMutex(void* object){ boost::mutex::scoped_lock lock( mLockMapLock ); // find the mutex in the map std::map<void*, boost::mutex*>::iterator it = mLockMap.find( object ); // if it wasn't found... if ( it == mLockMap.end() ) { // create a new mutex for the object, add it, and return it boost::mutex *mutex = new boost::mutex(); mLockMap[object] = mutex; return mutex; } // if it was found, return the associated mutex return it->second; }
Look back at mLockMapLock: while writing the class I realised that it’s inherently going to be called by multiple threads at the same time (that’s the whole point), so what if two threads call lock() at the same time on the same object for the first time, and they both go to create the necessary mutex? That won’t do, so I have to lock the map before doing any operations on it… hence a lock-map lock is in order.
As painful as it is to debug all this stuff, it really is exciting when every thread is co-operating nicely with all the others.
