Using Condition Variables

suggest change

A condition variable is a primitive used in conjunction with a mutex to orchestrate communication between threads. While it is neither the exclusive or most efficient way to accomplish this, it can be among the simplest to those familiar with the pattern.

One waits on a std::condition_variable with a std::unique_lock<std::mutex>. This allows the code to safely examine shared state before deciding whether or not to proceed with acquisition.

Below is a producer-consumer sketch that uses std::thread, std::condition_variable, std::mutex, and a few others to make things interesting.

#include <condition_variable>
#include <cstddef>
#include <iostream>
#include <mutex>
#include <queue>
#include <random>
#include <thread>

int main()
{
    std::condition_variable cond;
    std::mutex mtx;
    std::queue<int> intq;
    bool stopped = false;
std::thread producer{[&]()
{
    // Prepare a random number generator.
    // Our producer will simply push random numbers to intq.
    //
    std::default_random_engine gen{};
    std::uniform_int_distribution<int> dist{};

    std::size_t count = 4006;    
    while(count--)
    {    
        // Always lock before changing
        // state guarded by a mutex and
        // condition_variable (a.k.a. "condvar").
        std::lock_guard<std::mutex> L{mtx};

        // Push a random int into the queue
        intq.push(dist(gen));

        // Tell the consumer it has an int
        cond.notify_one();
    }

    // All done.
    // Acquire the lock, set the stopped flag,
    // then inform the consumer.
    std::lock_guard<std::mutex> L{mtx};

    std::cout << "Producer is done!" << std::endl;

    stopped = true;
    cond.notify_one();
}};

std::thread consumer{[&]()
{
    do{
        std::unique_lock<std::mutex> L{mtx};
        cond.wait(L,[&]()
        {
            // Acquire the lock only if
            // we've stopped or the queue
            // isn't empty
            return stopped || ! intq.empty();
        });

        // We own the mutex here; pop the queue
        // until it empties out.

        while( ! intq.empty())
        {
            const auto val = intq.front();
            intq.pop();

            std::cout << "Consumer popped: " << val << std::endl;
        }

        if(stopped){
            // producer has signaled a stop
            std::cout << "Consumer is done!" << std::endl;
            break;
        }

    }while(true);
}};

consumer.join();
producer.join();

std::cout << "Example Completed!" << std::endl;

return 0;
}

Feedback about page:

Feedback:
Optional: your email if you want me to get back to you:


Threading:
* Using Condition Variables

Table Of Contents
8 Arrays
11 Loops
39 Streams
51 Unions
56 Lambdas
57 Threading
60 SFINAE
62 RAII
67 Sorting
84 RTTI
87 Scopes
104 Profiling
107 Recursion
117 Iteration
125 Alignment
134 Semaphore
136 Debugging
139 Mutexes
142 decltype