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

Viewed 491

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?

2 Answers

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.

Related