0

0

C++怎么实现生产者消费者_C++多线程同步模型【协作】

裘德小鎮的故事

裘德小鎮的故事

发布时间:2026-02-22 15:44:03

|

328人浏览过

|

来源于php中文网

原创

最简可靠模型是std::mutex配std::condition_variable:所有队列访问须加锁,等待必须用带谓词的wait/ wait_for,notify_one前更新状态,避免虚假唤醒和竞态。

c++怎么实现生产者消费者_c++多线程同步模型【协作】

std::mutex + std::condition_variable 实现最简可靠模型

别碰 std::semaphore(C++20 才有,且 Windows 上实现不稳),也别手写自旋锁。标准库里唯一推荐的组合就是 std::mutexstd::condition_variable —— 它天然支持“等待条件成立”,正好对应消费者等数据、生产者等空位的核心逻辑。

关键不是加锁,而是“等什么、什么时候醒”。消费者必须在队列非空时才取;生产者必须在队列未满时才塞。这两个判断不能脱离锁,否则存在竞态:比如检查完非空,还没来得及取,就被另一个线程取走了。

  • 始终用 std::unique_lock<:mutex></:mutex> 构造条件变量的等待,不能用 std::lock_guard
  • wait() 的谓词(lambda)必须是“真实条件”,不要写成 while (queue.empty()) wait() 这种裸循环,容易被虚假唤醒搞崩
  • 每次 notify_one() 前,确保共享状态已更新(比如 push 后再 notify),否则唤醒了也取不到东西

避免 std::queue 在多线程下崩溃的三个硬约束

std::queue 本身不是线程安全的 —— 它的 empty()front()pop() 全部需要外部同步。常见错误是只锁了 push(),却让消费者直接调 q.front(),结果段错误或读到垃圾值。

  • 所有对队列的访问(包括 empty()size()front()back()pop()push())必须包裹在同一把 std::mutex
  • 不要在锁外保存 front() 返回的引用或指针 —— 锁一释放,对象可能已被另一个线程 pop()
  • 如果要用 size() 判断容量,记得它和 empty() 一样只是快照,不能替代条件变量的谓词

为什么不用 notify_all() 而用 notify_one()

多数场景下,一个新元素只够喂一个消费者;一个空位也只够一个生产者填。用 notify_all() 会唤醒所有等待线程,它们抢锁、检查条件、发现不满足又回去睡 —— 白耗 CPU,还可能引发惊群效应(thundering herd)。

立即学习C++免费学习笔记(深入)”;

Gaga
Gaga

曹越团队开发的AI视频生成工具

下载

只有两种情况才考虑 notify_all()

  • 你明确知道多个线程必须同时响应同一个事件(比如全局 shutdown 信号)
  • 条件逻辑复杂,无法精确判断该唤醒谁(但这时更该重构逻辑,而不是滥用 notify_all

绝大多数生产者-消费者代码里,notify_one() 是默认且安全的选择。

带超时的等待怎么写才不丢数据

wait_for()wait_until() 时,返回值是 std::cv_status,不代表条件是否成立 —— 它只表示“是因为超时退出,还是因为被唤醒”。真正要判断的,还是谓词本身。

  • 错误写法:if (cv.wait_for(lk, 100ms) == std::cv_status::no_timeout) { /* 取数据 */ } —— 谓词可能仍为 false
  • 正确写法:始终用带谓词的 wait_for(lk, timeout, []{ return !queue.empty(); }),返回 true 才安全取
  • 超时后若继续循环,注意重置超时时间(比如用 steady_clock::now() + 100ms),别让累积误差导致等待越来越短

边界情况最容易出问题:比如消费者超时醒来,发现队列仍空,但此时生产者正卡在锁里准备 push —— 这就是为什么谓词检查必须和等待原子绑定,不能拆开。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
if什么意思
if什么意思

if的意思是“如果”的条件。它是一个用于引导条件语句的关键词,用于根据特定条件的真假情况来执行不同的代码块。本专题提供if什么意思的相关文章,供大家免费阅读。

826

2023.08.22

while的用法
while的用法

while的用法是“while 条件: 代码块”,条件是一个表达式,当条件为真时,执行代码块,然后再次判断条件是否为真,如果为真则继续执行代码块,直到条件为假为止。本专题为大家提供while相关的文章、下载、课程内容,供大家免费下载体验。

103

2023.09.25

lambda表达式
lambda表达式

Lambda表达式是一种匿名函数的简洁表示方式,它可以在需要函数作为参数的地方使用,并提供了一种更简洁、更灵活的编码方式,其语法为“lambda 参数列表: 表达式”,参数列表是函数的参数,可以包含一个或多个参数,用逗号分隔,表达式是函数的执行体,用于定义函数的具体操作。本专题为大家提供lambda表达式相关的文章、下载、课程内容,供大家免费下载体验。

212

2023.09.15

python lambda函数
python lambda函数

本专题整合了python lambda函数用法详解,阅读专题下面的文章了解更多详细内容。

192

2025.11.08

Python lambda详解
Python lambda详解

本专题整合了Python lambda函数相关教程,阅读下面的文章了解更多详细内容。

60

2026.01.05

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

695

2023.08.10

Python 多线程与异步编程实战
Python 多线程与异步编程实战

本专题系统讲解 Python 多线程与异步编程的核心概念与实战技巧,包括 threading 模块基础、线程同步机制、GIL 原理、asyncio 异步任务管理、协程与事件循环、任务调度与异常处理。通过实战示例,帮助学习者掌握 如何构建高性能、多任务并发的 Python 应用。

370

2025.12.24

java多线程相关教程合集
java多线程相关教程合集

本专题整合了java多线程相关教程,阅读专题下面的文章了解更多详细内容。

26

2026.01.21

pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法
pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法

本专题系统整理pixiv网页版官网入口及登录访问方式,涵盖官网登录页面直达路径、在线阅读入口及快速进入方法说明,帮助用户高效找到pixiv官方网站,实现便捷、安全的网页端浏览与账号登录体验。

1030

2026.02.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C# 教程
C# 教程

共94课时 | 10万人学习

C 教程
C 教程

共75课时 | 4.9万人学习

C++教程
C++教程

共115课时 | 18.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号