zoukankan      html  css  js  c++  java
  • Memory Ordering (注意Cache带来的副作用,每个CPU都有自己的Cache,内存读写不再一定需要真的作内存访问)

    Memory Ordering

     
    • Background 
      很久很久很久以前,CPU忠厚老实,一条一条指令的执行我们给它的程序,规规矩矩的进行计算和内存的存取。 
      很久很久以前, CPU学会了Out-Of-Order,CPU有了Cache,但一切都工作的很好,就像很久很久很久以前一样,而且工作效率得到了很大的提高。 
      很久以前,我们需要多个CPU一起工作,于是出现了传说中的SMP系统,每个CPU都有独立的Cache,都会乱序执行,会打乱内存存取顺序,于是事情变得复杂了……
    • Problem 
      由于每个CPU都有自己的Cache,内存读写不再一定需要真的作内存访问,而是直接从Cache里面操作,同时CPU可能会在合适的时候对于内存访问进行重新排序以提高效率,在只有一个CPU的时候,这很完美。 
      而当有多个CPU的时候——
      • 从Cache到内存的flush操作通常是被延迟的,所以就需要某种方法保证CPU A进行的内存写操作真的可以被CPU B读取到。
      • CPU可能会因为某些原因(比如某两个变量同在一个Cacheline中)而打乱
        • 实际内存写入顺序
        • 实际内存读取顺序
        所以就需要某种方法保证在需要的时候
        • 之前的读写操作已经完成
        • 未来的读写操作还没开始
      考虑一个例子: 
      Thread A: 
      while (flag == 0) 
              ; // do nothing 
      printf("%d ", data); 
      Thread B: 
      data = 523; 
      flag = 1; 
      这里data代表了某种数据,它可以像这里一样是一个简单的整数,也可能是某种复杂的数据结构,总之,我们在Thread B中对data进行了写入,并利用flag变量表示data已经准备好了。 
      在Thread A中,一个忙等待直到发现data已经准备好了,然后开始使用data,这里是简单的把data打印出来。 
      现在考虑如果CPU发现对于data和flag的写入,如果按照先写入flag后写入data的方式进行,或者考虑由于Cache的flush操作的延迟,使得内存中变量的实际修改顺序是先flag后data,那么都将导致Thread A的结果不正确。事实上,由于内存读入操作同样是可能乱序进行的,Thread A甚至可能在读入flag进行判断之前就已经完成了对data的读入操作,这同样导致错误的结果。
    • Solution 
      在这个例子中,我们的需求是,Thread A中对于flag判断时,后面的任何读入操作都没有开始,Thread B中对于flag写入时,任何之前的写入操作都已经完成。 
      在Linux内核中,smp_rmb()、smp_wmb()、smp_mb()就是用来解决这类问题的,mb表示memory barrier。rmb表示读操作不可跨越(注意,不是人民币的意思:-P),也就是我们这个例子中的Thread A所需要的。wmb表示写操作不可跨越,也就是这里Thread B所需要的。mb集合了rmb和wmb的能力,读写操作都不可跨越。 
      在Qt中,其支持原子操作的类QAtomicInt支持四种类型的操作,Relaxed、Acquired、Release、Ordered,其中 Relaxed最为简单,就是不做特殊要求,由编译器和处理器对读写进行合适的排序。Acquired表示原子操作之后的内存操作不可被重排至原子操作之前。Release表示原子操作之前的内存操作不可被重排至原子操作之后。Ordered表示Acquired + Release。在前面的例子中,Thread A对于flag的读取操作需要Acquired版本,而Thread B对于flag的写入操作需要Release版本。 
      在实际实现中,不同体系结构的实现方法各不相同,很多RISC机器提供了专门的指令用于实现mb,而在x86上面,通常使用lock指令前缀加上一个空操作来实现,注意当然不能真的是nop指令,但是可以用来实现空操作的指令其实是很多的,比如Linux中采用的addl $0, 0(%esp)。Qt的不同类型原子操作由于本身就需要进行某种可被lock前缀修饰的操作,所以就不需要画蛇添足的再写一条空操作了,比如 testAndSetOrdered就可以直接使用lock cmpxchgl实现。

    转贴自:http://etrnlog.appspot.com/2009/10/12/memory-ordering.html

  • 相关阅读:
    Exp5
    Exp4
    Exp3
    Exp02
    【TPM】tpm搭建基础指南
    20155316 Exp1 PC平台逆向破解(5)M
    个人早期写的一些组件
    关于spring @scope("prorotype") 和 @aspectj 一起用的问题
    ThreadLocal内存泄漏需要注意的
    Spring IoC 容器大概流程
  • 原文地址:https://www.cnblogs.com/findumars/p/6253108.html
Copyright © 2011-2022 走看看