Locking multiple mutexes - c++

I'm wondering if it's possible to lock multiple mutexes at the same time, like:
Mutex1.Lock();
{
Mutex2.Lock();
{
// Code locked by mutex 1 and 2.
}
Mutex2.Unlock();
// Code locked by mutex 1.
}
Mutex1.Unlock();
It would be very useful for some situations. Thanks.

std::lock seems to exist for this purpose.
Locks the given Lockable objects lock1, lock2, ..., lockn using a deadlock avoidance algorithm to avoid deadlock.
The objects are locked by an unspecified series of calls to lock, try_lock, unlock. If a call to lock or unlock results in an exception, unlock is called for any locked objects before rethrowing.
http://en.cppreference.com/w/cpp/thread/lock

C++17 also provides scoped_lock for the specific purpose of locking multiple mutexes that prevents deadlock in a RAII style, similar to lock_guard.
#include<mutex>
std::mutex mtx1, mtx2;
void foo()
{
std::scoped_lock lck{mtx1, mtx2};
// proceed
}

It is possible but the order of locking must be consistent throughout the application otherwise deadlock is a likely result (if two threads acquire the locks in opposite order then each thread could be waiting on the other to release one of the locks).
Recommend using a scoped lock and unlock facility for exception safety, to ensure locks are always released (std::lock_guard with std::mutex for example):
std::mutex mtx1;
std::mutex mtx2;
std::lock_guard<std::mutex> mtx1_lock(mtx1);
{
std::lock_guard<std::mutex> mtx2_lock(mtx2);
{
}
}
If your compiler does not support these C++11 features boost has similar in boost::mutex and boost::lock_guard.

Related

Can scoped_lock lock a shared_mutex in read mode?

C++17 introduced both std::shared_mutex and std::scoped_lock. My problem is now, that it seems, that scoped_lock will lock a shared mutex always in exclusive (writer) mode, when it is passed as an argument, and not in shared (reader) mode. In my app, I need to update an object dst with data from an object src. I want to lock src shared and dst exclusive. Unfortunately, this has the potential for deadlock, if a call to another update method with src and dst switched occurs at the same time. So I would like to use the fancy deadlock avoidance mechanisms of std::scoped_lock.
I could use scoped_lock to lock both src and dst in exclusive mode, but that unnecessarily strict lock has performance backdraws elsewhere. However, it seems, that it is possible to wrap src's shared_mutex into a std::shared_lock and use that with the scoped_lock: When the scoped_lock during its locking action calls try_lock() on the shared_lock, the later will actually call try_shared_lock() on src's shared_mutex, and that's what I need.
So my code looks as simple as this:
struct data {
mutable std::shared_mutex mutex;
// actual data follows
};
void update(const data& src, data& dst)
{
std::shared_lock slock(src.mutex, std::defer_lock);
std::scoped_lock lockall(slock, dst.mutex);
// now can safely update dst with src???
}
Is it safe to use a (shared) lock guard like this inside another (deadlock avoidance) lock guard?
As pointed out by various commentators, who have read the implementation code of the C++ standard library: Yes, the use of a std::shared_mutex wrapped inside a std::shared_lock() as one of the arguments to std::scoped_lock() is safe.
Basically, a std::shared_lock forwards all calls to lock() to lock_shared() on the mutex.
std::shared_lock::lock -----------> mutex()->lock_shared(). // same for try_lock etc..
Another possible solution
std::shared_lock lk1(src.mutex, std::defer_lock);
std::unique_lock lk2(dst.mutex, std::defer_lock);
std::lock(lk1, lk2);
std::lock is a function that accepts any number of Lockable objects and locks all of them (or aborts with an exception, in which case they will all be unlocked).
std::scoped_lock according to cppreference is a wrapper for std::lock, with the added functionaliy of calling unlock() on each Lockable object in its destructor. That added functionality is not required here, as std::shared_lock lk1 and std::unique_lock lk2 also work as lock guards, that unlock their mutexes, when they go out of scope.
Edit: various clarifications
Mutex: Add thread safety to shared resources
Lock: Add RAII (and possibly extra functionality) to mutex
Different locks let you lock the mutex in different ways:
unique_lock: exclusive access to resource (for write)
shared_lock: shared access to resource (for simultaneous reads)
scoped_lock: same as unique_lock, but with less features
scoped_lock is a bare bone exclusive lock that is locked when constructed and unlocked when destroyed. unique_lock and shared_lock are exclusive and shared locks respectively that are also locked and unlocked with their default constructor and destructor. However, they also provide extra functionality. For example, you can try to luck them, or you can unlock them before they are destroyed.
So a typical use case would be to use a shared_lock for shared access (when multiple threads read the same resource), and use a unique_lock or a scoped_lock for exclusive access (depending on if you need the extra features of unique_lock or not).

