cpu缓存与多线程

1、cpu缓存结构

    CPU速度远高于内存(即若是只考虑CPU和内存因素,程序的性能经常受到内存访问速度的限制,内存访问和运行),为了协调CPU和内存在速度上的差别,在CPU中增长了高速缓存。和计算机存储金字塔结构相似,高速缓存也能够按照金字塔结构,从下到上越接近CPU速度越快,同时容量也越小。如今大部分的处理器都有二级或者三级缓存,从下到上依次为 L3 cache, L2 cache, L1 cache. 缓存又能够分为指令缓存和数据缓存,指令缓存用来缓存程序的代码,数据缓存用来缓存程序的数据。 
    单核CPU只含有一套L1,L2,L3缓存;若是CPU含有多个核心,即多核CPU,则每一个核心都含有一套L1(甚至和L2)缓存,而共享L3(或者和L2)缓存。多CPU,每一个CPU都相互独立,拥有本身的缓存,CPU之间没法共享缓存。 下图为一个单CPU双核的缓存结构。 
                        
html

缓存行 cache line 
    缓存行时缓存和内存交换数据的最小单位,通常为64字节。即每次缓存和内存之间进行数据交换的时候,都是以字节对齐的连续64字节的内存块整个进行。
shell

缓存访问 
    没有缓存的结构中,CPU执行进程的时候,使用虚拟地址,虚拟地址经过MMU翻译为物理地址,映射到内存中;在有缓存的结构中,CPU访问数据先查找缓存中是否存在该数据,这能够经过数据在进程中的虚拟地址去到缓存中查找,也能够经过该数据在内存中的物理地址去到缓存中查找。 
    所以,缓存中的数据既能够经过数据在进程空间中的虚拟地址检索,也能够经过数据的实际内存物理地址来检索。若是经过进程空间中的虚拟地址,那么多个不一样进程可能含有相同的虚拟地址,所以实际中还须要在缓存行中添加 ASID(address space identifier) the hardware version of a process ID,这样CPU在运行不一样进程的时候,就能够经过 虚拟地址+ASID 在cache中进行查找; 
    若是缓存经过物理地址来检索,那么须要MMU介于CPU和cache中间来进行地址的翻译,这样就下降了cache查找的速率,所以通常 L1 cache不能经过物理地址检索,而是经过虚拟地址,由CPU直接访问。而L2,L3 cache能够经过物理内存地址检索
缓存

TLB 快表 
    MMU进行虚拟地址到物理地址的映射,经过页表将虚拟地址翻译为物理地址。TLB位于MMU内部,不须要通过页表就能够将虚拟地址转换为物理地址,速度更快。 
    每个TLB寄存器的每一个条目包含一个页面的信息:有效位,虚页面号,修改位,保护码,和页面所在的物理页面号,它们和页面表中的表项一一对应。 
MMU在翻译的时候,先查看虚拟地址的虚拟页面号是否存在TLB(并行的查找)中,若是存在,且没有违背读写权限限制,则直接给出TLB中的物理页面号;若在TLB中不存在,则进行常规的页表的查找,而后从TLB中淘汰一个条目,并更新为刚刚查找的页面。
多线程

多线程场景下的缓存

    在单线程模式下,一块内存只对应一个cpu核心的缓存,且只被一个线程访问。缓存独占,不会出现访问冲突等问题。 
    在多线程模式下,一个CPU,且CPU单核,进程中的多个线程会同时访问进程中的共享数据,CPU将某块内存加载到缓存后,不一样线程在访问相同的物理地址的时候,都会映射到相同的缓存位置,这样即便发生线程的切换,缓存仍然不会失效。但因为任什么时候刻只能有一个线程在执行,所以不会出现缓存访问冲突。固然,因为CPU内部寄存器的存在,会有多线程下的 A++ 非原子性语句致使的问题。 
 
    A++ ==> 
    reg = (&A); 
    reg ++; 
    
(&A) = reg; 
在发生线程切换的时候,线程使用的内部寄存器会被做为现场进行保存。 
 
    多线程模式下,一个CPU,且CPU有多核,每一个核都至少有一个L1 cache。多个线程访问进程中的某个共享内存,且这多个线程分别在不一样的核心上执行,则每一个核心都会在各自的caehe中保留一份共享内存的缓冲。因为多核能够作到真并行,可能会出现多个线程同时写各自的cache, 
    所以CPU有“缓存一致性”原则,即每一个处理器(核)都会经过嗅探在总线上传播的数据来检查本身的缓存值是否是过时了,当处理器发现本身缓存行对应的内存地址被修改,就会将当前处理器(核)。所以,咱们常常看到在多核多线程的场景下,在声明变量时候使用volatile,volatile变量要求在更新了缓存以后当即写入到系统内存,而非volatile变量,则是CPU修改缓存,缓存在适当的识货(不知道何时)将缓存数据写入内存。写入内存的操做会出发其余处理器(核)将本身已经缓存的那块正在被写入的内存失效,并在下次须要使用到该内存的时候从新从内存读取。
ide

False Sharing(伪共享) 
    因为缓存按照最小单位缓存行进行和内存交互,缓存行通常为64字节。内存中的连续64字节会被加载到一个缓存行中。当多线程修改互相独立的变量时,若是这些变量共享同一个缓存行,就会无心中影响彼此的性能,这就是伪共享。 
            
性能

    如上图所示,X和Y被放在同一缓存行中,当core1 修改x的时候,为了线程间可见性,须要锁定缓存行;此时core2中的缓存行也跟着失效;一样,core2中修改y时候,也须要锁定缓存行,core1中的缓存行也跟着失效。影响效率。spa

相关文章
相关标签/搜索