关于 atomic 的话题

2020-06-01 00:00:00 指令 原子 保证 边界 这条

这里有一个很重要的概念: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 的话题 

相关文章