关于 atomic 的话题
这里有一个很重要的概念:boundary (边界)
常见的 boundary:
★ word boundary(16 位)
★ doubleword boundary(32 位)
★ quadword boundary(64 位)
---------------------------------------------------------------------------------
1、造成这些 boundary 的原因是:data bus width (数据线的宽度)
对于 processor 这里有一个很重要的分界点,以 Pentium 处理器为分界,在 Pentium 之前的 data bus 是 32 位,而 Pentiume 之后的 data bus 有 64 位。
每 8 bits 分成一组 byte,由信号 BE# 来控制 read/write,被称为 data path
所以,Pentiume 之后的 processor 有 8 个 data path(BE0 ~ BE7)
就是由这些 data path 造成了 多种 boundary,这 8 个 data path 造成了可以有 quadword boundary 的出现
但是 address bus 还是 32,以及后来的 48 位
2、 data path 是影响 boundary 和 atomic 的主要的因素,
而造成 非 atomic 的成因就是:跨 bounday,实际上是跨了 8 data path
因此:跨了 8 个 data path 就会造成 非 atomic 的情况
在 Pentium 之后的 processor 只要在不是跨 8 data path,即:quadword boudary 的情况下都能保证是 atomic
3、 何为跨 8 data path ?
BE0# ----> 0
BE1# ----> 1
BE2# ----> 2
BE3# ----> 3
BE4# ----> 4
BE5# ----> 5
BE6# ----> 6
BE7# ----> 7
-------------------------------------------
每个 data path 对应控制 1 个 byte
跨 quadword boudary 产生的情形:
例如:当从 BE3#(3 data path) read/write 一个 quadword(64位),这时就属于跨 quadword boudary
这时,processor 需要做 2 次 read/write 操作,这样,就不能保证 atomic
又例如:
从 BE3# (3 data path) read/write 一个 word 操作,不会跨过 8 data path,它的 atomic 得到保证。
4、 另一些很坏的情况是:跨 cache line boundary,甚至是:跨 page boundary
cache line boundary 是:大多数 processor 的 cache line 是 64 bytes(0 ~ 63 byte),如果一个 read/write 是跨过了 64 bytes 这个边界的话,若使用 lock 来保证它的 atomic 的话,processor 会先做 fill cache line 动作。
page bundary 是:以 4K page 为例,同样若跨了 4K bytes 边界,processor 会做两次读 page
5、 以指令来说明“跨 boundary“
指令: mov eax, dword ptr [5]
这条指令从 地址 5 开始读 doubleword 到 eax 寄存器
那么:
(1) processor 先将 BE5# = 0,BE6# = 0,BE7# = 0,其它置 1,使用 data path 5、6、7 有效,其它 data path ,先读 24 位,放到 eax 的低 24 位
(2) 接着 processor 再置 BE0# = 0,其它置1,使 data path 0 有效,其它 data path ,
读 byte 放到 eax 的高 8 位
------------------------------------------------------------
以这样来完成 doubleword 的读,这样 processor 实际上做了 2 次 read 工作。
所以,atomic 将不能得到保证。
不能保证 atomic 的第二个因素是:processor 做 read-modify-write 类交易
典型的如:执行 add dword ptr [eax], eax 指令
对于这条指令:
1、processor 是 read 从内存 [eax] 一个 dword 放到 temp registers
2、processor 做 add 工作,temp registers 与 eax 相加结果放 temp registers
3、processor 写内存 [eax],从 temp registers
-------------------------------------------------------------
这样,就是 read-modify-write 操作不能保证 atomic
需要 lock 进行 atomic
int b = a;
代码的目的是令 b = a
(1) movl a, %eax // atomic
(2) movl %eax, -4(%ebp) // atomic
-------------------------------------------------------------
虽然是2条指令,每条指令都是原子的。
(1) 中 a 已经 load 到 eax 中,即使读完后 a 被改变,不会影响 eax
(2) 中 eax 已经 store 到 -4(%ebp) 中,这个 eax 就是 a 值
>>> 即使 write 后,-4(%ebp) 被改写,那也是 write 完之后的事。
所以:int b = a; 这条语句是原子的,这样已经足够了
即使之后 b 被改写,但 b = a 语句来说,是原子的。
又例如:
b = a;
----------------------------------------------
如果,编译器是这样编译的话:
movl a, -4(%ebp) // a ---> temp
movl -4(%ebp), %eax // temp ---> eax
movl %eax, -8(%ebp) // eax ---> b
--------------------------------------------------------------------
中间,多了一个 memory 读/写,这就不能保证其原子性了。
文章来源CU社区:关于 atomic 的话题
相关文章