Bebe Carabina
Bebe Carabina

Reputation: 161

C++ Producer-Consumer with condition variable

Looking to synchronize two threads with a condition variable and created a simple example to practice.

Think I have messed something up when doing the synchronization, because consumer hangs on waiting on a signal from cv.

Even though there is cv.notify_one(), somehow the line return counter != 0 inside the lambda is never triggered and I completely fail to understand why.

#include <iostream>
#include <mutex>
#include <thread>
#include <chrono>
using namespace std::chrono_literals;

int main(int, char**)
{
    std::mutex mx;
    std::condition_variable cv;
    int counter;

    std::thread producer( [ & ] ( )
    {
        while( true )
        {
            std::lock_guard<std::mutex> lock( mx );

            std::cout << "adding task" << std::endl;
            std::this_thread::sleep_for(1s);
            ++counter;

            cv.notify_one();
        }
    });

    std::thread consumer( [ & ] ( )
    {
        while( true )
        {
            std::unique_lock<std::mutex> lock( mx );

            cv.wait( lock, [ & ] ( )
            {
                return counter > 0;
            });

            std::cout << "Executing" << std::endl;
            std::this_thread::sleep_for(.5s);
            --counter;
        }
    });

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

    return 0;
}

Upvotes: 1

Views: 2049

Answers (1)

elbrunovsky
elbrunovsky

Reputation: 440

The problem is clearly fairness, as demonstrated by adding a line like

std::this_thread::sleep_for(0.01s);

just before the producer acquires the mutex.

Most operating systems will not give you any fairness guarantees on mutexes.

There are many ways of working around the issue of fairness. If you know how to handle this, you can stop here.

In your case, assuming your producers and consumers don't actually take half a second or more to put or take a job into the queue, and that the producer doesn't actually have an infinite amount of jobs, then you don't need to worry about this at all. If the operating system favours producers over consumers in a moment of high contention, the queue simply fills up (or all pending jobs eventually get put into the queue), forcing producers to wait, release the mutex, and allow consumers to take their turn.

Note that in a producer/consumer scenario with a maximum queue size you actually need two condition variables - for full and empty conditions.

Upvotes: 2

Related Questions