Reputation: 132
I've came across with this sample of code provided by a book. Btw this book has bad reviews. I regret that I bought it
std::mutex m_mutex;
mutable std::unique_lock<std::mutex> m_finishedQueryLock{ m_mutex, std::defer_lock };
bool m_playerQuit{ false };
void SetPlayerQuit()
{
m_finishedQueryLock.lock();
m_playerQuit = true;
m_finishedQueryLock.unlock();
}
I'm not satisfied with the book's explanation of how it works and why should I use it. I already have an idea of how mutex locks work and the implementations of it, but I have a difficulty understanding the second line of the code above. And why does it have a mutable keyword in it?
I'm completely new on C++ Programming. So a basic level of explanation would help me a lot.
Upvotes: 3
Views: 2298
Reputation: 409
All answers explain very well why the example is not good. I will answer when you would want to use a std::unique_lock
instead of a std::lock_guard
.
When a thread is waiting on something, one may use a std::condition_variable
. A condition variable makes use of deferred locking and therefore uses a unique_lock
, which allows deferred locking. I don't think you explicitly need to say you need deferred locking, as in the example.
To grasp these concepts, you first need to learn what RAII is. Then have a look at this reference. An example of the condition variables can be found here.
Upvotes: 0
Reputation: 171303
That example looks totally stupid.
The second line is declaring a non-static data member, and
mutable
(for reasons given below);std::unique_lock<std::mutex>
, which is a helper type for locking/unlocking an associated mutex object;m_mutex
and the special tag std::defer_lock
as arguments.But doing that is stupid, and I'm not surprised the book has bad reviews if it has examples like that.
The point of unique_lock
is to lock the associated mutex, and then to automatically unlock it when it goes out of scope. Creating a unique_lock
member like this is stupid, because it doesn't go out of scope at the end of the function, so the code has absolutely no advantage over:
mutable std::mutex m_mutex;
bool m_playerQuit{ false };
void SetPlayerQuit()
{
m_mutex.lock();
m_playerQuit = true;
m_mutex.unlock();
}
But this manual unlocking has all the problems that unique_lock
was designed to solve, so it should be using a scoped lock (either unique_lock
or lock_guard
) but only in the function scope, not as a member:
mutable std::mutex m_mutex;
bool m_playerQuit{ false };
void SetPlayerQuit()
{
std::lock_guard<std::mutex> lock(m_mutex);
m_playerQuit = true;
} // m_mutex is automatically unlocked by the ~lock_guard destructor
The mutable
keyword is necessary so that you can lock the mutex in const
member functions. Locking and unlocking a mutex is a non-const operation that modifies the mutex, which would not be allowed in a const
member if it wasn't mutable.
Upvotes: 8
Reputation: 14392
The unique_lock
is a RAII system. When created, taking the mutex
as parameter, it will lock the mutex and when leaving the scope it is destroyed, thus unlocking the mutex. When you need to unlock earlier, you can call the unlock()
function like in your example.
Using the unique_lock
like in your example doesn't create added value over using the mutex directly.
Upvotes: 1