c++如何实现一个高性能的环形队列(Ring Buffer)_c++无锁实现方法【并发】
技术百科
冰火之心
发布时间:2026-01-01
浏览: 次 高性能环形队列需无锁设计+原子操作+内存序控制:SPSC模式仅用relaxed内存序的原子索引,MPMC需CAS与acquire/release配对;须防伪共享、禁存非平凡类型,并优先选用成熟库。
用 C++ 实现高性能环形队列,核心在于**无锁(lock-free)设计 + 原子操作 + 内存序控制**。它适用于高并发生产/消费场景(如日志缓冲、网络收发包、实时数据流),避免互斥锁带来的线程阻塞和上下文切换开销。
一、基础结构:单生产者单消费者(SPSC)最简单且高效
这是唯一能真正“免原子操作”的无锁模式——生产者只改 write_index,消费者只改 read_index,两者互不干扰。只需用 std::atomic 保证读写可见性,内存序用 memory_order_relaxed 即可(因为无竞争)。
- 用
std::array或new T[N]分配连续内存,N 必须是 2 的幂(方便位运算取模) - 索引用
size_t,通过index & (N-1)替代% N,避免除法开销 - 两个原子索引:
std::atomicm_read{0}, m_write{0} - 判空:
read == write;判满:(write + 1) & mask == read(预留一个空位避免歧义)
二、多生产者多消费者(MPMC):必须用原子操作 + 内存序协调
多个线程可能同时修改同一索引,必须用 CAS(compare-and-swap)+ 合理内存序。常用策略是「先占位再填值」:
- 生产者:用
fetch_add争抢写位置 → 得到 slot → 写入元素 → 最后用store更新 write_index(memory_order_release) - 消费者:类似,先
fetch_add读位置 → 读取 → 最后更新 read_index(memory_order_release) - 关键点:读写操作本身需
用 memory_order_acquire/memory_order_release配对,确保元素写入对消费者可见 - 注意 ABA 问题?在 SPSC 中不存在;MPMC 中若用指针或复杂状态,需结合版本号(如
std::atomic高32位存版本)
三、内存布局与缓存友好优化
性能瓶颈常在 CPU 缓存行(cache line)伪共享(false sharing)。避免多个原子变量落在同一 cache line(通常 64 字节):
- 把
m_read和m_write放在不同 cache line:用alignas(64)对齐,或填充 padding - 缓冲区本身要
alignas(64),尤其当 T 是 POD 类型时,提升访存效率 - 避免在循环中频繁访问非局部变量;热数据(如索引)尽量贴近使用位置
四、实用建议与避坑点
- 不要自己造轮子:优先考虑成熟库,如
boost::lockfree::queue(MPMC)、moodycamel::ConcurrentQueue(高性能 MPMC,支持异常安全) - SPSC 场景下,Linux 的
eventfd或pipe也可作轻量级 ring buffer 替代,但受限于系统调用开销 - 禁止在 ring buffer 元素中存放需析构的对象(如
std::string)——无锁结构无法安全调用 dtor;应存储 trivially copyable 类型,或用 placement new + 显式析构(需额外同步) - 调试时可用
std::atomic_thread_fence插桩验证顺序,但发布版务必删掉
基本上就这些。无锁 ring buffer 不复杂但容易忽略内存序和缓存细节。从 SPSC 入手验证逻辑,再逐步扩展到 MPMC,比一上来啃复杂模型更稳妥。
# 放在
# 这是
# 多个
# 适用于
# 最简单
# linux
# 循环
# 并发
# 对象
# c++
# String
# 字节
# 指针
# 线程
# 无锁
# 高性能
# 局部变量
# 落在
# 性能瓶颈
# 中不
# Array
# nas
# padding
# 最后更新
# 可作
相关栏目:
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
AI推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
SEO优化<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
技术百科<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
谷歌推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
百度推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
网络营销<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
案例网站<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
精选文章<?muma echo $count; ?>
】
相关推荐
- Dapper的Execute方法的返回值是什么意思
- Python集合操作技巧_高效去重解析【教程】
- 如何使用Golang匿名函数_快速定义临时函数逻辑
- Windows10如何更改开机密码_Win10登录
- Win11怎么开启窗口对齐助手_Windows11
- Win11系统占用空间大怎么办 Win11深度瘦身
- Win11怎么开启游戏工具栏_Windows11
- 使用类变量定义字符串常量时如何实现类型安全的 Li
- Win11怎么设置鼠标宏_Win11鼠标按键自定义
- c++怎么处理多线程死锁_c++ lock_gua
- Win10如何设置双wan路由器 Win10双wa
- Windows10怎么备份注册表_Windows1
- Win10如何关闭安全中心所有通知 Win10禁用
- MAC如何隐藏文件夹及文件_MAC终端命令隐藏与第
- 如何用::实现单例模式_php静态方法与作用域操作
- php8.4新语法match怎么用_php8.4m
- 如何从 Go 的 map[string]inter
- c++中的CRTP是什么 c++奇异递归模板模式【
- Windows Defender扫描失败怎么办_安
- Win10系统怎么查看显卡温度_Win10任务管理
- Python大型项目拆分策略_模块化解析【教程】
- c# F# 的 MailboxProcessor
- Win10如何卸载预装Edge扩展_Win10卸载
- Win11怎么更改计算机名_Windows11系统
- PHP 中如何在函数内持久修改引用变量所指向的目标
- Win11如何开启telnet服务 Win11启用
- 如何在 Go 中正确测试带 Cookie 的 HT
- Mac如何开启夜览模式_Mac护眼模式设置与定时
- Windows11怎么自定义任务栏_Windows
- Python列表推导式与字典推导式教程_简化代码高
- php订单日志怎么记录物流_php记录订单物流变更
- Win11视频默认播放器怎么改_Win11关联第三
- 电脑无法识别U盘怎么办 Windows磁盘管理与驱
- 如何使用Golang实现微服务状态监控_Golan
- Linux怎么实现内网穿透_Linux安装Frp客
- mac怎么安装pip_MAC Python pip
- 如何有效拦截拼接式恶意域名的垃圾信息
- 如何使用Golang实现容器安全扫描_Golang
- Windows如何拦截2345弹窗广告_Windo
- Windows怎样关闭开始菜单广告_Windows
- 如何使用Golang sync.Map实现并发安全
- Win11怎么开启剪贴板历史记录_Windows1
- Win11怎么设置ipv4地址_Windows 1
- c++如何实现一个高性能的环形队列(Ring Bu
- c++中的可变参数模板(variadic temp
- Windows10如何更改日期格式_Win10区域
- Win11如何设置环境变量 Win11添加和修改系
- php转mp4怎么保留字幕_php处理带字幕视频转
- Win11时间不对怎么同步_Win11自动校准互联
- Win11玩游戏全屏闪退怎么办_Win11全屏优化

用
QQ客服