c++如何使用condition_variable实现生产者消费者模型_c++线程同步

使用std::condition_variable实现生产者消费者模型,需结合互斥锁保护共享缓冲区,通过条件变量在缓冲区满或空时阻塞线程,并在状态变化时通知等待线程。

在C++中使用std::condition_variable实现生产者消费者模型,是一种典型的线程同步问题。核心目标是让生产者线程在缓冲区满时等待,消费者线程在缓冲区空时等待,通过条件变量和互斥锁配合完成安全的资源访问与通知机制。

基本组件准备

要实现该模型,需要以下几个关键元素:

  • std::mutex:保护共享缓冲区,防止数据竞争。
  • std::condition_variable:用于线程间通信,通知对方状态变化。
  • std::queue 或其他容器:作为共享任务缓冲区。
  • 生产者线程函数:向队列添加数据,并通知消费者。
  • 消费者线程函数:从队列取出数据,若为空则等待。

代码实现示例

下面是一个使用固定大小缓冲区的简单实现:

#include 
#include 
#include 
#include 
#include 
#include 

std::queue buffer;
std::mutex mtx;
std::condition_variable cv;
const int MAX_SIZE = 5;

void producer(int id) {
    for (int i = 0; i < 10; ++i) {
        std::unique_lock lock(mtx);
        cv.wait(lock, [](){ return buffer.size() < MAX_SIZE; });

        buffer.push(i);
        std::cout << "Producer " << id << " produced: " << i << "\n";

        lock.unlock();
        cv.notify_all(); // 通知所有等待的消费者
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
}

void consumer(int id) {
    for (int i = 0; i < 10; ++i) {
        std::unique_lock lock(mtx);
        cv.wait(lock, [](){ return !buffer.empty(); });

        int value = buffer.front();
        buffer.pop();
        std::cout << "Consumer " << id << " consumed: " << value << "\n";

        lock.unlock();
        cv.notify_all(); // 通知生产者可以继续生产
        std::this_thread::sleep_for(std::chrono::milliseconds(150));
    }
}

主函数启动多个生产者和消费者线程:

int main() {
    std::thread p1(producer, 1);
    std::thread p2(producer, 2);
    std::thread c1(consumer, 1);
    std::thread c2(consumer, 2);

    p1.join();
    p2.join();
    c1.join();
    c2.join();

    return 0;
}

关键点说明

使用condition_variable时需要注意以下几点:

  • 必须配合unique_lock使用wait()notify_one()notify_all()都要求传入std::unique_lock<:mutex>
  • 使用lambda判断条件:避免虚假唤醒,将条件判断写在wait()的第二个参数中。
  • 及时通知对方:每次修改共享状态后调用notify_all()notify_one(),确保等待线程能被唤醒。
  • 注意notify的位置:可以在持有锁时调用,也可以释放锁后调用,但需保证逻辑正确。

基本上就这些。只要掌握好互斥锁保护数据、条件变量等待事件、及时通知这三个核心环节,就能写出稳定的生产者消费者模型。