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

  • 相关阅读:
    Unity Animation扩展方法总结
    Unity 离线建造系统
    Unity 任意区域截屏创建Sprite
    Unity ugui拖动控件(地图模式与物件模式)
    Unity 极简UI框架
    Unity 芯片拼图算法
    Unity Procedural Level Generator 基础总结与功能优化
    MANIFEST.MF是个什么?
    外包程序员怎么办?
    文件上传transferTo一行代码的bug
  • 原文地址:https://www.cnblogs.com/ssskkk/p/12812793.html
Copyright © 2020-2023  润新知