问题标签 [memory-fences]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
c++ - C ++ 0x并发同步,是否需要围栏
我最近问了一些关于原子和 C++0x 的问题,我想确保在转换任何代码之前了解排序语义。假设我们有这个 pre-0x 代码:
使用您当前的编译器/平台为您提供的任何atomic_int
,atomic_store_fence
和atomic_load_fence
.
在 C++0x 中,代码有几种可能的形式。两个明显的似乎是:
或者
我是否正确地阅读了原子存储释放/加载获取序列是一个同步事件,它与显式围栏版本具有相同的内存顺序含义?也就是说,第二个版本是否正确?
如果正确,则第二个问题超出必要的范围:即使a != 1
. 标准的第 29.8-3 节表明我可以混合和匹配原子和栅栏。那么以下是正确合理的实现吗?
multithreading - __faststorefence 的行为是什么?
关于这个问题,我只对 x86 和 x86-64 感兴趣。
对于 MSVC 2005, __faststorefence 的文档说:“保证每个先前的存储在任何后续存储之前都是全局可见的。”
对于 MSVC 2008 和 2010,它更改为:“保证每个先前的内存引用,包括加载和存储内存引用,在任何后续内存引用之前都是全局可见的。”
后者的编写方式,在我看来这意味着这也会阻止 CPU 在旧存储之前对负载进行重新排序。这与第一个定义不同,这意味着内在函数仅用于处理阻塞或非临时存储与旧存储的重新排序(x86(-64)唯一的其他重新排序)。
但是,文档似乎自相矛盾:“在 x64 平台上,此例程生成的指令比sfence指令更快的存储栅栏。在 x64 平台上使用此内在函数而不是 _mm_sfence。”
这意味着它仍然具有类似 sfence 的功能,因此仍然可以使用旧商店重新排序加载。那么它是哪一个?有人可以解决我的困惑吗?
PS:寻找这个函数的GCC版本,我遇到了,long local; __asm__ __volatile__("lock; orl $0, %0;" : : "m"(local));
但我认为它来自32位代码;什么是 64 位模拟?
c++ - Windows+VisualC 上的 volatile 读写是原子的吗?
该站点上有几个问题询问是否可以使用volatile
变量进行原子/多线程访问:例如,请参见此处、此处或此处。
现在,符合 C(++) 标准的答案显然是no。
但是,在 Windows 和 Visual C++ 编译器上,情况似乎并不那么清楚。
微软特定
声明为 volatile 的对象是 (...)
- 对 volatile 对象的写入(volatile write)具有 Release 语义;对全局或静态对象的引用?在指令序列中写入易失性对象之前发生的事件将发生在已编译二进制文件中的易失性写入之前。
- 对 volatile 对象的读取(volatile read)具有 Acquire 语义;对全局或静态对象的引用 ?在指令序列中读取易失性存储器之后发生的情况将发生在已编译二进制文件中的易失性读取之后。
这允许易失性对象用于多线程应用程序中的内存锁定和释放。
[强调我的]
现在,阅读本文,在我看来,MS 编译器std::atomic
将像在即将到来的 C++11 标准中一样处理 volatile 变量。
然而,在对我的回答的评论中,用户Hans Passant写道:“那篇 MSDN 文章非常不幸,它是大错特错。你不能用 volatile 实现锁,即使是微软的版本也不能。(...)”
请注意:MSDN 中给出的示例看起来很可疑,因为您通常无法在没有 atomic exchange的情况下实现锁。(正如亚历克斯也指出的那样。)这仍然留下了问题。对于这篇 MSDN 文章中给出的其他信息的有效性,尤其是对于像这里和这里这样的用例。)
此外,还有 The Interlocked* 函数的文档,尤其是InterlockedExchange
使用volatile(!?)变量并进行原子读写。(请注意,我们对 SO 提出的一个问题—— 何时应使用 InterlockedExchange? ——并没有权威地回答只读或只写原子访问是否需要此函数。)
更重要的是,volatile
上面引用的文档以某种方式暗示了“全局或静态对象”,我认为“真正的”获取/释放语义应该适用于所有值。
回到问题
在 Windows 上,使用 Visual C++ (2005 - 2010),将声明一个 (32bit?int?) 变量以volatile
允许对该变量进行原子读取和写入 - 或不?
对我来说特别重要的是,这应该在 Windows/VC++ 上保持(或不)独立于程序运行的处理器或平台。(也就是说,在 Itanum2 上运行的是 WinXP/32bit 还是 Windows 2008R2/64bit?)
请用可验证的信息、链接、测试用例来支持您的答案!
c - 乱序执行和内存栅栏
我知道现代 CPU 可以乱序执行,但是它们总是按顺序退出结果,如 wikipedia 所述。
“Out of Oder 处理器及时用其他准备好的指令填充这些“插槽”,然后在最后对结果重新排序,以使指令看起来像正常处理。
现在据说在使用多核平台时需要内存栅栏,因为由于乱序执行,可以在此处打印错误的x值。
现在我的问题是,由于乱序处理器(我假设多核处理器的核心)总是按顺序退出结果,那么内存栅栏的必要性是什么。多核处理器的内核是否只看到从其他内核退出的结果,或者它们也看到正在进行的结果?
我的意思是在我上面给出的示例中,当处理器 2 最终将退出结果时,x的结果应该在f之前,对吗?我知道在乱序执行期间,它可能在x之前修改了f ,但它一定没有在x之前退休,对吧?
现在有了按顺序退出结果和缓存一致性机制,为什么在 x86 中还需要内存栅栏?
opencl - 在 OpenCL 中,mem_fence() 与 barrier() 相比做什么?
不像barrier()
(我想我理解),mem_fence()
不会影响工作组中的所有项目。OpenCL 规范说(第 6.11.10 节),用于mem_fence()
:
订购执行内核的工作项的加载和存储。
(因此它适用于单个工作项)。
但是,与此同时,在第 3.3.1 节中,它说:
在工作项内存中具有加载/存储一致性。
所以在一个工作项中,内存是一致的。
那么什么样的东西mem_fence()
有用呢?它不适用于项目,但在项目中不需要......
请注意,我没有使用原子操作(第 9.5 节等)。mem_fence()
是与这些结合使用的想法吗?如果是这样,我很乐意看到一个例子。
谢谢。
更新:我可以看到它在与 barrier()
(隐含地,因为屏障调用mem_fence()
)一起使用时是如何有用的——但肯定有更多,因为它是单独存在的?
c++ - 使用 xchg 时是否需要 mfence
我有一套基于测试xchg
的装配锁。我的问题是:
使用指令时是否需要使用内存围栏(mfence
或sfence
)lfence
?xchg
编辑 :
64 位平台:采用 Intel nehalem
c++ - 在 C++ 程序中使用电围栏
我最近一直在试验 Electric Fence,但我不知道如何将它与 c++ 代码一起使用。
这是一个例子:
我用它编译了
而且我在开始时没有看到 Electric Fence 横幅,并且在可执行文件中找不到 EF 符号(使用 nm 命令)。
但是,如果我像这样修改程序:
一切都很好——EF 出现了。我知道它有点解决问题,我知道:)。我只是想了解为什么它一开始就不起作用,因为new()
应该调用malloc()
和delete()
调用free()
,不是吗?
我进入这个项目的原因是一个使用boost库和其他几个库的大项目。而且这个程序从不调用malloc()
或free()
直接调用。当我用 EF 构建它时,我不仅将 EF 链接到最终的可执行文件,而且重建了所有试图将 EF 链接到它们的库。而且我在其中任何一个中都找不到 EF 符号。这是正确的方法吗?或者是错误的,EF 最终应该只链接到可执行文件,库应该保持不变?但是我再次在可执行文件中找不到 EF 符号。
c++ - std::call_once 和内存重新排序
鉴于此处的代码:
我在其他地方也看到了相同模式的一些变体。所以我的问题是:为什么这段代码被认为是保存?为什么编译器不能在调用 std::call_once 之前读取数据并最终得到不正确的数据?例如
我的意思是我没有发现任何可以阻止这种情况的障碍。
multithreading - 我应该在主管-工作者模型中使用内存栅栏吗?
我正在为我的应用程序构建多线程支持。
在我的应用程序中,一个工作人员可能会访问另一个工作人员的“工作区”来完成自己的工作。我曾尝试使用 pthread 互斥锁来确保这一点安全,但结果证明它们非常慢,即使只有一个工作人员并且没有争用。
所以,我想出了另一个主意。让一个worker在可能的地方完成它的工作,然后将存在上述问题的工作添加到(per-worker,own)队列中:当所有工作人员都完成后,主监督线程将完成未完成的工作,在希望它们将比工人完成的工作数量少几个数量级。
我的问题是:在我将执行从主管转移到工人的那一刻,我是否应该设置记忆栅栏,反之亦然?
编辑:更多细节(代码在github 上,参见 pool::collision_wsc())。每个线程从各种“单元”(基本上是 std::vector)读取指针,并对指向的对象应用一些操作(硬球体之间的碰撞)。
关键是一个细胞与它的(一些)邻居交互,但其中一些细胞可能是另一个工人的所有权(一个球体可能靠近一个细胞的边界,并与另一个细胞中的一个发生碰撞)。
synchronization - 对 pthread 互斥体所涉及的完整内存屏障的说明
我听说在处理互斥体时,必要的内存屏障由 pthread API 本身处理。我想了解更多关于这个问题的细节。
- 这些说法是真的吗,至少在最常见的架构上是这样吗?
- 编译器是否识别此隐式障碍,并在生成代码时避免重新排序操作/从本地寄存器读取?
- 何时应用内存屏障:在成功获取互斥锁之后并在释放它之后?