c++multithreadingatomicdeadlock

Deadlock on condition variable Example


I am getting a deadlock I can't explain with the below code. I expected that the code should work because of the spurious wake-up but I think I am missing something. I checked this Condition variable deadlock but no luck.

class SafeQueue
{
private:
    std::queue<int> data_queue;
    mutable std::mutex m;
    std::condition_variable cv;
    std::atomic<bool> flag{ true }; // Atomic flag to control the queue

public:
    void push(int val)
    {
        std::lock_guard<std::mutex> lock(m);
        data_queue.push(val);
        cv.notify_one(); // Notify waiting thread upon pushing data
    }

    bool pop(int& val)
    {
        std::unique_lock<std::mutex> lock(m);
        cv.wait(lock, [this]() { return !data_queue.empty() || !flag; }); // Wait until queue is not empty or flag is turned off

        if (!flag && data_queue.empty())
        {
            return false; // Queue is empty and flag is off, return false to indicate termination
        }

        if (!data_queue.empty())
        {
            val = data_queue.front();
            data_queue.pop();
            return true;
        }
        return false;
    }

    void turnOff()
    {
        flag = false;
    }

    bool isFlagOn() const
    {
        return flag;
    }
};

void consumerLoop(SafeQueue& q)
{
    while (q.isFlagOn())
    {
        int val;
        if (q.pop(val))
        {
            std::cout << "Consumed: " << val << std::endl;
        }
    }
    std::cout << "Consumer exiting" << std::endl;
}

int main()
{
    SafeQueue q;
    std::thread consumerThread(consumerLoop, std::ref(q));

    // Producer pushes some values into the queue
    for (int i = 0; i < 10; ++i)
    {
        q.push(i);
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }

    // Turn off the queue flag
    q.turnOff();

    consumerThread.join();

    return 0;
}

Can you please help point out where it happens and how to correct the implementation? Any other suggestions for implementation are welcome (I need a deque I just included the example for queue for simplicity)


Solution

  • Your consumerThread is hanging on cv.wait and only waking up when push does a cv.notify_one(). This happens 10 times, then the producer loop is done and flag is turned off - however consumerThread is still/again hanging on cv.wait.

    At this point your consumerThread is stuck until either:

    A fairly simple solution in this case is to do this:

    void turnOff()
    {
        flag = false;
        cv.notify_one();
    }