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_guardandunique_lock) being used to do what appears to be the same thing (performing the same function)
 
     
    