da cheng
da cheng

Reputation: 3

program went into dead lock using condition variable in c++11

I am currently trying to learn how to use a condition_variable for thread synchronization. For testing, I have made the demo application shown below. When I start it, it runs into a dead lock. I know the location where this happens, but I'm unable to understand why the deadlock occurs.

I know that a condition_variable's wait function will automatically unlock the mutex when the condition is not true, so the main thread should not be blocked in the second pass. But it is just this what happens.

Could anybody explain why?

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

bool flag = false;
std::mutex g_mutex;
std::condition_variable cv;


void threadProc()
{
    std::unique_lock<std::mutex> lck(g_mutex);

    while (true)
    {
        static int count = 0;

        std::cout << "wait for flag" << ++count << std::endl;

        cv.wait(lck, []() {return flag; }); // !!!It will blocked at the second round

        std::cout << "flag is true " << count << std::endl;

        flag = false;
        lck.unlock();
    }

}

int main(int argc, char *argv[])
{
    std::thread t(threadProc);

    while (true)
    {
        static int count = 0;

        {
            std::lock_guard<std::mutex> guard(g_mutex); // !!!It will blocked at the second round

            flag = true;
            std::cout << "set flag " << ++count << std::endl;
        }

        cv.notify_one();

        std::this_thread::sleep_for(std::chrono::seconds(1));
    }


    t.join();

    return 0;
}

Upvotes: 0

Views: 126

Answers (2)

Solomon Slow
Solomon Slow

Reputation: 27115

I know that a condition_variable's wait function will automatically unlock the mutex when the condition is not true.

Um..., yes..., Just to be absolutely clear, cv.wait(lck, f) does this:

while(! f()) {
    cv.wait(lck);
}

And each call to cv.wait(lck) will;

  • unlock lck,
  • wait until some other thread calls cv.notify_one() or cv.notify_all(),
  • re-lock lck, and then
  • return.

Upvotes: 2

Leo
Leo

Reputation: 48

You can fix the problem by moving the unique_lock(...) statement inside the while loop. As it is now, you're attempting to unlock lck on round 2 but it was not in a locked state, since, after round 1 you never locked it again.

Upvotes: 1

Related Questions