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