CPU(特别是其内存控制器)可以利用内存未突变这一事实
优点是,此事实可避免访问数据时编译器使用membar指令。
内存屏障,也称为“内存屏障”,“内存屏障”或“篱笆指令”,是一种屏障指令,它使中央处理单元(CPU)或编译器对屏障指令之前和之后发出的存储器操作强制执行排序约束。这通常意味着可以保证某些操作在屏障之前执行,而其他操作则在之后执行。
内存屏障是必需的,因为大多数现代CPU都采用了性能优化,这些性能优化可能导致乱序执行。通常在单个执行线程中不会注意到这种内存操作(装入和存储)的重新排序,但是除非小心控制,否则可能导致并发程序和设备驱动程序中的行为无法预测。
您会看到,当从不同的线程访问数据时,在多核CPU上的运行情况如下:不同的线程在不同的内核上运行,每个内核都使用自己的(本地到其内核)缓存-一些全局缓存的副本。
如果数据是可变的,并且程序员需要在不同线程之间保持一致,则需要采取措施来保证一致性。对于程序员来说,这意味着在他们访问(例如读取)特定线程中的数据时使用同步构造。
对于编译器,代码中的同步构造意味着它需要插入一条membar指令,以确保正确传播(“发布”)一个内核上的数据副本所做的更改,以确保其他内核上的缓存具有相同(最新)的副本。
某种程度上的简化,请参见下面的注释,这是针对membar的多核处理器发生的情况:
- 所有内核均停止处理 -避免意外写入缓存。
- 对本地缓存所做的所有更新都被写回到全局缓存中-确保全局缓存包含最新数据。这需要一些时间。
- 更新后的数据从全局缓存写回到本地缓存-以确保本地缓存包含最新数据。这需要一些时间。
- 所有核心恢复执行。
您会看到,在全局和本地缓存之间来回复制数据时,所有内核都无所作为。这是确保可变数据正确同步(线程安全)所必需的。如果有4个核心,则所有4个将在同步缓存时停止并等待。如果有8,则所有8个停止。如果有16个……那么,您有15个内核在等待其中之一需要做的事情时完全不执行任何操作。
现在,让我们看看当数据不可变时会发生什么?无论什么线程访问它,都保证它是相同的。对于程序员来说,这意味着当它们访问(读取)特定线程中的数据时,无需插入同步结构。
对于编译器,这反过来意味着无需插入membar指令。
因此,对数据的访问不需要停止内核,也不需要等待在全局和本地缓存之间来回写数据时使用。这是不更改内存的优势。
请注意,上面的一些简化说明降低了数据可变性的一些更复杂的负面影响,例如在流水线上。为了保证所需的排序,CPU必须使受数据更改影响的堆积线无效-这是另一个性能损失。如果这通过所有管道的直接(因此可靠:)无效来实现,那么负面影响会进一步扩大。