Acquire a lock on two mutexes and avoid deadlock
Impose some kind of total order on instances of foo
and always acquire their locks in either increasing or decreasing order, e.g., foo1->lock()
and then foo2->lock()
.
Another approach is to use functional semantics and instead write a foo::clone
method that creates a new instance rather than clobbering an existing one.
If your code is doing lots of locking, you may need a complex deadlock-avoidance algorithm such as the banker's algorithm.
As @Mellester mentioned you can use std::lock
for locking multiple mutexes avoiding deadlock.
#include <mutex>
void foo::copy(const foo& rhs)
{
std::lock(pMutex, rhs.pMutex);
std::lock_guard<std::mutex> l1(pMutex, std::adopt_lock);
std::lock_guard<std::mutex> l2(rhs.pMutex, std::adopt_lock);
// do copy
}
But note to check that rhs
is not a *this
since in this case std::lock
will lead to UB due to locking same mutex.
How about this?
void foo::copy(const foo & rhs)
{
scopedLock lock(rhs.pMutex); // release mutex in destructor
foo tmp(rhs);
swap(tmp); // no throw swap locked internally
}
This is exception safe, and pretty thread safe as well. To be 100% thread save you'll need to review all code path and than re-review again with another set of eyes, after that review it again...