单生产者双消费者带最大缓冲区限制的最优控制实现咨询
双消费者同取全量图像的多线程缓冲区实现方案
核心逻辑调整如下:
- 缓冲区存储单元新增
processed_count整型字段,记录当前图像已被消费者读取的次数,初始值为0,仅当计数达到2时才将该图像从缓冲区移除、释放空位 - 生产者每成功放入一张图像,调用两次
sem_post(&waitPush),确保两个消费者都能收到新图像通知 - 消费逻辑仅在两个消费者都读取完同一张图像后,才执行一次
sem_post(&waitPop)释放缓冲区空位,严格保证缓冲区大小不会超过预设上限
修改后可运行代码
sem_init(&waitPop, 0, bufferLimitSize); // 控制缓冲区最大容量 sem_init(&waitPush, 0, 0); // 通知消费者有新图像可用 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // 缓冲区元素结构,原逻辑仅存image,新增消费计数 struct BufferItem { Image image; int processed_count; }; std::deque<BufferItem> buffer; bool thereAreImages = true; void *producer(){ while(thereAreImages){ Image image = loadimage(); sem_wait(&waitPop); pthread_mutex_lock(&mutex); // 原冗余判断可删除,sem_wait(&waitPop)已保证缓冲区存在空位 buffer.push_front({image, 0}); pthread_mutex_unlock(&mutex); // 关键改动:两个消费者都需要收到通知,所以post两次 sem_post(&waitPush); sem_post(&waitPush); } // 生产结束后额外post两次,唤醒可能阻塞的消费者退出 sem_post(&waitPush); sem_post(&waitPush); return NULL; } void *consumer(){ while(true){ sem_wait(&waitPush); pthread_mutex_lock(&mutex); // 生产已结束且缓冲区无剩余图像,直接退出 if (!thereAreImages && buffer.empty()) { pthread_mutex_unlock(&mutex); break; } BufferItem& item = buffer.back(); Image image = item.image.clone(); item.processed_count += 1; // 两个消费者都读取完当前图像,弹出并释放空位 if (item.processed_count == 2) { buffer.pop_back(); pthread_mutex_unlock(&mutex); sem_post(&waitPop); } else { pthread_mutex_unlock(&mutex); } doImageProcessing(image); } return NULL; }
方案说明
- 资源开销极低:仅新增每个缓冲区元素的1个整型计数,复用原有的1个互斥锁和2个信号量,无额外开销
- 缓冲区大小严格受控:只有一张图像被两个消费者都处理完毕后才会释放空位,不会出现缓冲区溢出问题
- 兼容消费者速度差异:消费速度慢的一方不会影响快的一方,图像会保存在缓冲区直到慢的消费者读取完成,不会丢图
- 无空访问风险:信号量计数和缓冲区操作完全由互斥锁保护,不会出现消费者读取空缓冲区的情况
内容的提问来源于stack exchange,提问作者Roc
相关产品推荐
相关产品推荐

