Say I have a thread running a member method like runController in the example below:
class SomeClass { public: SomeClass() { // Start controller thread mControllerThread = std::thread(&SomeClass::runController, this) } ~SomeClass() { // Stop controller thread mIsControllerThreadInterrupted = true; // wait for thread to die. std::unique_lock<std:::mutex> lk(mControllerThreadAlive); } // Both controller and external client threads might call this void modifyObject() { std::unique_lock<std::mutex> lock(mObjectMutex); mObject.doSomeModification(); } //... private: std::mutex mObjectMutex; Object mObject; std::thread mControllerThread; std::atomic<bool> mIsControllerInterrupted; std::mutex mControllerThreadAlive; void runController() { std::unique_lock<std::mutex> aliveLock(mControllerThreadAlive); while(!mIsControllerInterruped) { // Say I need to synchronize on mObject for all of these calls std::unique_lock<std::mutex> lock(mObjectMutex); someMethodA(); modifyObject(); // but calling modifyObject will then lock mutex twice someMethodC(); } } //... }; And some (or all) of the subroutines in runController need to modify data that is shared between threads and guarded by a mutex. Some (or all) of them, might also be called by other threads that need to modify this shared data.
With all the glory of C++11 at my disposal, how can I ensure that no thread ever locks a mutex twice?
Right now, I'm passing unique_lock references into the methods as parameters as below. But this seems clunky, difficult to maintain, potentially disastrous, etc...
void modifyObject(std::unique_lock<std::mutex>& objectLock) { // We don't even know if this lock manages the right mutex... // so let's waste some time checking that. if(objectLock.mutex() != &mObjectMutex) throw std::logic_error(); // Lock mutex if not locked by this thread bool wasObjectLockOwned = objectLock.owns_lock(); if(!wasObjectLockOwned) objectLock.lock(); mObject.doSomeModification(); // restore previous lock state if(!wasObjectLockOwned) objectLock.unlock(); } Thanks!
try_to_locks? How can a thread lock a mutex and then forget about it?unique_lockon the stack, not passed in as a parameter. You must be doing something quite unorthodox if locking the same mutex twice is an actual risk in your design. Can you show exactly how this may happen for you?std::try_to_lockis the answer I was looking for? Can I just call that from every function that needs a lock instead of creating a localunique_lockor passing locks around?modifyObject(), and instead have only the functions that call it handle the access to the shared resource.