C++版本的生产者消费者模型

本文记录了C++版的生产者消费者模型,通过一个阻塞队列,缓解生产者和消费者之间的直接依赖,提高多线程效率。文中详细介绍了实现逻辑,包括使用C++11的线程库、互斥锁、条件变量、队列和原子操作,并讨论了多线程同步和调试中的问题。同时,给出了代码实现和测试函数。
摘要由CSDN通过智能技术生成

C++版生产者消费者模型

字节跳动三面提到的手写代码,当时没能写出来。这几天补了一下,在此记录一下。
生产者消费者模型本身主要是利用一个缓冲区来存储数据,从而减弱生产者和消费者之间的直接关系,提高多线程下程序效率。

代码

https://github.com/Huang-Jin/ProducerConsumerDemo

参考资料

  • https://blog.csdn.net/lvxin15353715790/article/details/89143121
  • http://www.cplusplus.com/reference/condition_variable/condition_variable/
  • CSAPP,12.5.4。

工具

  • 实现的语言是C++.
    • C++11提供的thread库
    • 互斥锁mutex
    • 条件变量condition_variable
    • 队列queue
    • 原子操作atomic
    • Windows临界区
  • 开发环境是Visual Studio 2013。

实现细节

  • 具体的实现逻辑是构建一个queue来存储生产的数据,queue不满时可以生产,不空时可以消费。
  • 对于这个队列,采用阻塞队列的实现思路。
  • 先实现构造函数,初始化一个unique_lock供condition_variable使用。
    • 如何在类里面使用unique_lock等需要初始化,并且初始化会加锁的对象。这要研究下。我的理解是构造列表初始化,然后函数体里unlock。
    • 对于条件变量,申请两个,分别控制consumer和producer。
  • 然后就是入和出队列的细节。
    • 首先加锁。
    • 循环判断一下目前的队列情况,对于各自的特殊情况(队满和队空)进行处理。
    • 唤醒一个线程来处理特殊情况。
    • 等待处理完毕。
    • 处理入和出队列操作。
    • 最后释放锁。
  • 对于输出cout可能因为多线程紊乱的问题,加入了临界区。不过据说因为cout缓存问题,还是可能出错,没试验出来。

问题

  1. 对于多线程很多细节不是很理解。
  2. 如何判断多线程同步是成功的。如何调试bug。
  3. BUG:在多个consumer线程的情况下,会出现有些线程无法退出的情况。
    • 在析构函数里
      • 加入stop,并且唤醒因条件变量阻塞的线程。
    • 在pop函数中,
      • 加入对stop的判断,当队列为空并且stop时,退出pop函数。
      • 对consumer的条件变量wait调用加入pred,队列为空或者没有停止时阻塞。
  4. 之前对条件变量的wait函数理解不够深入,这次学习了一下。
    • 单参数版本,此时传入一个unique_lock类型的变量,并且已经加锁。调用wait之后释放锁,并阻塞等待notify唤醒。唤醒后加锁。要注意的是被唤醒后有可能加锁失败,此时继续阻塞。
    • 双参数版本,此时需要再加入一个Predicate类型的变量,应该是一个返回bool的函数。我一般用lamda表达式代替。返回false阻塞,true解除。要注意这里的意思是即使notify了,如果后面的条件不满足,也不会解除阻塞。
    • 对于pred不知道性能会有多大影响。
  5. 初步完成了多consumer的代码编写以及测试。
  6. 对于多consumer的消息同步暂时没做,是在外部程序完成调用的stop。

主要代码

阻塞队列

void CBlockQueue::push(const int & data) {
   
	unique_lock<mutex> _lck(_mt);
	while (full()) {
   
		_cv_con.notify_one();
		_cv_prod.wait(_lck)
生产者消费者模型是一种并发编程模型,用于解决生产者和消费者之间的数据交换问题。在这个模型中,生产者负责生产数据,消费者负责消费数据。 模型的实现通常涉及到共享资源(如队列)和同步机制(如锁、条件变量)。生产者和消费者通过共享的队列进行通信。当队列为空时,消费者将等待,直到有数据可供消费。当队列满时,生产者将等待,直到有空间可供生产。 在你提供的引用中,生产者线程和消费者线程使用了互斥锁和条件变量来实现同步。当消费者线程获取锁后,如果队列为空,则会进入等待状态,并释放锁。此时生产者线程可以获取锁,并判断队列是否为空,如果为空,则进入等待状态并释放锁。当生产者线程生产了产品后,会通过条件变量通知消费者线程可以消费了。消费者线程收到通知后,需要获取锁才能进行消费。 总结一下生产者消费者模型的步骤: 1. 定义共享队列作为生产者和消费者之间的数据交换通道。 2. 定义互斥锁,确保同时只有一个线程能够访问共享资源(即队列)。 3. 定义条件变量,用于线程间的通信。 4. 生产者线程获取互斥锁,判断队列是否已满,如果满则等待,否则生产数据并将其放入队列。 5. 如果消费者线程获取互斥锁,判断队列是否为空,如果为空则等待,否则消费数据并从队列中移除。 6. 在适当的时候,使用条件变量通知等待中的线程继续执行。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值