How to properly solve the producer consumer in C++11

I'm trying to solve the producer consumer problem in C++11.
I have an object which holds resources, and multiple threads can
add or consume those resources. My problem is when I try to implement
a "consume when available" method on that object.
Please assume that insert/remove operations are of trivial complexity.
A little explanation of the logic in code.
struct ResourceManager{
std::mutex mux;
std::unique_lock lock{mux};
std::condition_variable bell;
void addResource(/*some Resource*/){
lock.lock();
//add resource
lock.unlock();
bell.notify_one(); //notifies waiting consumer threads to consume
}
T getResource(){
while(true){
lock.lock();
if(/*resource is available*/){
//remove resource from the object
lock.unlock();
return resource;
}else{
//new unique lock mutex object wmux creation
lock.unlock(); //problem line
bell.wait(wmux); //waits until addResource rings the bell
continue;
}
}
}
};
Suppose the following scenario:
-Two threads, T1, T2, call addResource, getResource almost simultaneously.
-T2 locks the mutex, and finds out there are no more resources available,
so it has to block until a new resource is available.
So it unlocks the mutex and sets up the bell waiting.
-T1 runs match faster. When the mutex is unlocked,
it immediately adds the resource, and before T2 sets up the waiting bell,
T1 has already rang the bell, which notifies no one.
-T2 indefinitely waits for the bell to ring, but no further resources are added.
I'm making the assumption that a thread locking a mutex, may be the only one
to unlock it. So if I tried calling bell.wait before unlocking the mutex,
the mutex could never be unlocked.
I'd like to use no time-waiting or multiple times checking solution if possible.
So which way could I solve this problem in C++11?
lock.unlock(); //problem line
bell.wait(wmux); //waits until addResource rings the bell
Yes, this is the problem line, indeed.
To correctly use a condition variable as designed, you do not unlock a mutex before wait()ing on its related condition variable. wait()ing on a condition variable atomically unlocks it for the duration of the wait, and reacquires the mutex once the thread has been notify()-ed. Both the unlock-and-wait, and wake-up-after-being-notified-and-lock, are atomic operations.
Allnotify()s should be issued while the mutex is locked. All wait() are also done while the mutex is fully locked. Given that notify(), as I mentioned, is atomic, this results in all mutex-related operations being atomic and fully sequenced, including managing the resources protected by the mutex, and thread notification via condition variables, which is now protected by a mutex as well.
There are design patterns that can be implemented that notify condition variables without using mutex protection. But they're much harder to implement correctly and still achieve thread-safe semantics. Having all condition variable operations also protected by the mutex, in addition to everything else that the mutex protects, is much simpler to implement.
std::condition_variable::wait needs to be passed a locked std::unique_lock on your mutex. wait will unlock the mutex as part of its operation, and will re-lock it before it returns.
The normal way to use lock guards like std::lock_guard and std::unique_lock is to construct them locally and let their constructor lock your mutex and their destructor unlock it.
Also, you can avoid the external while loop in your original code by providing a predicate to std::condition_variable::wait.
struct ResourceManager {
std::mutex mux;
std::condition_variable bell;
void addResource(T resource)
{
std::lock_guard<std::mutex> lock{mux};
// Add the resource
bell.notify_one();
}
T getResource()
{
std::unique_lock<std::mutex> lock{mux};
bell.wait(lock, [this](){ return resourceIsAvailable(); });
return // the ressource
}
};

