生产者-消费者中的竞争条件:将通知限制在条件变量等待时

Race condition in Producer-Consumer: limit notifications to when condition variable is waiting

我实现了一个简单的生产者-消费者消息队列。

#include <chrono>
#include <iostream>
#include <thread>
#include <mutex>
#include <deque>


#define MESSAGE_QUIT 1


struct MessageQueue
{
    std::deque<int> message_ids;
    std::mutex mutex;
    std::condition_variable condition_variable;
};


void SleepFor(int time_in_millis)
{
    std::this_thread::sleep_for(std::chrono::milliseconds(time_in_millis));
}


void ProcessMessage(int message_id)
{
    std::cout << "Processing Message #" << message_id << '\n';
}


void Producer(MessageQueue *messages)
{
    for (int message_id = 10; message_id >= MESSAGE_QUIT; --message_id) {
        std::unique_lock<std::mutex> guard(messages->mutex);    
        messages->message_ids.push_back(message_id);            
        guard.unlock();
        messages->condition_variable.notify_one();
        SleepFor(200);
    }
}


void Consumer(MessageQueue *messages)
{
    int next_message_id = -1;

    while (next_message_id != MESSAGE_QUIT) {
        std::unique_lock<std::mutex> guard(messages->mutex);
        messages->condition_variable.wait(guard);
        next_message_id = messages->message_ids.front();
        messages->message_ids.pop_front();
        guard.unlock();
        ProcessMessage(next_message_id);
    }
}


int main()
{
    MessageQueue messages;

    std::thread producer_thread(&Producer, &messages);
    std::thread consumer_thread(&Consumer, &messages);

    producer_thread.join();
    consumer_thread.join();
}

竞争条件:在某些情况下,条件变量在生产者线程中调用notify_one(),而在消费者线程中不处于等待状态。你会如何解决这个问题?我暂时不考虑虚假唤醒的情况。

条件变量可以虚假唤醒。

messages->condition_variable.wait(guard)

所以不要这样做。还有其他不这样做的原因,包括您可以在数据准备就绪时等待条件变量。

messages->condition_variable.wait(guard, [&]{return !messages->message_ids().empty();)

如果队列中已有消息,则不会等待。它还处理虚假唤醒。