Reputation: 383
I've seen an example for a shared mutex:
class MyData {
std::vector<double> data_;
mutable shared_mutex mut_; // the mutex to protect data_;
public:
void write() {
unique_lock<shared_mutex> lk(mut_);
// ... write to data_ ...
}
void read() const {
shared_lock<shared_mutex> lk(mut_);
// ... read the data ...
}
};
Naturally I would have written instead:
public:
void write() {
mut_.lock();
// ... write to data_ ...
mut_.unlock();
}
void read() const {
mut_.lock_shared();
// ... read the data ...
mut_.unlock_shared();
}
};
Is my way also correct? And is there a difference between what I used and what was used in the example? Also, are there advantages of one over the other? Thank you!
Upvotes: 5
Views: 2395
Reputation: 24738
Is my way also correct?
Consider what would happen if the code between the locking of the mutex and the unlocking throws an exception:
void write() {
mut_.lock();
// <-- exception is thrown here
mut_.unlock();
}
The mutex then remains locked.
are there advantages of one over the other?
Yes, unique_lock<>
follows the RAII idiom, and therefore unlocking of the mutex is handled automatically (i.e., by its destructor) in case of an exception:
void write() {
unique_lock<shared_mutex> lk(mut_);
// <-- exception is thrown
}
In case of an exception after the creation of the unique_lock<shared_mutex>
object – lk
– its destructor is called, and it then unlocks the associated mutex if it was locked (remember that std::unique_lock
, unlike std::lock_guard
, doesn't always have ownership of the lock on the associated mutex – see std::defer_lock
and std::unique_lock::unlock()
).
To sum up, with lock_guard
/unique_lock
/shared_lock
, no special handling is required from your side in case of exceptions or when leaving the member function from different execution paths.
Upvotes: 12
Reputation: 17668
Raw mutex is generally avoided in favour of the RAII version unique_lock(), which is safer in two situations:
Like raw pointer are generally avoided in favour of RAII version smart pointers: unique_ptr or shared_ptr.
Either case, the RAII version ensure that the mutex (or pointer) is always released when the it goes out of scope.
Upvotes: 5