迁安做网站中的cms润强,百度网页游戏排行榜,网站空间服务器费用,wordpress眉顶布局无论程序语言如何千变万化#xff0c;他们都深深地根植于目前的计算机体系结构。左图是intel CPU的三级高速缓存设计#xff0c;由于高速缓存对程序员基本不可见#xff0c;因此可以抽象为右图。缓存的设计首先还是先谈谈左图。L1-cache分为两部分#xff0c;i-cache存储指…无论程序语言如何千变万化他们都深深地根植于目前的计算机体系结构。左图是intel CPU的三级高速缓存设计由于高速缓存对程序员基本不可见因此可以抽象为右图。缓存的设计首先还是先谈谈左图。L1-cache分为两部分i-cache存储指令(只读)d-cache存储数据(可读可写)CPU只能和寄存器以及L1-cache进行直接交互数据不能隔层传递只能一层一层往上读一层一层往下写访问L1需要至少4个时钟周期L2需要至少10个L3需要至少30个。即便是速度最快的L1也低于运算单元的执行速度何况存在缓存未命中的情况因此在L1和运算单元之间加上了Writebuffer和Readbuffer(合称Memory Ordering BufferMOB)数据准备好的时候再完成相关指令这就是CPU指令乱序——顺序执行乱序完成。乱序完成的结果放入到Writebuffer中按照原有的执行顺序刷到缓存中缓存由多个缓存行组成。每个缓存行结构如图所示(以64位机器为例)CPU读取缓存的时候找到对应的缓存行如果前面的有效位为零就从下一级缓存加载到这一级缓存相关的问题明白缓存的设计之后再看右图来分析其中的问题缓存导致的内存可见性已知线程A运行在core 0上线程B运行在core 1上两者都对同一个内存地址进行读取这个内存地址的内容会被加载到cache然后CPU读取这时候线程A对内容进行了修改但是线程B却可能一直从本核心的cache读取无法感知到该地址的内容已被修改。多核导致的自增操作原子性自增操作分为三步从内存读取变量到寄存器寄存器中的值加1写回到内存。已知线程A运行在core 0上线程B运行在core 1上两者都对变量执行加一操作。A执行完一二两步时B执行完第一步A将加一后的值写入到内存B执行完二三两步也将加一后的值写入到内存结果变量只加了一而不是加二MOB导致的cache可见性a1.0; aa/2; aa-1.0;按照正常的逻辑a最后的结果为-0.5但是因为除法的执行时钟周期大于减法第三句执行时a/2的结果存放在writebuffer中还没写入到缓存a-1.0中a的值已经从缓存中加载到readbuffer也就是a-1.01.0-1.00 (高级语言不会出现这个问题因为编译器已经做了处理前面的伪代码仅表示逻辑)相关的实现为了解决这些问题CPU提供了一些指令其中比如lock和cmpxchg。lock 汇编前缀在Intel奔腾系列之前这个指令前缀能够锁定总线禁止其他CPU核心操作内存执行完后边的指令后释放总线在这个过程中其他CPU核心会监听总线发现某个内存地址内容被修改就会将本核心下的对应cache行有效位置0。因为锁总线会禁止所有内存操作降低效率因此在奔腾之后这个指令前缀不锁总线而是锁定相关的cache行对某个地址修改后直接让相关cache失效。这样解决了问题一cmpxchg 将寄存器a中的值与内存中比较如果一样将寄存器c中的值和内存中的值交换如果不一样就设置异常位并将内存中的值读取到寄存器a。代入到问题二从内存读取值到寄存器a加一后保存到寄存器c然后执行cmpxchg执行完后如果有异常就重新加一再尝试写回直到成功。这样解决了问题二cmpxchg和lock 在执行完以后会将writebuffer刷到cache并清空readbuffer这样解决了问题三。另外X86_64引入了内存屏障指令 lfence、sfence、mfence。lfence前面的读取操作完成也就是readbuffer中的内容全部被cpu读取后才能执行lfence之后的读取操作sfence前面的写入操作完成也就是writebuffer全部刷到缓存中才能执行sfence之后的写入操作mfence之前的读写操作全部完成才能进行mfence之后的操作。