如果两个线程读取和写入同一块内存会发生什么

che*_*kow 7 concurrency memory-access

我的理解是,如果两个线程从同一块内存中读取,并且没有线程正在写入该内存,那么操作是安全的.但是,我不确定如果一个线程正在读取而另一个正在写入会发生什么.会发生什么?结果是否未定义?或者阅读是否陈旧?如果陈旧的读取不是一个问题,是否可以对变量进行非同步读写?或者数据是否可能被破坏,读取和写入都不正确,在这种情况下应该始终同步?

我想说我已经知道这是后一种情况,内存访问的竞争使状态未定义......但我不记得我在哪里学到了这些并且我很难找到在谷歌上回答.我的直觉是变量在寄存器中操作,并且真实(如在硬件中)并发是不可能的(或者是它),因此可能发生的最坏情况是陈旧数据,即以下内容:

WriteThread: copy value from memory to register
WriteThread: update value in register
ReadThread:  copy value of memory to register
WriteThread: write new value to memory
Run Code Online (Sandbox Code Playgroud)

此时读取线程具有陈旧数据.

Ira*_*ter 10

通常,存储器以CPU架构确定的原子单位读取或写入(32位和64位项目在32位和64位边界上对齐这些天很常见).

在这种情况下,发生的情况取决于正在写入的数据量.

让我们考虑32位原子读/写单元的情况.

如果两个线程将32位写入这样一个对齐的单元格中,那么绝对定义会发生什么:保留两个写入值中的一个.不幸的是你(好吧,程序),你不知道哪个值.通过极其聪明的编程,您实际上可以使用读取和写入的原子性来构建同步算法(例如,Dekker的算法),但通常使用体系结构定义的锁更快.

如果两个线程编写更比一个原子单元(例如,他们都写了128位值),那么实际上的原子单元大小的块写入将被存储在一个绝对明确的道路价值观,但你不会知道哪个哪些值以什么顺序写入.因此,最终存储的是来自第一个线程,第二个线程或两个线程的原子单元大小的位混合的值.

类似的想法适用于一个线程读取,一个线程以原子单位写入,并且更大.

基本上,您不希望对内存位置进行不同步的读写操作,因为您不会知道结果,即使它可能由架构很好地定义.


Jer*_*fin 9

结果未定义.数据损坏完全是可能的.举一个明显的例子,考虑一个由32位处理器操纵的64位值.假设该值是一个简单的计数器,当低32位包含0xffffffff时,我们递增它.增量产生0x00000000.当我们检测到它时,我们增加上面的单词.但是,如果某个其他线程在低位字递增和高位字递增的时间之间读取值,则它们会得到一个带有未递增的高位字的值,但是低位字设置为0 - 一个完全不同的值从增量完成之前或之后的情况来看.

  • 这是完全有道理的。非常感谢。不是吹毛求疵,而是为了理解起见,假设我知道我使用的是 32 位处理器并且我的变量是 32 位(或更少)。如果只有一个线程在写,其他线程在读,是否还有数据损坏的可能?换句话说,您提供的示例是*唯一*问题吗? (2认同)
  • 如果您的计算机提供32位原子写操作,并且仅一个线程写操作,那么另一个线程看到的值就是旧值或新值。这是Dekker算法的基础。 (2认同)