Several mutexes locking in c++

In many places there is a suggestion to use std::defer_lock:
{
std::unique_lock<std::mutex> lk1(mutex1, std::defer_lock);
std::unique_lock<std::mutex> lk2(mutex2, std::defer_lock);
std::lock(lk1, lk2);
//Do some stuff
}
But what if I won't use std::defer_lock, and try to do simply that:
{
std::unique_lock<std::mutex> lk1(mutex1);
std::unique_lock<std::mutex> lk2(mutex2);
//Do some stuff
}
As far as I know, this code will lock mutex1, and then lock mutex2. Unlocking will be performed in the reverse order - mutex2, and then mutex1. There is no reason to deadlock.
Documentation says, that std::lock(lk1, lk2); in the first example would lock buth mutexes simultaneously. So, is this some sort of optimization?
The deadlock issue is a problem of the order of locking several mutexes. This might be apparent in easy applications, but very difficult in more (or too?) complex situations where the mutexes may not always be locked at the same function and they are usually not called lk1, lk2,... so by locking simultaneously, you don't create a situation where two threads wait on locked mutex, hence being unable to unlock the mutex they locked.
You might want to avoid mixing mutexes, but that can lead to other tricky situations. However when possible, it is best to let threads work on independent state and let 1 controlling thread accumulate the result.

boost equivalent to windows mutex

In boost land on Mac OS, following code will deadlock itself:
boost::mutex m;
m.lock();
m.lock();
the same goes with
boost::mutex m;
boost::mutex::scoped_lock lock(m);
boost::mutex::scoped_lock lock(m);
in Windows land, the same thread can get a Win32 mutex as often as it wants, as long as the release count is the same. I need the exact behavior with a boost sync object.
What you need is a boost::recursive_mutex:
The recursive_mutex class uses a Recursive locking strategy, so attempts to recursively lock a recursive_mutex object succeed and an internal "lock count" is maintained. Attempts to unlock a recursive_mutex object by threads that don't own a lock on it result in undefined behavior.
Note that the boost::mutex:
The mutex class uses an Unspecified locking strategy, so attempts to recursively lock a mutex object or attempts to unlock one by threads that don't own a lock on it result in undefined behavior. This strategy allows implementations to be as efficient as possible on any given platform.
In Computer Science the recursive mutex is called Reentrant Mutex:
In computer science, a reentrant mutex is a mutual exclusion, recursive lock mechanism. In a reentrant mutex, the same thread can acquire the lock multiple times. However, the lock must be released the same number of times or else other threads will be unable to acquire the lock
try to use a recursive mutex : As boost::mutex is not recursive, we need to use its recursive version boost::recursive_mutex

How can implement a recursive lock using boost, that spans multiple methods?

I have a class that opens transactions, adds operations to a queue, then closes the transaction. Across the open->close lifetime I would like to employ a recursive mutex, so that only one thread can have a transaction open at any time. All other threads are blocked until the current transaction is ended.
class MyObject
{
void beginTransaction()
{
// acquire mutex
}
void endTransaction()
{
// release mutex
}
boost::recursive_mutex m_mutex;
}
I am having difficulty determining how I can use a recursive_mutex in this case, as the lock would exist longer than the scope of a single method. Can anyone suggest how I might apply locking here?
Boost (and the standard library) provide mutexes, which can be locked and unlocked, and locks, which lock mutexes in their constructor and unlocks them in their destructor. Locks are really just lightweight wrappers that are used to ensure a lock is released when leaving scope.
In your case, you would just use the mutex directly, without wrapping it in a lock.
You can call m_mutex.lock() in beginTransaction to lock the mutex, then m_mutex.unlock() in endTransaction to unlock the mutex. If another thread attempts to call m_mutex.lock() between calls, it will block until the mutex is unlocked by the owning thread in endTransaction