Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

difference between std::mutex and std::shared_mutex

I came across an std::shared_mutex in C++17. what exactly is std::shared_mutex and how it is different from std::mutex?

like image 301
asad_nitp Avatar asked Sep 27 '17 16:09

asad_nitp


People also ask

What is std :: Shared_mutex?

std::shared_mutex The shared_mutex class is a synchronization primitive that can be used to protect shared data from being simultaneously accessed by multiple threads.

What is the difference between unique_lock and Lock_guard?

A lock_guard always holds a lock from its construction to its destruction. A unique_lock can be created without immediately locking, can unlock at any point in its existence, and can transfer ownership of the lock from one instance to another.

What is shared lock in C++?

The class shared_lock is a general-purpose shared mutex ownership wrapper allowing deferred locking, timed locking and transfer of lock ownership. Locking a shared_lock locks the associated shared mutex in shared mode (to lock it in exclusive mode, std::unique_lock can be used)

Is std :: mutex recursive?

std::recursive_mutexA calling thread owns a recursive_mutex for a period of time that starts when it successfully calls either lock or try_lock . During this period, the thread may make additional calls to lock or try_lock . The period of ownership ends when the thread makes a matching number of calls to unlock .


2 Answers

As noted in the documentation

The shared_mutex class is a synchronization primitive that can be used to protect shared data from being simultaneously accessed by multiple threads. In contrast to other mutex types which facilitate exclusive access, a shared_mutex has two levels of access:

  • shared - several threads can share ownership of the same mutex.
  • exclusive - only one thread can own the mutex.

Shared mutexes are usually used in situations when multiple readers can access the same resource at the same time without causing data races, but only one writer can do so.

This has a variety of uses, but one common one is to implement a Read Write Lock where you could have multiple threads reading shared data, but only one thread exclusively writing at any time. So when you have multiple readers the mutex acts in "shared mode", but when a write is requested it changes into "exclusive mode".

like image 67
Cory Kramer Avatar answered Sep 21 '22 14:09

Cory Kramer


A mutex is either locked or not.

A shared_mutex is either locked exclusively, or locked shared, or not.

Any number of clients can shared lock a shared mutex.

If anyone has it exclusive locked, nobody else can hold any locks.

On windows, this is the SWRLOCK type -- and in fact, this lock is typically used to implement read-write locks; many readers allowed, but writing must be exclusive.

Here is some sample code to create two template wrappers for shared and non-shared mutexes. In one case, we have read and write operations that aquire different locks. In the other, we just have access:

template<class T, class M=std::mutex>
struct mutex_guarded {
  template<class F>
  auto access( F&& f ) {
    auto l = lock();
    return std::forward<F>(f)(t);
  }
  template<class F>
  auto access( F&& f ) const {
    auto l = lock();
    return std::forward<F>(f)(t);
  }
  mutex_guarded(mutex_guarded const&)=delete;
  mutex_guarded& operator=(mutex_guarded const&)=delete;
  template<class...Ts>
  mutex_guarded( Ts&&...ts ):t(std::forward<Ts>(ts)...){}
  mutex_guarded()=default;
protected:
  mutable M m;
  T t;
  auto lock() { return std::unique_lock<M>(m); }
};
template<class T, class M=std::shared_mutex>
struct shared_mutex_guarded:private mutex_guarded<T, M> {
  using base = mutex_guarded<T, M>;
  template<class F>
  auto read( F&& f ) const { return access(std::forward<F>(f)); }
  template<class F>
  auto write( F&& f ) { return access(std::forward<F>(f)); }

  using base::base;
protected:
  using base::access;
  template<class F>
  auto access( F&& f ) const {
    auto l = lock();
    return std::forward<F>(f)(this->t);
  }
  using base::lock;
  auto lock() const { return std::shared_lock<M>(this->m); }
};
like image 31
Yakk - Adam Nevraumont Avatar answered Sep 19 '22 14:09

Yakk - Adam Nevraumont