• 内存屏障


    问题产生原因:

      cpu0执行写操作,若CPU本地cache没有此变量,须发一个invalidate到总线,其他CPU收到invalidate消息后将此变量从自己的本地cache中清除,并且发送ack给CPU0,CPU0收到其他CPU发送的ack后将变量值写入到本地cache,但是CPU0在等待其他CPU回复ack时是出于停滞状态,大部分时间都是在等待消息,为了解决此问题引入CPU本地stroed buff。

      stroed buff引入使的CPU0无需等待其他CPU的答复先把值写入本地stroed buff,等其他CPU回复ack后再把变量值写入本地cache;收到读请求后先放入本地无效化队列,在写入cpu cache

      这两个问题导致了数据可见性:1、数据写入时,先到store buff,而没有到cpu 本地cache,更到不了内存,大量数据写入时候本地store buff数据乱序,并且其他cpu看不见此数据,因为此时在本地store buff中还没后到cache,EMSI协议无效;2、读数据时如果收到read invalid消息放入本地无效化队列,此时再读取数据是属于脏数据,其他cpu修改的数据导致本地不可见

      引入stroed buff后,变量读写情况为:

    a = 0 , b = 0;
    a = 1;
    b = a + 1;
    assert(b == 2);

      a在CPU1的本地cache中,b在CPU0的本地cache中

    1. CPU0写变量a,但是CPU0本地cache中没有此变量,发送read invalidate到总线上,让CPU1清除本地cache中a的值
    2. CPU0把a的值写入本地stroed buff
    3. CPU1收到read invalidate消息后清除本地cache中a的值并回应CPU0 ack消息
    4. CPU0执行b=a+1;
    5. CPU0收到CPU1回复的消息中a为0,从本地cache中读取a == 0
    6. CPU0执行a+1,写入b,由于b被CPU0独占直接写入本地cache,此时b的值为1
    7. b == 2 报错

      造成这个问题原因是由于CPU对内存进行操作的时候顺序和程序代码执行指令顺序不一致造成的;另一个原因是由于同一个CPU中stroed buff和本地数据不一致造成的;解决本地CPU数据顺序不一致可以由stroed forwarding处理,当CPU进行读操作时从stroed buff和本地cache中读取数据,若stroed buff中有数据则使用stroed buff的。

    内存操作顺序

    a = 0 , b = 0;
    void fun1() {   
      a = 1;   
      b = 1;
    }
    
    void fun2() {  
      while (b == 0) continue;  
      assert(a == 1);
    }

      CPU 0 执行 fun1() , CPU 1 执行 fun2() , a 变量在 CPU 1 cache 中 , b 变量在 CPU 0 cache 中

    1. CPU0执行a=1,由于不在本地cache中,把a=1放入stroed buff中,发送read invalidate到总线上
    2. CPU1执行while循环,由于b不在CPU1本地cache中,发送read message到总线上,从其他CPU或memory中获取b的值
    3. CPU0执行b=1,由于b在本地cache(cacheline处于modified状态或者exclusive状态)中,直接写入cache中
    4. CPU0收到cpu1发送的read message后,把最新值1送给CPU1,同时将b cacheline的状态设定为shared
    5. CPU1收到CPU0的read response后,把b=1写入本地cache,修改状态为shared
    6. 由于b值等于1了,因此CPU 1跳出while (b == 0)的循环,继续执行
    7. CPU 1执行assert(a == 1),这时候CPU 1的local cache中还是旧的a值,因此assert(a == 1)失败
    8. CPU1收到CPU0的read invalidate后,以变量a的值进行回应,清空本地cache中a的值
    9. CPU0收到CPU1的read response、ack后,将stroed buff中a的值写入本地cache

      由于CPU0对a的值写入还没有完成,CPU1开始对a的值进行读取;因为CPU并不知道哪些变量有相关性,这些变量是如何相关的。

  • 相关阅读:
    JSP学习-10-EL表达式
    深入浅出Mybatis(一)
    第10章—开启事务
    第09章—使用Lombok插件
    第08章—整合Spring Data JPA
    第06章—热部署
    第05章—Swagger2打造在线接口文档
    第03章—打造RESTful风格API
    第04章—整合Mybatis
    第01章—快速构建
  • 原文地址:https://www.cnblogs.com/tianzeng/p/14998876.html
Copyright © 2020-2023  润新知