问题标签 [memory-barriers]
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++ - 锁保护数据的缓存一致性
给定线程 TA 和 TB 在下面的 f() 中竞争:
在获得锁后,TB 如何知道他缓存的“a”副本已过时?
这就是人们多年来在没有明确使用原子或内存屏障的情况下进行编程的方式,并且一切正常。获取互斥锁(或自旋锁)是否会产生隐式内存屏障?谢谢。
编辑:也许这是互斥锁功能是否足够没有易失性的重复?.
linux - Linux内核内存屏障
我是 Linux 内核编程的新手。我对GUARANTEES章节中的内存障碍文档感到困惑。
特定 CPU 中的重叠加载和存储似乎在该 CPU 中是有序的。
CPU只会发出:
然后是另一个例子:
必须假设可以合并或丢弃重叠的内存访问。
我们可能会得到:
它们看起来一样,这两个例子有什么区别?
linux - 了解 Linux 内核循环缓冲区
有一篇文章在:http ://lwn.net/Articles/378262/描述了 Linux 内核循环缓冲区的实现。我有一些问题:
这里是“生产者”:
问题:
- 既然这段代码明确地处理了内存排序和原子性,那么 spin_lock() 的意义何在?
- 到目前为止,我的理解是 ACCESS_ONCE 停止编译器重新排序,对吗?
- producer_item(item) 是否简单地发出与该项目相关的所有写入?
- 我相信 smp_wmb() 保证produce_item(item) 中的所有写入都在随后的“发布”写入之前完成。真的?
- 我获得此代码的页面上的评论似乎暗示在更新头索引后通常需要 smp_wmb() ,但 wake_up(consumer) 会这样做,因此没有必要。真的吗?如果是,为什么?
这里是“消费者”:
特定于“消费者”的问题:
- smp_read_barrier_depends() 有什么作用?从论坛中的一些评论来看,您似乎可以在此处发布 smp_rmb(),但在某些架构上,这是不必要的(x86)且过于昂贵,因此创建了 smp_read_barrier_depends() 来选择性地执行此操作......也就是说,我真的不明白为什么 smp_rmb() 是必要的!
- smp_mb() 是否可以保证它之前的所有读取在它之后的写入之前完成?
memory-barriers - JMM 食谱混淆的内存屏障示例
我对 JMM 食谱 http://g.oswego.edu/dl/jmm/cookbook.html中的障碍示例的编译器插入感到困惑
i = u (它不涉及来自 u 的不稳定负载和正常存储到 i 中吗?)
j = b (在我看来是来自 b 的正常加载和正常存储到 j )
根据cookbook中的查表,LoadLoad和LoadStore这两个屏障是哪里来的?
谢谢!
///////////////JSR 示例 ////
易变的诠释你;
整数 i,b,j;
我=你; //加载你
j = b; //加载b
c++ - 这个内存屏障是否正确实施?
我正在阅读一个遗留 C++ 代码,其中内存屏障定义如下。主要操作系统是 linux 和 vxworks。编译器是 gcc(WindRiver 的 gcc)。
但是我看不到无操作操作如何产生内存屏障?或者这只是一个错误的实现?
java - 原始数组写入的 Java 并发可见性
我最近在我的代码库中发现了这个 gem:
这是这样使用的:
线程 1
线程 2
线程 1 是一个持续运行的后台更新线程。线程 2 是一个 HTTP 工作线程,它不关心它读取的内容是否一致或原子,只关心写入“最终”到达那里并且不会丢失作为并发神灵的祭品。
现在,这触发了我所有的警钟。自定义并发算法编写在不相关代码的深处。
不幸的是,修复代码并非易事。Java 对并发原始矩阵的支持不好。看起来解决此问题的最清晰方法是使用 a ReadWriteLock
,但这可能会对性能产生负面影响。显然,正确性更重要,但似乎我应该在将其从性能敏感区域中剥离出来之前证明这是不正确的。
根据java.util.concurrent 文档,以下创建happens-before
关系:
线程中的每个动作都发生在该线程中的每个动作之前,这些动作按程序的顺序出现在后面。
对 volatile 字段的写入发生在对同一字段的每次后续读取之前。volatile 字段的写入和读取具有与进入和退出监视器类似的内存一致性效果,但不需要互斥锁定。
所以听起来像:
- 矩阵写入发生在发布之前()(规则 1)
- publish() 发生在 syncChanges() 之前(规则 2)
- syncChanges() 发生在矩阵读取之前(规则 1)
所以代码确实已经为矩阵建立了一个happens-before链。
但我不相信。并发很难,而且我不是领域专家。我错过了什么?这真的安全吗?
c - mutex_unlock 是否起到内存围栏的作用?
我将描述的情况发生在 iPad 4 (ARMv7s) 上,使用 posix 库进行互斥锁定/解锁。不过,我在其他 ARMv7 设备上也看到过类似的事情(见下文),所以我认为任何解决方案都需要更全面地了解 ARMv7 的互斥锁和内存栅栏的行为。
场景的伪代码:
线程 1 – 生产数据:
线程 2 – 消费数据:
以前(当问题出现在 iPad 2 上时),我认为这mSharedProducerIndex = TempProducerIndex
不是原子执行的,因此改为使用AtomicCompareAndSwap
to assign mSharedProducerIndex
。到目前为止,这一直有效,但事实证明我错了,错误又回来了。我猜“修复”只是改变了一些时间。
我现在得出的结论是,实际问题是互斥锁内的写操作乱序执行,即如果编译器或硬件决定重新排序:
... 至:
...然后消费者交错生产者,当消费者试图读取数据时,数据还没有被写入。
在阅读了一些内存屏障之后,我因此认为我会尝试将信号移动到 之外的消费者mutex_unlock
,相信解锁会产生一个内存屏障/栅栏,这将确保mSharedArray
已写入:
然而,这仍然失败,并让我质疑 amutex_unlock
是否肯定会充当写栅栏?
我还阅读了 HP 的一篇文章,其中建议编译器可以将代码移入(但不能移出)crit_sec
s。因此,即使在上述更改之后,写入mSharedProducerIndex
也可能在屏障之前。这个理论有什么意义吗?
通过添加明确的栅栏,问题就消失了:
因此,我认为我理解这个问题,并且需要围栏,但是任何对解锁行为以及为什么它似乎没有执行屏障的洞察都会非常有用。
编辑:
关于消费者线程中缺少互斥锁:我依赖于int mSharedProducerIndex
单个指令的写入,因此希望消费者能够读取新值或旧值。两者都是有效状态,并且如果mSharedArray
按顺序编写(即在编写之前mSharedProducerIndex
),这将是可以的,但从目前所说的来看,我无法对此作出答复。
按照同样的逻辑,当前的屏障解决方案似乎也存在缺陷,因为mSharedProducerIndex
写入可能会移动到屏障内,因此可能会被错误地重新排序。
是否建议向消费者添加一个互斥锁,只是作为一个读取屏障,或者是否有一个pragma
or 指令来禁用生产者上的乱序执行,比如EIEIO
在 PPC 上?
multithreading - 英特尔 SFENCE 是否具有发布语义?
获取和释放语义的公认定义似乎是这样的:(引自http://msdn.microsoft.com/en-us/library/windows/hardware/ff540496(v=vs.85).aspx)
如果其他处理器总是在任何后续操作的效果之前看到它的效果,则该操作具有获取语义。如果其他处理器将在操作本身的效果之前看到每个先前操作的效果,则该操作具有释放语义。
我已经简要了解了半内存屏障的存在,并且据说它们具有遵循上述相同语义的获取屏障和释放屏障的味道。
查找我遇到 SFENCE 的硬件指令的真实示例。这个博客(http://peeterjoot.wordpress.com/2009/12/04/intel-memory-ordering-fence-instructions-and-atomic-operations/)说这是一种释放栅栏/屏障:
Intel 提供双向栅栏指令 MFENCE、获取栅栏 LFENCE 和释放栅栏 SFENCE。
但是阅读 SFENCE 的定义,它似乎没有提供释放语义,因为它根本不与负载同步?而据我了解,发布语义定义了所有内存操作(加载和存储)的顺序。
winapi - 具有进程间(非)同步多线程访问的 CreateFileMapping 和 MapViewOfFile?
我使用共享内存区域将 som 数据获取到第二个进程。
第一个过程使用和。CreateFileMapping
(INVALID_HANDLE_VALUE, ..., PAGE_READWRITE, ...)
MapViewOfFile
( ... FILE_MAP_WRITE)
第二个过程使用和。OpenFileMapping
(FILE_MAP_WRITE, ...)
MapViewOfFile
( ... FILE_MAP_WRITE)
文档状态:
如果文件映射对象的多个视图在指定时间包含相同的数据,则它们是一致的。如果文件视图派生自同一文件支持的任何文件映射对象,则会发生这种情况。(...)
除了一个重要的例外,从由同一文件支持的任何文件映射对象派生的文件视图在特定时间是连贯的或相同的。对于进程内的视图和由不同进程映射的视图,一致性得到保证。
异常与远程文件有关。(...)
由于我只是按原样使用共享内存(由分页文件支持),我会假设进程之间需要一些同步才能看到另一个进程写入的内存的一致视图。但是我不确定究竟需要什么同步。
我目前的模式(简化)是这样的:
这是否足够同步,即使对于共享内存也是如此?
两个进程之间通常需要什么同步?
请注意,在单个进程内部,对的调用SetEvent
肯定会构成一个完整的内存屏障,但我并不完全清楚这是否适用于跨进程的共享内存。
c++ - 如何为类 x86 系统实现 C++11 内存屏障?
我对 C++11 的std::memory_order
类型有很好的概念性理解(宽松vs获取发布vs顺序一致......),但我想更好地理解它们通常是如何(由编译器)为 x86 实现的(或 x86_64) 目标。
memory_order_consume
具体来说,比较每个顺序约束( 、memory_order_acquire
、memory_order_release
和)的低级细节(例如用于在处理器之间同步状态或缓存的重要内存相关 CPU 指令memory_order_seq_cst
)。
请提供尽可能多的底层细节,最好是x86_64或类似架构。您的帮助将不胜感激。