Can scoped_lock lock a shared_mutex in read mode? - c++

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).

Related

How to lock multiple locks where some are shared and some are not in C++

Let's suppose I have some threadsafe class. It uses a std::shared_mutex for protection against concurrent access. Read only operations use a std::shared_lock, while write operations use std::scoped_lock.
Now, in the case of the copy assignment operator both the assignee's and the object's being assigned mutexes must be locked, except that the assignee gets modified and must have its mutex locked with std::shared_lock while the object being assign is read-only and must be locked using std::scoped_lock. As far as I know, locking multiple mutexes without using a specific lock ordering algorithm, like this, could cause a deadlock.
Normally a deadlock could be circumvented by using std::lock or std::scoped_lock, but in this case, they cannot be used, as one of the std::shared_mutexes must not be locked, but lock_shareded.
How can multiple locks be locked avoiding a deadlock, where some of them are shared and some are not?
In very same way you should be using function std::lock for multiple mutexes.
Let me give you an example:
std::mutex m;
std::shared_mutex sm;
std::unique_lock ul(m,std::defer_lock);
std::shared_lock sl(sm,std::defer_lock);
std::lock(ul,sl);
Function std::lock simply applies try_lock()/unlock() until it succedes on all input lockables whereas shared_lock's methods lock/try_lock impose shared locking (for reading).
Just fix your design so this doesn't happen. The issues with deadlock and difficulty of code maintenance are going to be intolerable with a design like this.
For example, maybe copy the source object to a temporary, unlock it, and then copy the temporary to the destination object. Or, alternatively, have a single lock that protects all the objects and architect so you don't hold it very long.

Why we keep mutex instead of declaring it before guard every time?

Please consider this classical approach, I have simplified it to highlight the exact question:
#include <iostream>
#include <mutex>
using namespace std;
class Test
{
public:
void modify()
{
std::lock_guard<std::mutex> guard(m_);
// modify data
}
private:
/// some private data
std::mutex m_;
};
This is the classical approach of using std::mutex to avoid data races.
The question is why are we keeping an extra std::mutex in our class? Why can't we declare it every time before the declaration of std::lock_guard like this?
void modify()
{
std::mutex m_;
std::lock_guard<std::mutex> guard(m_);
// modify data
}
Lets say two threads are calling modify in parallel. So each thread gets its own, new mutex. So the guard has no effect as each guard is locking a different mutex. The resource you are trying to protect from race-conditions will be exposed.
The misunderstanding comes from what the mutex is and what the lock_guard is good for.
A mutex is an object that is shared among different threads, and each thread can lock and release the mutex. That's how synchronization among different threads works. So you can work with m_.lock() and m_.unlock() as well, yet you have to be very careful that all code paths (including exceptional exits) in your function actually unlocks the mutex.
To avoid the pitfall of missing unlocks, a lock_guard is a wrapper object which locks the mutex at wrapper object creation and unlocks it at wrapper object destruction. Since the wrapper object is an object with automatic storage duration, you will never miss an unlock - that's why.
A local mutex does not make sense, as it would be local and not a shared ressource. A local lock_guard perfectly makes sense, as the autmoatic storage duration prevents missing locks / unlocks.
Hope it helps.
This all depends on the context of what you want to prevent from being executed in parallel.
A mutex will work when multiple threads try to access the same mutex object. So when 2 threads try to access and acquire the lock of a mutex object, only one of them will succeed.
Now in your second example, if two threads call modify(), each thread will have its own instance of that mutex, so nothing will stop them from running that function in parallel as if there's no mutex.
So to answer your question: It depends on the context. The mission of the design is to ensure that all threads that should not be executed in parallel will hit the same mutex object at the critical part.
Synchronization of threads involves checking if there is another thread executing the critical section. A mutex is the objects that holds the state for us to check if it was "locked" by a thread. lock_guard on the other hand is a wrapper that locks the mutex on initialization and unlocks it during destruction.
Having realized that, it should be clearer why there has to be only one instance of the mutex that all lock_guards need access to - they need to check if it's clear to enter the critical section against the same object. In the second snippet of your question each function call creates a separate mutex that is seen and accessible only in its local context.
You need a mutex at class level. Otherwise, each thread has a mutex for itself, and therefore the mutex has no effect.
If for some reason you don't want your mutex to be stored in a class attribute, you could use a static mutex as shown below.
void modify()
{
static std::mutex myMutex;
std::lock_guard<std::mutex> guard(myMutex);
// modify data
}
Note that here there is only 1 mutex for all the class instances. If the mutex is stored in an attribute, you would have one mutex per class instance. Depending on your needs, you might prefer one solution or the other.

Difference between mutex.timed_lock(duration) and boost::timed_mutex::scoped_lock scoped_lock(mutex, duration)

I would like to know which is the difference between:
boost::timed_mutex _mutex;
if(_mutex.timed_lock(boost::get_system_time() + boost::posix_time::milliseconds(10))){
exclusive code
_mutex.unlock();
}
and
boost::timed_mutex _mutex;
boost::timed_mutex::scoped_lock scoped_lock(_mutex, boost::get_system_time() + boost::posix_time::milliseconds(10));
if(scoped_lock.owns_lock()) {
exclusive code
}
I do know already that the scoped_lock makes unnecessary the call to unlock. My question refers to:
Why in the first case we call timed_lock as member function of a
mutex and in the second one we construct a lock from a mutex and a
duration.
Which one is more efficient?
The usage of boost::posix_time is okay or is recommended to use another kind,
e.g. chrono or duration?
There's a better way (faster) to try to
acquire a lock for 'x' time than the two methods above specified?
I'll try to answer your questions:
as you can read in this Document, locks are used as RAII devices for the locked state of a mutex. That is, the locks don't own the mutexes they reference. They just own the lock on the mutex. basically what it means is that you acquire the mutex lock when you initialize it's corresponding lock and release it when the lock object is destroyed.
that's why in the second example you didn't have to call timed_lock from the mutex, the scoped_lock does it for you when initialized.
I don't know if the first example is more efficient but I know for sure that the second example (the RAII scoped_lock) is much safer, it guarantees that you won't forget to unlock the mutex and ,more important, it guarantees that other people that use and modify your code won't cause any mutex related problems.
as far as I know you can't construct scoped_lock (which is basicallyunique_lock<timed_mutex>) from posix_time. I personally prefer duration.
In my opinion constructing the lock with Duration absolute time is your best option.

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

Locking multiple mutexes

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.