C++怎么实现生产者消费者模型

来源:PHP编程网作者:缓存小熊猫头衔:程序员
导读:本期聚焦于小伙伴创作的《C++怎么实现生产者消费者模型》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《C++怎么实现生产者消费者模型》有用,将其分享出去将是对创作者最好的鼓励。

生产者消费者模型是多线程编程中处理线程间数据交互的经典设计模式,核心是通过一个共享的缓冲区,让生产者线程向缓冲区写入数据,消费者线程从缓冲区读取数据,同时保证多线程操作下的数据安全和线程协作效率。在C++中实现该模型,需要借助标准库提供的多线程同步工具来完成。

C++怎么实现生产者消费者模型

核心同步工具介绍

实现生产者消费者模型需要用到三个核心的同步组件,分别是互斥锁、条件变量和共享队列,各自的作用如下:

  • 互斥锁(std::mutex):保证同一时间只有一个线程可以操作共享缓冲区,避免数据竞争问题。
  • 条件变量(std::condition_variable):用于线程间的等待和唤醒通知,当缓冲区满时生产者等待,缓冲区空时消费者等待,有空闲或有数据时对应线程被唤醒。
  • 共享队列(std::queue):作为生产者和消费者之间的数据缓冲区,存储生产者生成的数据供消费者读取。

完整实现代码示例

下面的代码实现了一个简单的生产者消费者模型,包含一个生产者线程和三个消费者线程,生产者每隔100毫秒生成一个随机整数放入队列,消费者从队列中取出数据并处理,当生产者生成10个数据后结束生产,所有消费者处理完剩余数据后退出。

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

// 共享队列,作为数据缓冲区
std::queue<int> data_queue;
// 互斥锁,保护共享队列的操作
std::mutex queue_mutex;
// 条件变量,用于生产者消费者之间的通知
std::condition_variable queue_cv;
// 标记生产者是否结束生产
bool producer_finished = false;
// 生产者需要生成的数据总量
const int TOTAL_DATA_COUNT = 10;

// 生产者线程函数
void producer() {
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<> dis(1, 100);
    for (int i = 0; i < TOTAL_DATA_COUNT; ++i) {
        // 模拟生产耗时
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
        int data = dis(gen);
        {
            // 加锁,操作共享队列
            std::lock_guard<std::mutex> lock(queue_mutex);
            data_queue.push(data);
            std::cout << "生产者生成数据: " << data << ", 当前队列大小: " << data_queue.size() << std::endl;
        }
        // 唤醒一个等待的消费者线程
        queue_cv.notify_one();
    }
    {
        // 生产结束,加锁修改标记
        std::lock_guard<std::mutex> lock(queue_mutex);
        producer_finished = true;
    }
    // 唤醒所有消费者线程,让它们检查生产结束标记
    queue_cv.notify_all();
    std::cout << "生产者结束生产" << std::endl;
}

// 消费者线程函数
void consumer(int consumer_id) {
    while (true) {
        std::unique_lock<std::mutex> lock(queue_mutex);
        // 等待条件:队列不为空 或者 生产者已经结束生产
        queue_cv.wait(lock, []() {
            return !data_queue.empty() || producer_finished;
        });
        // 如果队列为空且生产者已经结束,退出循环
        if (data_queue.empty() && producer_finished) {
            break;
        }
        // 从队列取出数据
        int data = data_queue.front();
        data_queue.pop();
        std::cout << "消费者" << consumer_id << "消费数据: " << data << ", 剩余队列大小: " << data_queue.size() << std::endl;
        // 解锁,让其他线程可以操作队列
        lock.unlock();
        // 模拟消费耗时
        std::this_thread::sleep_for(std::chrono::milliseconds(150));
    }
    std::cout << "消费者" << consumer_id << "退出" << std::endl;
}

int main() {
    // 创建生产者线程
    std::thread prod_thread(producer);
    // 创建三个消费者线程
    std::thread cons_threads[3];
    for (int i = 0; i < 3; ++i) {
        cons_threads[i] = std::thread(consumer, i + 1);
    }
    // 等待生产者线程结束
    prod_thread.join();
    // 等待所有消费者线程结束
    for (int i = 0; i < 3; ++i) {
        cons_threads[i].join();
    }
    std::cout << "所有线程执行完毕" << std::endl;
    return 0;
}

代码关键点解析

互斥锁的使用

代码中使用了std::lock_guardstd::unique_lock两种锁管理工具,std::lock_guard适合简单的加锁场景,在作用域结束时自动解锁;std::unique_lock更灵活,可以手动解锁,适合需要配合条件变量使用的场景,因为条件变量的wait函数需要接收一个std::unique_lock对象,并且会在等待时自动释放锁,被唤醒后重新加锁。

条件变量的等待逻辑

消费者线程的等待使用了带谓词的wait函数,即queue_cv.wait(lock, [](){ return !data_queue.empty() || producer_finished; });,这样可以避免虚假唤醒问题。虚假唤醒是指线程在没有收到明确通知的情况下被唤醒,使用谓词可以让线程被唤醒后再次检查条件是否满足,不满足则继续等待。

生产结束的处理

生产者生产完所有数据后,会修改producer_finished标记并调用notify_all唤醒所有等待的消费者,消费者被唤醒后会检查队列是否为空且生产已经结束,如果是则退出循环,避免消费者线程一直等待。

实际应用场景扩展

上述示例是最基础的生产者消费者模型实现,在实际项目中可以根据需求扩展,比如可以设置缓冲区的最大容量,当队列大小达到最大值时生产者等待,避免队列无限增长占用过多内存;也可以支持多个生产者线程,只需要保证生产者的操作同样受互斥锁保护即可;还可以给数据加上优先级,使用优先队列代替普通队列作为缓冲区。

C++多线程生产者消费者模型线程同步条件变量互斥锁修改时间:2026-07-03 01:21:28

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。