Is `std::shared_mutex` virtually a superset of `std::mutex`?

127 views Asked by At

std::shared_mutex can provide an exclusive lock like std::mutex. Plus it extends the synchronization capabilities by allowing the parallel read-only accesses to the multiple threads.

Under the hood the number of machine instructions might be lesser for std::mutex. But at a practical level, while reading about their usage I feel that std::shared_mutex can potentially supersede or even deprecate std::mutex.

In other words, is there any place where std::mutex has to be used over std::shared_mutex?

2

There are 2 answers

0
Akhilesh Pandey On BEST ANSWER

Yesstd::shared_mutex is a powerful synchronization primitive that can be used to implement both read/write locks and exclusive locks which makes it more flexible than std::mutex in many ways.there are still several scenarios where std::mutex would be preferable over std::shared_mutex.

  • Performance: std::mutex is often simpler and thus faster than std::shared_mutex. A std::shared_mutex typically requires more overhead to manage shared access rights. If you don't need the ability to allow multiple simultaneous readers, the simpler std::mutex will often be faster.

  • Memory: std::shared_mutex can consume more memory than std::mutex due to the extra data needed to manage multiple reader threads.

  • Concurrency Scenario: If the lock is mostly used for writing rather than reading, a simple std::mutex could be preferable since the use case does not really benefit from the std::shared_mutex functionality.

  • Complexity: std::shared_mutex comes with more operations (lock, try_lock, unlock, lock_shared, try_lock_shared, unlock_shared) which could add unnecessary complexity to the code if only mutual exclusion is required.

So, std::shared_mutex can offer benefits in terms of allowing multiple readers, if your primary use case is simply to provide exclusive access to a resource std::mutex could still be a simpler and more efficient choice.

2
Nicol Bolas On

std::vector is a functional superset of std::array. Anything an array can do, a vector can do as well.

But that's not a good excuse to avoid using array when it is obviously appropriate (ie: statically sized, no need for heap allocation, etc).

Likewise, shared_mutex could be used in any place that mutex could. But that doesn't mean you should.

The types you use communicates something to the people who read your code. If you use shared_ptr, you are communicating to users that ownership of this object is being shared. That's what the name means. Using shared_ptr when you only use it for unique ownership of a resource says either that you expect to share it in the future or you don't know what you're doing.

Using shared_mutex communicates that users are expected to acquire shared locks to this mutex. This says something about the access patterns of code trying to access the guarded data. It means that the data will be read concurrently by a lot of code, but will only occasionally need exclusive access by some restricted subset of code.

And as with shared_ptr, using it in cases where this does not happen is a miscommunication of what is going on in your code.

And that ignores the performance implications. shared_mutex and its locks aren't free, after all. Any "practical level" should not throw performance away.