不能直接用 std::queue 做无锁生产者消费者,因其 push/pop/size 非原子且 std::atomic 不支持非平凡类型;需用 2 的幂容量循环缓冲区,配原子下标与位掩码实现线性安全。
std::queue 做无锁生产者消费者因为 std::queue 的所有操作(push、pop、size)都不是原子的,内部有内存分配、指针更新、状态判断等多步操作。即使你把 std::queue 包在 std::atomic 里,也毫无意义——std::atomic 不支持非平凡类型(non-trivial type),编译直接报错:error: use of deleted function 'std::atomic<:queue>>::atomic()'。
真正的无锁(lock-free)要求:所有线程对共享数据的读写,仅通过原子操作(如 load、store、compare_exchange_weak)完成,且不依赖互斥量或条件变量。
std::atomic m_produce_idx 和 std::atomic m_consume_idx
核心思想:把下标看作无限递增的序列号,但只取低 N 位作为实际数组索引;用高位隐含“版本”或“绕圈次数”,从而区分“满”和“空”状态(避免单独用标志位或牺牲一个槽位)。
假设缓冲区长度 CAPACITY = 1024,则掩码 MASK = CAPACITY - 1(即 0x3FF)。所有索引访问统一用 idx & MASK。
关键约束:
(m_consume_idx.load(std::memory_order_acquire) + CAPACITY) > m_produce_idx.load(std::memory_order_acquire) 时写入(即“未满”)m_consume_idx.load(std::memory_order_acquire) 时读取(即“非空”)
store(..., std::memory_order_release) 更新下标;消费者读下标前用 load(std::memory_order_acquire)
class LockFreeRingBuffer {
static constexpr size_t CAPACITY = 1024;
static constexpr size_t MASK = CAPACITY - 1;
std::array m_buffer;
std::atomic m_produce_idx{0};
std::atomic m_consume_idx{0};
public:
bool try_push(int val) {
auto current_prod = m_produce_idx.load(std::memory_order_acquire);
auto current_cons = m_consume_idx.load(std::memory_order_acquire);
if (current_prod - current_cons >= CAPACITY) return false; // 已满
m_buffer[current_prod & MASK] = val;
m_produce_idx.store(current_prod + 1, std::memory_order_release);
return true;
}
bool try_pop(int& out) {
auto current_cons = m_consume_idx.load(std::memory_order_acquire);
auto current_prod = m_produce_idx.load(std::memory_ord
er_acquire);
if (current_cons >= current_prod) return false; // 为空
out = m_buffer[current_cons & MASK];
m_consume_idx.store(current_cons + 1, std::memory_order_release);
return true;
}};
std::memory_order 选错会导致什么现象
最常见错误是全用 std::memory_order_relaxed:编译器和 CPU 可能重排指令,导致消费者读到“新下标、旧数据”或“旧下标、新数据”,结果就是读到未初始化值、重复读、甚至崩溃。
正确配对逻辑:
- 生产者:写数据 →
store(新下标, release):确保数据写入对其他线程可见
- 消费者:
load(下标, acquire) → 读数据:确保后续读数据一定看到之前被 release 写入的内容
- 不能用
acquire 去读生产者下标后,再用 relaxed 去读消费者下标——这会破坏同步关系
-
compare_exchange_weak 场景(如 CAS 更新下标)必须明确指定 success/fail memory order,通常 success 用 acq_rel,fail 用 relaxed
如果你在调试中发现偶发读到 0 或随机大数,大概率是 memory order 失配,而不是逻辑错误。
性能陷阱:缓存行伪共享(false sharing)怎么破
m_produce_idx 和 m_consume_idx 如果在内存中挨得太近(比如同属一个 64 字节缓存行),多核并发读写会触发缓存一致性协议频繁同步,性能断崖式下降——实测吞吐可能比加锁还差。
解决方法只有两个字:隔离。
- 用
alignas(64) 强制每个原子变量独占缓存行
- 或者在它们之间插入填充字段(
char pad[64]),但不如 alignas 清晰可靠
- 别忘了
m_buffer 本身也要对齐(尤其当它很大时),否则首尾元素也可能跨缓存行争抢
一个没对齐的无锁队列,跑得越快,伪共享越严重——这不是理论风险,是真实压测中反复验证过的瓶颈点。
# 字节
# ai
# c++
# nas
# 解决方法
# 无锁
# 为什么
# Error
# char
# 循环
# 指针
# 线程
# 并发
# function
# 掩码
# 读到
# 不支持
# 多核
# 也要
# 只能在
# 你在
# 这不是
# 更快
# 你把
相关文章:
如何在西部数码注册域名并快速搭建网站?
网站视频怎么制作,哪个网站可以免费收看好莱坞经典大片?
为什么Go需要go mod文件_Go go mod文件作用说明
建站VPS选购需注意哪些关键参数?
建站之星免费版是否永久可用?
如何在Ubuntu系统下快速搭建WordPress个人网站?
外贸公司网站制作哪家好,maersk船公司官网?
高防服务器租用指南:配置选择与快速部署攻略
如何通过万网虚拟主机快速搭建网站?
高端建站三要素:定制模板、企业官网与响应式设计优化
建站VPS推荐:2025年高性能服务器配置指南
网站插件制作软件免费下载,网页视频怎么下到本地插件?
,巨量百应是干嘛的?
建站主机助手选型指南:2025年热门推荐与高效部署技巧
早安海报制作网站推荐大全,企业早安海报怎么每天更换?
如何通过西部建站助手安装IIS服务器?
如何通过虚拟机搭建网站?详细步骤解析
制作销售网站教学视频,销售网站有哪些?
如何选择服务器才能高效搭建专属网站?
建站主机与服务器功能差异如何区分?
韩国网站服务器搭建指南:VPS选购、域名解析与DNS配置推荐
制作充值网站的软件,做人力招聘为什么要自己交端口钱?
免费公司网站制作软件,如何申请免费主页空间做自己的网站?
SQL查询语句优化的实用方法总结
c++ stringstream用法详解_c++字符串与数字转换利器
韩国代理服务器如何选?解析IP设置技巧与跨境访问优化指南
深圳网站制作培训,深圳哪些招聘网站比较好?
怎么制作网站设计模板图片,有电商商品详情页面的免费模板素材网站推荐吗?
如何高效生成建站之星成品网站源码?
山东云建站价格为何差异显著?
Avalonia如何实现跨窗口通信 Avalonia窗口间数据传递
如何使用Golang安装API文档生成工具_快速生成接口文档
微课制作网站有哪些,微课网怎么进?
简单实现Android验证码
如何获取PHP WAP自助建站系统源码?
购物网站制作费用多少,开办网上购物网站,需要办理哪些手续?
如何通过主机屋免费建站教程十分钟搭建网站?
香港服务器租用费用高吗?如何避免常见误区?
代购小票制作网站有哪些,购物小票的简要说明?
,想在网上投简历,哪几个网站比较好?
如何在自有机房高效搭建专业网站?
西安市网站制作公司,哪个相亲网站比较好?西安比较好的相亲网站?
如何构建满足综合性能需求的优质建站方案?
宝塔建站无法访问?如何排查配置与端口问题?
专业型网站制作公司有哪些,我设计专业的,谁给推荐几个设计师兼职类的网站?
广州网站制作公司哪家好一点,广州欧莱雅百库网络科技有限公司官网?
沈阳个人网站制作公司,哪个网站能考到沈阳事业编招聘的信息?
如何快速完成中国万网建站详细流程?
电影网站制作价格表,那些提供免费电影的网站,他们是怎么盈利的?
建站ABC备案流程中有哪些关键注意事项?
*请认真填写需求信息,我们会在24小时内与您取得联系。