7_线程安全_线程间的内存可视性2缓存_内存屏障_读写排序

接着上次的问题------并不意味着最终的结果是"2"。

为什么?因为涉及到高速缓存与内存总线的工作细节。处理器可能有高速缓存,用来保存最近从主存中读出数据的拷贝的快速本地内存。在一个"回写"(write-back)高速缓存系统中,数据最初只是保存在高速缓存中,而在后面的时间写入(刷新)主存。在不保证写顺序的系统中,高速缓存中的数据块可能在任何处理器认为方便的时候写入主存。如果两个处理器向同一内存地址写不同的数据,则不同的数据将分别保存在二者的高速缓存中。最终两个值将写到主存中,但是是在随机的时刻写入,与写到相应的高速缓存中的顺序无关。

即使同一线程(或处理器)中的两个写操作也不需要在内存中表现相同的顺序。内存控制器可能发现以相反的顺序写入会更快或更方便。

问题还不仅局限于两个线程写内存。想像一下,一个线程在某个处理器上向内存中写入数据,而另一个线程在其他处理器上读相同的内存。好像很显然地,线程将得到最近写入的值,而在有些硬件上的确如此。这种现象有时被称为"内存一致性"或"读写排序"。但是在处理器之间确保这种同步是复杂的,它会降低内存系统的速度,并且对大部分代码没有任何意义。现在很多的计算机(通常是最快的计算机)不再保证不同处理器间内存访问的顺序,除非程序使用特殊的指令,这些指令就是常说的"内存屏障"(memory barrier)。

内存屏障确保:所有在内存屏障之前发起的内存访问,必须先于在设置屏障之后发起的内存访问之前完成。

内存屏障是一堵移动的墙,而不是刷新cache的命令。

即使没有读写排序和内存屏障,写内存好像也必须是原子性的操作。即任何其他线程只能看到完整的旧数据或者看到完整的新数据。但这也并不总是正确的。大部分计算机有一个天然的内存粒度,依赖于内存的组织和总线结构。即使处理器读写8位数据,内存传输可能以32位或64位为单位。这意味着,相对于其他覆盖相同32或64位数据单元的内存操作而言,8位写操作不是原子操作。大部分计算机会写包含修改数据的整个内存数据单元(如32位)。如果两个线程向同一个32位内存单元中写入不同的8位数据,则结果是最后写入的线程将确定两个8位字节的值,即覆盖第一个线程写入的值。图3.8显示了这种效果。

聪明的你是不是想到了一种情况------如果一个变量跨越了内存单元的界限(这将在允许对齐内存访问的机器上出现),计算机不得不在两次总线事物中传送数据。例如,一个非对齐的32位数据可能需要写两个相邻的32位内存单元。如果其中一个内存单元同时被另一个处理器写入,则将丢失一半数据。这被称为"word tearing",如图3.9所示。

欢迎关注,持续前进。

相关推荐
CoderYanger10 小时前
Java EE 进阶:8.MyBatis 操作数据库(入门)(第二弹)
java·数据库·spring boot·spring·面试·java-ee·mybatis
CQU_JIAKE13 小时前
11.7[高体】
java·后端·spring
apcipot_rain14 小时前
C++转Java日记(04)
java·开发语言·c++
特立独行的猫A14 小时前
我给女儿写了个打字练习:一边敲键盘,一边把小学英语单词记牢
java·后端·python
云和数据.ChenGuang15 小时前
LangGraph 异步 Node 的设计与写法实践
开发语言·人工智能·python·机器学习·php
憧憬成为java架构高手的小白16 小时前
LangGraph4j 实战(下)
java
天诰16 小时前
SA-K-11 检索会消失吗与四个未解问题
java·服务器·人工智能·python·机器学习·ai编程
蜗牛一步步往上爬19 小时前
第十六章 C++语言在深度学习中的应用
开发语言·c++·深度学习
这个昵称不容易20 小时前
SpringBoot「衣依」服装销售平台:144个Java文件180个接口,从挑衣服到收货评价整条链路都在
java·springboot·毕设
计算机毕设定制辅导-无忧学长20 小时前
《基于微信小程序的居家医疗陪护预约系统设计与实现》
java·spring boot·微信小程序·uniapp·居家医疗陪护预约系统