Simple question - basically, do I have to unlock a mutex, or can I simply use the scope operators and the mutex will unlock automatically?
ie:
{
pthread_mutex_lock (&myMutex);
sharedResource++;
} // my mutex is now unlocked?
or should I:
{
pthread_mutex_lock (&myMutex);
sharedResource++;
pthread_mutex_unlock (&myMutex);
}
The mutex does not become unlocked until the owner has called pthread_mutex_unlock() for each successful lock request that it has outstanding on the mutex. An errorcheck mutex checks for deadlock conditions that occur when a thread relocks an already held mutex.
Mutexes are used to protect shared resources. If the mutex is already locked by another thread, the thread waits for the mutex to become available. The thread that has locked a mutex becomes its current owner and remains the owner until the same thread has unlocked it.
The std::scoped_lock and std::unique_lock objects automate some aspects of locking, because they are capable of automatically unlocking.
Using std::mutex takes about 74 machine cycles, while using a native Win32 CRITICAL_SECTION takes about 53 machine cycles. So unless 100 machine cycles is a significant amount of time compared to the code itself, the mutexes aren't going to be the source of a performance problem.
The mutex is not going out of scope in your examples; and there is no way for the compiler to know that a particular function needs calling at the end of the scope, so the first example does not unlock the mutex.
If you are using (error-prone) functions to lock and unlock the mutex, then you will need to ensure that you always call unlock()
- even if the protected operation throws an exception.
The best way to do this is to use a RAII class to manage the lock, as you would for any other resource that needs releasing after use:
class lock_guard {
public:
explicit lock_guard(mutex & m) : m(m) {mutex_lock(m);}
~lock_guard() {mutex_unlock(m);}
lock_guard(lock_guard const &) = delete;
void operator=(lock_guard &) = delete;
private:
mutex & m;
};
// Usage
{
lock_guard lock(myMutex);
shared_resource++;
} // mutex is unlocked here (even if an exception was thrown)
In modern C++, use std::lock_guard
or std::unique_lock
for this.
Using the RAII scope method is much better because it guarantees that the mutex will always be unlocked even in the face of exceptions or early return.
If you have access to C++11 though you might consider using a std::atomic<int>
instead in which case you don't need to lock it to increment.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With