什么是使用显式内存屏障?
为获得更好的性能,现代CPU通常会乱序执行指令以充分利用可用的硅(包括内存读/写)。由于硬件执行指令的完整性,您在单个执行线程中永远不会注意到这一点。但是,在多个线程或具有易失性内存的环境下(例如内存映射I/O),这可能导致不可预测的行为。
内存屏障是一类指令,意味着内存读/写按照您期望的顺序发生。例如,“全屏障”表示屏障之前的所有读/写在屏障之后提交。
请注意,内存屏障是硬件概念。在更高级别的语言中,我们习惯处理互斥锁和信号量 - 这些可能在低级别上使用内存屏障来实现,并且不需要明确使用内存屏障。使用内存屏障需要对硬件架构进行仔细研究,而不是应用程序代码中常见的设备驱动程序。
CPU重排序与编译器优化不同-尽管它们的效果可能相似。如果编译器重新排序您的指令可能会导致不希望的行为,需要采取单独的措施来阻止编译器重新排序(例如,在C中使用volatile关键字)。
将我的答案复制到另一个问题中,有哪些处理器用于优化代码的技巧?:
最重要的是内存访问重排序。
在缺少内存栅栏或序列化指令的情况下,处理器可以自由地重新排序内存访问。一些处理器体系结构对它们可以重新排序的限制有所不同;Alpha被认为是最弱的(即可以重新排序最多的处理器)。
该主题的非常好的论述可以在Linux内核源文档中找到,位于Documentation/memory-barriers.txt。
大多数时候,最好使用来自编译器或标准库的锁原语;这些经过充分测试,应该具有所有必要的内存屏障,并且可能已经相当优化了(优化锁定原语很棘手;即使专家有时也会出错)。
根据我的经验,它指的是一个内存屏障(memory barrier),它是一种同步多个线程之间内存访问的指令(显式或隐式)。
问题出现在现代的激进编译器和多核CPU的组合上。(编译器有极大的自由度来重新排列指令,但通常不了解你的线程)
关于这个问题的一个很好的介绍是 "'Double-Checked Locking is Broken' 声明"。对于许多人来说,这是他们开始意识到存在风险的警钟。
通常包含隐式的完整内存屏障在平台线程同步例程中,这涵盖了核心部分。然而,在无锁编程和实现自定义、轻量级同步模式时,您通常只需要该屏障,或者甚至只需要单向屏障。
内存屏障(memory barrier)也被称为membar或memory fence,是一类指令,它使得中央处理器(CPU)对在屏障指令之前和之后发出的内存操作施加排序约束。
CPU使用性能优化可以导致乱序执行,包括内存加载和存储操作。内存操作重新排序通常在单个线程执行中不会被注意到,但除非仔细控制,否则会在并发程序和设备驱动程序中引起不可预测的行为。排序约束的确切性质因硬件而异,并由体系结构的内存模型定义。有些体系结构提供多个屏障以强制执行不同的排序约束。
内存屏障通常用于实现基于内存的机器码,其操作由多个设备共享。这种代码包括在多处理器系统上的同步原语和无锁数据结构,以及与计算机硬件通信的设备驱动程序。
内存屏障
(内存栅栏
)是一种无锁机制,用于同步多线程。在单线程环境中,重排序是安全的。
问题在于排序、共享资源和缓存。处理器或编译器能够为了优化而重新排序程序指令(程序员顺序)。这会在多线程环境中产生副作用。这就是为什么引入了内存栅栏
来保证程序正常工作。它速度较慢,但可以解决这种类型的问题。