x64平台非原子16字节元素无锁双端队列实现可行性问询
结论
你限定的Intel/AMD Windows x64 + VS2019环境下,直接将缓冲区改为非原子16字节对齐结构体的volatile指针、用普通赋值读写元素的方案完全可行,无需额外复杂优化。
原理说明
- VS标准库的
atomic<T>对非内置整数/指针类型默认嵌入自旋锁是实现特性,并非原子操作的必然要求,你完全可以依托x64平台本身的内存模型和指令特性规避该开销。 - 内存可见性完全符合要求:
- push操作是单线程执行,16字节元素写入完成后才会执行release语义的线程屏障,屏障保证所有之前的写入全局可见后,才会执行后续的bottom指针更新。
- steal操作先acquire读取top、执行seq_cst屏障后才读取bottom,只要满足
t < b的判断,说明对应索引位置的元素已经完成写入,不可能出现读取到半写内容的问题。
- 16字节读写的原子性有官方保证:
Intel/AMD x64指令集规范明确规定,对齐到16字节边界的SSE加载/存储指令(如MOVDQA)是原子操作,不会出现读写撕裂。你只要给16字节结构体添加__declspec(align(16))修饰,VS编译普通结构体赋值时会自动生成MOVDQA指令,无需手动调用cmpxchg16b。 - 你使用volatile指针的操作完全合理,可以防止编译器将元素读写优化掉、或是重排到内存屏障之外,满足语义要求。
注意事项
- 必须保证每个16字节元素16字节对齐,避免元素跨缓存行导致读写撕裂。
- 读写元素时直接使用结构体赋值,不要使用memcpy等库函数,避免编译器生成多次8字节读写指令破坏原子性。
- 无需使用
cmpxchg16b,该指令执行开销远高于普通MOVDQA读写,只会带来不必要的性能损失。 - 不需要改原队列的其他内存屏障逻辑,原论文的屏障要求在x64下依然完全适用。
内容的提问来源于stack exchange,提问作者iam
相关产品推荐
相关产品推荐

