多核cpu怎么保证数据一致性(二)cpu为什么要用高速缓存?L1,L2,L3 cache

本文探讨多核CPU如何确保数据一致性,包括指令重排序的原因、多级缓存的作用及其必要性,并介绍了多核CPU的优势及高速缓存数据一致性的挑战。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

系列文章目录

多核cpu怎么保证数据一致性(一)为什么要做指令重排序?
多核cpu怎么保证数据一致性(二)cpu为什么要用高速缓存?L1,L2,L3 cache
多核cpu怎么保证数据一致性(三)MESI缓存一致性协议
多核cpu怎么保证数据一致性(四)volatile关键字、happens-before原则、内存屏障

前言

上篇文章《多核cpu怎么保证数据一致性(一)为什么要做指令重排序?》,我们说了为什么要做指令重排序,以及重排序保证指令正确执行的原则,本篇我们就从cpu的结构说说多核cpu怎么保证数据一致性的

一、cpu存取数的内存结构

我们知道cpu分为三级缓存和内存,如下图(图1-1)
cpu三级缓存
其中l1cache,l2cache,l3cache(其中l1cache中又分为L1D(L1 Data Cahce)和L1I(L1 Instruction Cache),我们这里只说数据缓存,指令缓存没什么可讲的哈),L3cache下面就是我们的主存,也是我们说的内存。

其中L1和L2cache是每个cpu核独享的,L3cache是多个cpu核共享的。

二、CPU为什么要有那么多级的缓存呢?

我用的是macbook pro 2017款,这是我的电脑配置:
电脑配置
可以看到我的处理器是2.8GHz,这是一个什么概念呢,就是每秒钟可以产生2.8G个(0或1)这样的数字,我们知道计算机中的程序和数据都是0和1组成的,这就是cpu的运算效率。一个int类型由32个bit组成,也就是说我处理一个int类型只要10ns,而我们从内存中读取一次数据呢,需要1000ns,差了100倍(这个速度相当于一个是高铁的速度,一个是步履蹒跚的老太太走路,差距巨大)。
虽然我的内存有16G,但是对于cpu来说去内存读数据还是太慢了。我们为了提升cpu存取数据的效率,如果能把cpu读取数据的效率控制在30-40ns,那cpu的效率将显著提升,此时就诞生了我们的cpu高速缓存。
为什么高速缓存要分为三级呢?这是跟硬件有关的,为了提升cpu存取数据的效率,那么这些数据一定要距离cpu足够的近,此时高速缓存的空间就很有限了,所以l1cache是距离cpu最近的,当然空间也是最小的,距离图示如下:
cpu内存结构

三、cpu为什么要用多核?

其实一个cpu的内核,性能是有极限的(上面说的2.8GHz),为了提升性能,让计算机做更多的任务,所以就要使用多个内核来提升效率。关于多核里面的高速

四、cpu怎么处理多核中的高速缓存数据不一致

我们在图1-1中说到,l1cache和l2cache是cpu的核独有的(如我的电脑4核16G,每个cpu核中都有l1cache和l2cache),如果遇到多线程的情况,如下代码所示:

public class VolatileTest {
    private static volatile int COUNTER = 0;

    public static void main(String[] args) {
        new ChangeListener().start();
        new ChangeMaker().start();
    }

    static class ChangeListener extends Thread {
        @Override
        public void run() {
            int threadValue = COUNTER;
            while ( threadValue < 5){
                if( threadValue!= COUNTER){
                    System.out.println("Got Change for COUNTER : " + COUNTER + "");
                    threadValue= COUNTER;
                }
            }
        }
    }

    static class ChangeMaker extends Thread{
        @Override
        public void run() {
            int threadValue = COUNTER;
            while (COUNTER <5){
                System.out.println("Incrementing COUNTER to : " + (threadValue+1) + "");
                COUNTER = ++threadValue;
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) { e.printStackTrace(); }
            }
        }
    }
}

我的数据既有在线程ChangeListener中执行,又有在线程ChangeMaker中执行,但是两个线程都用到了COUNTER这个共享变量(此时可能ChangeListener在核1上执行,ChangeMaker在核2上执行)。但是我存取数据都是在缓存中的,而缓存是cpu核独有的,怎么保证每个cpu核读到的数据都是最新的且正确的呢,我们将在下一章节说说“cpu的MESI缓存一致性协议”


总结

今天我们说了

  • cpu为什么要用多核:以为单个cpu核的性能是有极限的
  • cpu为什么要用高速缓存:从内存中存取数据太慢
    下一章节,我们将说说cpu怎么保证缓存的一致性:MESI缓存一致性协议

其实我一直认为,工欲善其事,必先利其器,在工具的使用上,我准备了专栏《java开发工具》,如果你感兴趣可以来看看

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值