惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Project Zero
Project Zero
F
Fortinet All Blogs
Recent Announcements
Recent Announcements
云风的 BLOG
云风的 BLOG
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
M
MIT News - Artificial intelligence
S
SegmentFault 最新的问题
Blog — PlanetScale
Blog — PlanetScale
T
Tailwind CSS Blog
WordPress大学
WordPress大学
Engineering at Meta
Engineering at Meta
S
Schneier on Security
N
News and Events Feed by Topic
N
News | PayPal Newsroom
H
Help Net Security
C
CXSECURITY Database RSS Feed - CXSecurity.com
T
The Exploit Database - CXSecurity.com
Attack and Defense Labs
Attack and Defense Labs
博客园 - Franky
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
J
Java Code Geeks
A
About on SuperTechFans
AWS News Blog
AWS News Blog
S
Secure Thoughts
The Cloudflare Blog
Hugging Face - Blog
Hugging Face - Blog
爱范儿
爱范儿
C
Cybersecurity and Infrastructure Security Agency CISA
V2EX - 技术
V2EX - 技术
Recorded Future
Recorded Future
Microsoft Azure Blog
Microsoft Azure Blog
博客园_首页
MyScale Blog
MyScale Blog
Martin Fowler
Martin Fowler
Help Net Security
Help Net Security
人人都是产品经理
人人都是产品经理
Latest news
Latest news
C
Cyber Attacks, Cyber Crime and Cyber Security
大猫的无限游戏
大猫的无限游戏
The Last Watchdog
The Last Watchdog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
月光博客
月光博客
H
Hacker News: Front Page
P
Proofpoint News Feed
N
News and Events Feed by Topic
H
Heimdal Security Blog
L
Lohrmann on Cybersecurity
有赞技术团队
有赞技术团队
L
LangChain Blog
Application and Cybersecurity Blog
Application and Cybersecurity Blog

博客园 - egmkang

配眼镜最佳实践 [Python]解密pyc文件 C# Protobuf如何做到0分配内存的序列化/反序列化(2) Flash----一种VirtualActor模式的分布式有状态系统原型 [投资]对价值投资新的理解 通过Consul Raft库打造自己的分布式系统 Dapr实现分布式有状态服务的细节 [06] 优化C#服务器的思路和工具的使用 [05] 通过P/Invoke加速C#程序 [04] C# Alloc Free编程之实践 [03] C# Alloc Free编程 [02] 多线程逻辑编程 [01] C#网络编程的最佳实践 C#如何正确的做深拷贝 C# Protobuf如何做到0分配内存的序列化 最近很火的namebase羊毛, 手把手教你怎么薅 DotNetty发送请求的最佳实践 C# protobuf自动更新cs文件 多读少写场景下多线程锁冲突的降低
CPU实现原子操作的原理
egmkang · 2020-12-04 · via 博客园 - egmkang

586之前的CPU, 会通过LOCK锁总线的形式来实现原子操作. 686开始则提供了存储一致性(Cache coherence),  这是多处理的基础, 也是原子操作的基础.

1. 存储的粒度

存储的组织形式(粒度)是以CacheLine为单位的, 通常为64字节甚至更高(早期也有32字节的). 然后几组CacheLine组成一个小的LRU(或者其他替换规则).

2. 协议

存储一致性(CC)一般是通过MESI协议, 以及后续的变种协议, 例如Intel的MESIF协议和AMD的MOESI协议, 来实现的. 

以MESI协议为例:

Modified: 独占CacheLine, 已经修改了, 但是还未同步到主存

Exclusive: 独占, 并且和主存一致

Shared : 共享的, 其他core也拥有该CacheLine, 并且与主存中一致

Invalid: 表示该CacheLine不可用

3. 通讯

有了协议, 那么就需要通讯来实现协议(存储的状态). 通讯有两种, 一种是广播/侦听, 一种是目录式.

广播/侦听顾名思义就是存储状态的变更, 会被广播到其他core上面去, 进而去维护CacheLine的状态. 很明显这种方式会浪费大量的流量, 而且难以扩展, CPU核数多了, 总线就是明显的瓶颈.

目录式, 就是把改变通知给具体的core, 从而避免广播. 但是考虑一种极端情况, 如果很多个core都在访问同一个CacheLine, 那还是不能避免(事实上的)广播. 所以, 多线程编程时, 共享同一个CacheLine不是一个好的选择.

 有了上面的东西, 现在我们来考虑原子操作的实现:

1. 原子的Load/Store

由于CPU对缓存的管理是以CacheLine为单位的, 所以在一个CacheLine内load/store实际上都是原子的. Load和Store一个8字节对象, 不可能高4位和低4位是分开操作的(从而搞成俩值). 

但是光有这个实际上还不够, CPU对CacheLine的修改不是立即写到主存里面去, 所以其他Core看到的值就有可能是老的值, 所以这时候还需要fence来读到最新的值; 至于写, 那一定需要写权限, 即M或者E状态, 而这两个权限里面都有最新的值(只是你刚才读到的不一定是最新的, 所以有可能用老值覆盖了新值).

2. FetchAndAdd

这是比load和store稍微复杂的操作, 实际上是一个复合操作. 但是有了M和E状态, 就很好理解了:

lock(CacheLine)
v := load(obj)
v += add
store(obj, v)
release(CacheLine)

x86里面是xadd指令.

3. CompareAndSwap

那么CAS, 也就可以猜出来:

lock(CacheLine)
v := load(obj)
if v != expected {
  store(obj, new_value)
}
release(CacheLine)

x86里面是xchg

这里说的lock和release均表示对该CacheLine独占和解出独占的意思.

关于原子操作的原理, 鲜有资料表表示其具体怎么做的, 很有可能是过于偏向于硬件. 但是对MESI等协议的思考, 实际上还是能猜到CPU内部的实现(至少七八不离十).  好在找到两个资料, 一个是<<并行多核体系结构基础>>和<<从鲲鹏920了解现代服务器实现和引用>>. 其中鲲鹏920内存模型章节这么写到:

原子指令在软件上看来逻辑并不复杂,但在微架构上看,成本是很高的。如果我们把CPU 和内存都看做是总线上的一个个独立的实体,有一个CPU要做CAS指令,这个CPU需要先从 内存中读一个值,同时要在内存控制器上设置一个标志,保证其他CPU写不进去,等它比 较完了,然后再决定写一个值回去,才会让其他CPU写入。

不同微架构实现有不同方法对行为进行优化,在鲲鹏920上,原子指令的请求需要在 L3Cache上进行排队,保证在原子操作的多个动作之间能维持原子指令要求的语义。这个 排队本身也有成本。所以没有原子需要就不要轻易用原子变量,这其实是有成本的。

 并行多核体系结构这么写到:

幸运的是, 缓存一致性协议提供了原子性被保障的基础. 举例来说, 当遇到一个原子指令时, 这个协议知道需要保证原子性. 他首先获得对存储单元M的"独家所有权" (通过将其他包含M的缓存块中的拷贝都置为无效). 当获得独家所有权之后, 这个协议会确保只有一个处理器能够访问这个块, 而如果其他处理器在此时想要访问的话就会经历缓存缺失, 接下来原子指令就可以执行. 在原子指令持续期间, 其他处理器不允许"偷走"这个块. 距离来说, 如通另一个处理器要求读或者写这个块, 这个块就被"偷"了(如块被清理, 块的状态被降级为无效). 在原子指令完成之前暴露块会破坏指令的原子性, ......

参考:

1) 并行多核体系结构基础

2) 从鲲鹏920了解现代服务器实现和应用