Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

内存屏障(对硬件) #10

Open
seaswalker opened this issue Jul 3, 2020 · 0 comments
Open

内存屏障(对硬件) #10

seaswalker opened this issue Jul 3, 2020 · 0 comments

Comments

@seaswalker
Copy link
Owner

seaswalker commented Jul 3, 2020

来自: Is Parallel Programming Hard, And, If So, What Can You Do About It?

我们能信任的东西

即所有CPU(不同架构)均遵从的准则:

  1. 一个特定的CPU的所有访问操作都与该CPU上的程序顺序是一致的。
  2. 所有CPU对单个变量的访问都与存储这个变量的全局顺序有一些一致性
  3. 内存屏障成对操作。
  4. 互斥锁原语提供这样的手段。

第二条有意思,暂时不太准确理解其意思。几句耐人寻味的原文摘抄过来:

Because current commercially available computer systems provide cache coherence, if a group of CPUs all do concurrent non-atomic stores to a single variable, the series of values seen by all CPUs will be consistent with at least one global ordering.

Please note well that this section applies only when all CPUs’ accesses are to one single variable. In this single-variable case, cache coherence guarantees the global ordering, at least assuming that some of the more aggressive compiler optimizations are disabled via the Linux kernel’s ACCESS_ONCE() directive or C++11’s relaxed atomics [Bec11]. In contrast, if there are multiple variables, memory barriers are required for the CPUs to consistently agree on the order for current commercially available computer systems.

最后一句话,如果是对多个变量进行操作,那么需要memory barrier,换句话说,如果只有一个变量,无需memory barrier.

锁的内存屏障作用

锁的加锁和解锁操作必定以显性或隐性的方式存在memory barrier,这提供了内存顺序保证:第一个线程在临界区内的操作必定发生在第二个线程获得锁之前。Java的ReentrantLock的实现参考 #9

关于内存屏障不能做的假设

  1. 不能保证在内存屏障之前的内存访问将在内存屏障指令完成时完成;屏障仅仅用来在 CPU的访问队列中做一个标记,表示相应的访问不能被穿越。
  2. 不能保证在一个CPU中执行一个内存屏障将直接影响另外一个 CPU或者影响系统中其他硬件。间接效果是第二个CPU看到第一个CPU的访问是按顺序的。
  3. 不能保证一个CPU将看到第二个CPU 访问操作的正确顺序,即使第二个CPU使用一个内存屏障,除非第一个CPU也使用一个配对的内存屏障。
  4. 不能保证某些 CPU片外硬件不会重排对内存的访问。CPU缓存一致性机制将在CPU之间传播内存屏障的间接影响,但是不会按顺序执行这项操作。

种类

  1. 写(或存储) 内存屏障
  2. 数据依赖屏障
  3. 读内存屏障
  4. 通用内存屏障

屏障对

内存屏障必须成对使用才能推导出先后顺序。

当处理 CPU-CPU 交互时,几种类型的内存屏障总是应当配对。缺少适当的配对将总是会产生错误。一个写屏障应当总是与数据依赖屏障或者读屏障配对,虽然通用屏障也是可以的。类似的,一个读屏障或者数据依赖屏障总是应当与至少一个写屏障配对使用,虽然通用屏障也是可以的。

从CPU的角度看为什么需要内存屏障

MESI

CPU使用MESI协议(或其升级款)来保证其缓存的一致性。当CPU进行数据写入时,如果数据不在当前核心,那么会发送Read Invalidate消息,指示其它核心将此数据置为无效状态并发送给当前核心。

详解

直接参考书中附录B

概括

写内存屏障作用于store buffer,读屏障作用于无效队列,完整的屏障同时作用于两者

总结

  1. 每一个CPU总是按照编程顺序来感知内存访问
  2. 仅仅在操作不同地址时,CPU才对特定的存储操作进行重新排序
  3. 一个特定 CPU在内存屏障之前的所有装载操作(smp_rmb())将被所有随后的读内存屏障后面的操作之前被所有CPU所感知
  4. 所有在写内存屏障之前的写操作 (smp_wmb()) 都将比随后的写操作先感知
  5. 所有在内存屏障之前的内存访问 (装载和存储) (smp_mb())都将比随后的内存访问先感知
@seaswalker seaswalker changed the title 内存屏障(来自Is Parallel Programming Hard, And, If So, What Can You Do About It?) 内存屏障(对硬件) Jul 3, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant