Linux内核原子操作实现原理几问几答

1.前言

因为项目的开发需要用到这一块的API,结果发现自己对这块内容的理解已经很模糊了。抓起书重新理解了一下。了解这一块内容的话完全没有必要阅读本文。

2.问题

2.1为什么不用锁?

        因为锁太“重”了。本质上原子操作不过是对一小块内存区域的操作,或读或写,或加或减。用锁当然可以实现独占原子性的操作,但是要么引发调度,要么自旋空转,对于简单的内存操作没有必要。现代CPU架构可以从硬件指令的层面实现原子操作,是一种更合适的做法。

        本文基于v.5.0.0版本进行讨论。

2.2 原子操作是怎么实现的?

        Linux内核中如果搜索ATOMIC_OP宏定义,可以看到arch目录下每个架构 都有自己的实现。include目录下还有个共用的实现。

        公共的实现在include/asm-generic/atomic.h中。

        可以看到cmpxchg操作是实现原子操作的核心机制。

        cmpxchg在各个平台都有各自的实现,且其实现的方式都以原子性指令实现,比如x86架构的cmpxchg指令,ARM64架构的ldxr和stxr指令。所以cmpxchg的通用性和原子性使得其称为ATOMIC_OP实现的基础。

        除了上面的公共实现,各个架构对ATOMIC_OP有各自的实现,比如ARM64架构上,

arch/arm64/include/asm/atomic_ll_sc.h提供了ARM64架构专属版本。

        可以看到实现的的基础还是ldxr和stxr指令。

        各个架构实现的版本理论上可以提供更好的性能。

​​​​​​​2.3 ARM64架构的LDXR和STXR指令如何具有魔力?

        手边的ARMV8.x手册找不到了,这里就不截图了。主要是ldxr可以标记访问内存的独占访问标记,stxr可以解除这个独占访问标记。这两条指令中间的操作就具有了内存访问的原子性。

​​​​​​​2.4 RISC-V架构有类似的指令吗?

        是的,相关的指令定义在A拓展指令集中。

​​​​​​​2.5 比较交换操作有哪些实现方式?

        首先,armv8.0架构上可以调用casx指令,但是个人理解应该是伪指令的形式实现的,本质上还是利用ldxr和stxr实现的。armv8.1架构提供了实质的casx指令。

        总结一下:

指令

隐含内存屏障操作

解释

casa

Load-Acquire

防止后续指令重排在当前指令前面。

casl

Store-Release

防止前面指令重排在当前指令后面。

cas

/

/

casal

Load-Acquire + Store-Release

防止后续指令重排在当前指令前面,同时防止前面指令重排在当前指令后面。

        以cmpxchg的实现来讲,也有下面几个方式:

隐含内存屏障操作

解释

cmpxchg_acruire

Load-Acquire

防止后续指令重排在当前指令前面。

cmpxchg_release

Store-Release

防止前面指令重排在当前指令后面。

cmpxchg_relaxed

/

/

cmpxchg

Load-Acquire + Store-Release

防止后续指令重排在当前指令前面,同时防止前面指令重排在当前指令后面。

3. 总结

        高并发访问的时候可以根据需求使用原子操作API,可以使用共用定义基于cmpxchg实现的API也可以使用架构优化的版本。

        精力有限,开发场景也十分依赖原子操作,所以本文理解非常粗糙,仅供参考。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值