• 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锁定,产生互相影响的伪共享问题,使用缓存行对齐可以提高效率

  • 相关阅读:
    bzoj 3238
    bzoj 3473 后缀自动机多字符串的子串处理方法
    bzoj 2998 第k小字串
    bzoj 3672 利用点分治将CDQ分治推广到树型结构上
    bzoj 3671 贪心
    NOIP模拟题——nan
    NOIP模拟题——kun(栈)
    hduP2586——How far away ?
    DP习题
    NOIP模拟题——来自风平浪静的明天
  • 原文地址:https://www.cnblogs.com/ssskkk/p/12812793.html
Copyright © 2020-2023  润新知