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