c++ should condition variable be notified under lo

2019-04-25 07:15发布

问题:

I found the following example for condition variable on www.cppreference.com, http://en.cppreference.com/w/cpp/thread/condition_variable. The call to cv.notify_one() is placed outside the lock. My question is if the call should be made while holding the lock to guarantee that waiting threads are in fact in waiting state and will receive the notify signal.

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

std::mutex m;
std::condition_variable cv;
std::string data;
bool ready = false;
bool processed = false;

void worker_thread()
{
    // Wait until main() sends data
    std::unique_lock<std::mutex> lk(m);
    cv.wait(lk, []{return ready;});

    // after the wait, we own the lock.
    std::cout << "Worker thread is processing data\n";
    data += " after processing";

    // Send data back to main()
    processed = true;
    std::cout << "Worker thread signals data processing completed\n";

    // Manual unlocking is done before notifying, to avoid waking up
    // the waiting thread only to block again (see notify_one for details)
    lk.unlock();
    cv.notify_one();
}

int main()
{
    std::thread worker(worker_thread);

    data = "Example data";
    // send data to the worker thread
    {
        std::lock_guard<std::mutex> lk(m);
        ready = true;
        std::cout << "main() signals data ready for processing\n";
    }
    cv.notify_one();

    // wait for the worker
    {
        std::unique_lock<std::mutex> lk(m);
        cv.wait(lk, []{return processed;});
    }
    std::cout << "Back in main(), data = " << data << '\n';

    worker.join();
}

Should the notify_one() call be moved inside the lock to guarantee waiting threads receive the notify signal,

// send data to the worker thread
{
    std::lock_guard<std::mutex> lk(m);
    ready = true;
    cv.notify_one();
    std::cout << "main() signals data ready for processing\n";
}

回答1:

You do not need to notify under lock. However, since notify is logically happening when the actual value is changed (otherwise, why would you notify?) and that change must happen under lock, it is often done within the lock.

There would be no practical observable difference.



回答2:

if I understand your question correctly, it's equivilant to "should the notifier thread lock the mutex while trying to notify some CV in other thread"

no, it is not mandatory and even does some counter-effect.
when condition_variable is notified from another thread it tries to-relock the mutex on which it was put to sleep. locking that mutex from other thread will block the other other thread which trying to lock it , untill the that lock-wrapper gets out of scope.

PS
if you do remove the locking from the function that send data to the worker threads, ready and processed should at least be atomics. currently they are synchronized by the lock , but when you remove the lock they cease to be thread-safe



回答3:

If you do not wait on a condition variable then the notification is lost. It does not matter if you are holding any locks. A condition variable is a synchronization primitive and do not need a lock for protection.

You can miss signals with and without lock. The mutex protects only normal data like ready or processed.