Zeeshan Hayat
Zeeshan Hayat

Reputation: 431

C++ - std::condition_variable notified by different threads

I am trying to notify an event from two different threads. Main thread wakes up on first notify_one() call but not on the second one. Is this the right way to use condition variable?

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

bool is_ready_1(false);
bool is_ready_2(false);
std::mutex m;
std::condition_variable cv;

void test1()
{
    std::this_thread::sleep_for(std::chrono::seconds(3));
    std::unique_lock<std::mutex> lk(m);
    is_ready_1 = true;
    cv.notify_one();
}
void test2()
{
    std::this_thread::sleep_for(std::chrono::seconds(6));
    std::unique_lock<std::mutex> lk(m);
    is_ready_2 = true;
    cv.notify_one();
}

int main()
{
    std::thread t1(test1);
    std::thread t2(test2);

    std::unique_lock<std::mutex> lk(m);
    while (!is_ready_1)
    {
        cv.wait(lk);
        if (is_ready_1)
            std::cout << "Spurious wake-1 up!\n";
    }

    while (!is_ready_2)
    {
         cv.wait(lk);
         if (is_ready_2)
         std::cout << "Spurious wake-2 up!\n";
    }
    t1.join(); 
    t2.join();
    system("pause");
}

Upvotes: 2

Views: 1106

Answers (1)

Mikhail
Mikhail

Reputation: 8028

Try this code. Note that a condition variable accepts a predicate that first checks if the the condition is met, and then takes the lock. When you notify the variable, it runs the predicate (without taking the lock), if the condition is true, the thread will own the lock else the calling thread will keep waiting for the next notification.

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

auto is_ready_1=false;
auto is_ready_2=false;
std::mutex m;
std::condition_variable cv;

void test1()
{
    std::this_thread::sleep_for(std::chrono::seconds(3));
    std::unique_lock<std::mutex> lk(m);
    is_ready_1 = true;
    cv.notify_one();
}
void test2()
{
    std::this_thread::sleep_for(std::chrono::seconds(6));
    std::unique_lock<std::mutex> lk(m);
    is_ready_2 = true;
    cv.notify_one();
}

int main()
{
    std::thread t1(test1);
    std::thread t2(test2);

    std::unique_lock<std::mutex> lk(m);
    cv.wait(lk, [] {
        if (!is_ready_1)
        {
            std::cout << "Spurious 1" << std::endl;
        }
        return is_ready_1;
    });
    //preceding line must clear before this is executed
    cv.wait(lk, [] {
        if (!is_ready_2)
        {
            std::cout << "Spurious 1" << std::endl;
        }
        return is_ready_2;
    });

    t1.join();
    t2.join();
    system("pause");
}

Also on Windows 10, I see two spurious wakeup events, I suspect these happen when the thread is woken up from sleep.

Upvotes: 1

Related Questions