Search code examples
c++multithreadingconcurrencymutexcondition-variable

If a thread that is blocked on a std::condition_variable is notified, but the lock on the associated mutex has not been released what would be result?


Is it clear what would happen if a thread blocked on a std::condition_variable receives a notification but the lock on the associated mutex is not yet released, and the lock will be released 10 seconds later? Would the thread wait for the lock to be released or is the situation undefined? I added a 15seconds sleep on purpose to make the lock unavailable during that time to see how waiting thread will be doing. It is doing OK but just wanted to be sure about it.

#include <iostream>
#include <condition_variable>
#include <thread>
#include <chrono>

struct SharedResource
{
    SharedResource() :
        cv_mutex(), cv(), counter(0)
    {

    }

    /*
    This mutex is used for three purposes:
    1) to synchronize accesses to counter
    2) to synchronize accesses to std::cerr
    3) for the condition variable cv
    */
    std::mutex cv_mutex;
    std::condition_variable cv;
    int counter;
};

void waits(SharedResource& sharedRes)
{
    std::unique_lock<std::mutex> lk(sharedRes.cv_mutex);
    std::cerr << "Waiting... \n";
    while (sharedRes.counter != 1) 
    {
        sharedRes.cv.wait_for(lk,3s);
        std::cerr << "Thread ID: " << std::this_thread::get_id() << " wakes up every 3 seconds.\n";
    }
    std::cerr << "...finished waiting." << "counter: " << sharedRes.counter << std::endl;
} //The lk object will be unlocked after this scope ends.

void signals(SharedResource& sharedRes)
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
    {
        std::lock_guard<std::mutex> lk(sharedRes.cv_mutex);
        std::cerr << "Notifying...\n";
    } // The lk object will be unlocked after this scope ends.
    sharedRes.cv.notify_all();

    std::this_thread::sleep_for(std::chrono::seconds(6));

    {
        std::lock_guard<std::mutex> lk(sharedRes.cv_mutex);
        sharedRes.counter = 1;
        std::cerr << "Notifying again...\n";
    
    sharedRes.cv.notify_all();
    std::this_thread::sleep_for(std::chrono::seconds(15));

    }// The lk object will be unlocked after this scope ends.
}

int main()
{
    SharedResource sharedRes;

    std::thread
        t1(waits, std::ref(sharedRes)),
        t2(signals, std::ref(sharedRes));
    t1.join();
    t2.join();
}

Solution

  • If a thread that is blocked on a std::condition_variable is notified, but the lock on the associated mutex has not been released what would be result?

    It will continue to wait / wait_for until it can reacquire the lock.

    When std::condition_variable::wait and wait_for returns (for whatever reason), the lock is held again, so you don't have to worry about that.

    It can even return from wait without having gotten any notifications (spurious wake-ups) - but, no matter what, the lock is reacquired when the call returns.