Youtube details
I have been browsing youtube to try and develop my understanding of C++ multithread support with mutex and condition variables.
I came across this video. Skip to time 6:30 to see what I am currently looking at. (A page of code.)
I believe there is a mistake in the code, but I wanted to check. It could just as well be that I don't understand something.
Question
The author states that std::unique_lock
locks the mutex on creation. Meaning that there is no need to call
unique_lock<mutex> lock(m)
lock.lock(); // this is wrong, because unique_lock already locked the mutex
after creating a unique_lock
object.
I assume although I do not know for certain, that unique_lock
will release the mutex lock on destruction. (Aka when it goes out of scope.)
Can it also be unlocked manually by calling
lock.unlock()
? From the documentation it appears there is no such unlock function. It looks like unique_lock
is therefore the same as scoped_lock
? But again, I'm assuming this isn't the case and there's some other information I am missing.
Continuing... The author has a function which looks like this:
void addMoney(int money)
{
std::lock_guard<mutex> lg(m); // lock_guard being used interchangably with unique_lock - why?
balance += money; // adding to global variable
cv.notify_one(); // error here
// the lock_guard is still in scope
// the mutex is still locked
// calling notify_one() may cause the sleeping thread to wake up
// check if the mutex is still locked (which it might be if the
// destructor for lg hasn't finished running)
// and then go back to sleep
// meaning this line of code may have no effect
// it is undefined behaviour
}
I have anotated where I believe there is an error. I think this function causes undefined behaviour, because the lock_guard
is still in scope, and therefore the mutex might be locked.
Effectively it is a race condition:
- If
addMoney()
ends before the other function begins, we are ok - If the other function
withdrawMoney()
checks the lock (cv.wait()
) beforeaddMoney()
exits then the program breaks, and remains in a locked state
For completeness here is the other function:
void withdrawMoney(int money)
{
std::unique_lock<mutex> ul(m); // unique_lock instead of scoped_lock? why?
cv.wait(ul, []{return balance != 0;});
// some more stuff omitted
}
Summary
There are a couple of points I have raised
- Most importantly the race condition
- Of secondary importance, why are two different things (
lock_guard
andunique_lock
) being used to do what appears to be the same thing (performing the same function)