MESI缓存一致性

硬件上存储器的层次结构

有一个问题:

当我们数据在L3到L6之间的时会被Load到不同的CPU之中,不同的CPU之间的数据怎么一致性

也就是说,一个线程改了CPU内部的数据,另一个线程在另一个CPU上怎么才能知道呢

解决办法

1. 把总线锁住(L2和L3之间加把锁),一个CPU访问L3上的一个数的时候,另外一个CPU不允许访问

2. 缓存一致性协议(不同的CPU型号协议不同)

  Intel的CPU则是用的MESI Cache一致性协议,给每个缓存做个标记(额外两位)

  Modified 数据和主存的内容相比,更改过

  Exclusive 数据我独享

  Shared 数据在我读的时候 别的CPU也在读

  Invalid 无效的:我读的时候 被别的CPU改过了

参考文章:https://www.cnblogs.com/z00377750/p/9180644.html

缓存行对齐(CacheLine)

缓存行Cache Line:当我们把内存中的某些数据放到CPU的缓存中去,不会仅仅把这一个数放进去,

缓存行越大:局部空间效率越高,读取时间慢

缓存行越小:局部空间效率越低,读取时间快

取一个折中值:目前多用64字节。

两个int类型的数据 x,y位于同一个缓存行,我一个CPU只用x,但是会把y读进来,另一个CPU只用y,读的时候也会把x,y都读进来。

当其中一个CPU把x改了之后,通知其他CPU整个缓存行都改变了(其他CPU可能只用到了y)

同样:当其中一个CPU把y改了之后,通知其他CPU整个缓存行都改变了(其他CPU可能只用到了x)

demo1 数组中的两个值可能位于同一个缓存行,并且两个线程位于不同的CPU

package com.mashibing.juc.c_028_FalseSharing;

import java.util.Random;

public class T01_CacheLinePadding {
    private static class T {
        public volatile long x = 0L;
    }

    public static T[] arr = new T[2];

    static {
        arr[0] = new T();
        arr[1] = new T();
    }

    public static void main(String[] args) throws Exception {
        Thread t1 = new Thread(()->{
            for (long i = 0; i < 1000_0000L; i++) {
                arr[0].x = i;
            }
        });

        Thread t2 = new Thread(()->{
            for (long i = 0; i < 1000_0000L; i++) {
                arr[1].x = i;
            }
        });

        final long start = System.nanoTime();
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println((System.nanoTime() - start)/100_0000);
    }
}
View Code

demo2 首先声明了7个Long类型的变量 占用了(7X8=56字节),因为CacheLine的长度是64个字节,所以在此声明Long类型数组的时候,数组中的两个元素会位于不同的缓存行

package com.mashibing.juc.c_028_FalseSharing;

public class T02_CacheLinePadding {
    private static class Padding {
        public volatile long p1, p2, p3, p4, p5, p6, p7;
    }

    private static class T extends Padding {
        public volatile long x = 0L;
    }

    public static T[] arr = new T[2];

    static {
        arr[0] = new T();
        arr[1] = new T();
    }

    public static void main(String[] args) throws Exception {
        Thread t1 = new Thread(()->{
            for (long i = 0; i < 1000_0000L; i++) {
                arr[0].x = i;
            }
        });

        Thread t2 = new Thread(()->{
            for (long i = 0; i < 1000_0000L; i++) {
                arr[1].x = i;
            }
        });

        final long start = System.nanoTime();
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println((System.nanoTime() - start)/100_0000);
    }
}
View Code

demo1打印时间200 demo2打印时间100。

证明了:位于同一缓存行的两个不同数据,被两个不同CPU锁定,产生互相影响的伪共享问题,使用缓存行对齐可以提高效率

 

posted @ 2020-05-01 11:51  palapala  阅读(321)  评论(0编辑  收藏  举报