user2260241 user2260241 - 23 days ago 6
C++ Question

notify_all does not wake up wait thread

DBThread::DBThread() : running_(false)
{

}

DBThread::~DBThread()
{
if (thread_)
{
thread_->join();
}
}

void DBThread::Init()
{
thread_ = std::make_shared<std::thread>(std::bind(&DBThread::Run, this));
std::unique_lock<std::mutex> lock(mutex_);
cv_.wait(lock, [&] {return running_; });
std::cout << "Init success";
}

void DBThread::AddTask(std::shared_ptr<Delegate> task)
{
std::lock_guard<std::mutex> lock(mutex_);
task_queue_.push(task);
}

void DBThread::Run()
{
running_ = true;
cv_.notify_all();
while (true)
{
std::unique_lock<std::mutex> lock(mutex_);
cv_.wait(lock, [&] {return !task_queue_.empty(); });
std::cout << "run task" << std::endl;
}
}


I have two threads,let's name it A and B,A call Init and wait for B to fully initialized, A sometimes hang on wait even if running_ is true.Any idea why this happens.Any help will be appreciated.

Answer

std::condition_variable::wait(lock, pred) is basically the same as

while (!pred()) {
    wait(lock);
}

If the thread sets running_ to true and calls notify_all() between the time that the predicate is checked, but before wait is called, then the notification will be lost, and the wait will wait until another notification comes. Easiest way to fix it is:

void DBThread::Run()
{
    std::unique_lock<std::mutex> lock(mutex_);
    running_ = true;
    cv_.notify_all();
    while (true)
    {
        cv_.wait(lock, [&] {return !task_queue_.empty(); });
        std::cout << "run task" << std::endl;
    }
}