robert
robert

Reputation: 3726

why lock_guard can get an already locked mutex by unique_lock? - still questions

I am studying this example. I have found this question and thought that I will get an answer, but I still have a question.

I post the the code here for convenience:

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::cout << "------------------------\n";
    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();

    return 0;
}

Should not the statement std::unique_lock<std::mutex> lk(m); block the main thread because mutex m is locked by worker_thread? If yes, isn't the statement cv.wait(lk, []{return processed;}); after it unnecessary in this example? When main thread can lock the mutex, processed will be already true.

Upvotes: 1

Views: 1786

Answers (2)

Alan Stokes
Alan Stokes

Reputation: 18964

The call to wait unlocks the mutex for the duration of the wait. See http://en.cppreference.com/w/cpp/thread/condition_variable/wait.

EDIT: Which is explicitly stated in the answer to the question you linked to: https://stackoverflow.com/a/32030975/212870

EDIT 2: It is not true that "When main thread can lock the mutex, processed will already be true". The worker thread may not even have started yet, or if it has it may not have seen that ready is set.

Upvotes: 1

Hrant
Hrant

Reputation: 506

Line cv.wait(lk, []{return ready;}); does the following if ready is false:

  1. Unlocks the mutex lk

  2. Blocks the thread waiting for notification

  3. When notification arrives, unblocks the thread and locks the mutex lk

So the main thread does not block on std::lock_guard<std::mutex> lk(m); as the mutex is unlocked by worker thread.

Upvotes: 0

Related Questions