问题标签 [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.
memory - 彼得森算法关于锁中的数据修改对使用 mfence/lfence/sfence 的第二个线程可见
https://www.justsoftwaresolutions.co.uk/threading/petersons_lock_with_C++0x_atomics.html
我写了评论,问了两个问题,对安东尼的回复还有另一个问题。
这是回复:
"1. flag0和flag1变量上的acquire/release是必要的,以确保它充当锁:unlock中的release store与next lock中的acquire-load同步,以确保在锁的同时修改数据被持有的现在对第二个线程可见。”
我用 C 写了一个彼得森锁
我测试了它,我认为它是正确的,对吧?
如果正确,我的问题是我是否需要添加 sfence 和 lfence 以“确保在持有锁时修改的数据现在对第二个线程可见”?像这样,
我认为没有必要这样做。我的理解是,在 x86/64 上,'store' 有一个释放语义,'load' 有一个获取语义(根本原因是在 x86/64 上只有 store 加载重新排序),并且 'lock.flag[id]= false' 是一个'store','lock.flag[1 - id]' 是一个'load',所以在 Dmitriy 的实现中不需要对 flag0 和 flag1 做获取/释放之类的事情
编辑@Anthony 非常感谢您的重播。是的,我需要避免编译器重新排序。那么,像下面这样的修改,是否正确?因为对于 x86,只需要在 'peterson_unlock' 中禁止编译器重新排序
opencl - OpenCL 1.2:mem_fence() 或 barrier() 或两者兼有
我刚刚开始 openCL C 编程。工作组的所有工作项都会更新本地内存的唯一位置。稍后,一个工作项的私有变量会根据其他两个工作项更新的本地数据进行更新。像这样的东西:
尽管上面的代码片段是保守的,但屏障不会像它在内部做击剑那样完成这项工作吗?
c# - C# volatile 变量:内存栅栏 VS。缓存
所以我研究了这个话题很长一段时间,我想我理解了最重要的概念,比如释放和获取内存栅栏。
volatile
但是,对于主存的缓存和缓存之间的关系,我还没有找到令人满意的解释。
因此,我了解对字段的每次读取和写入都会volatile
强制执行严格的读取顺序以及在它之前和之后的写入操作(读取-获取和写入-释放)。但这只能保证操作的顺序。它没有说明这些更改对其他线程/处理器可见的时间。特别是,这取决于刷新缓存的时间(如果有的话)。我记得曾经读过 Eric Lippert 的评论,他说“volatile
字段的存在会自动禁用缓存优化”。但我不确定这到底意味着什么。这是否意味着整个程序的缓存完全禁用,因为我们只有一个volatile
某处的领域?如果不是,禁用缓存的粒度是多少?
另外,我读了一些关于强易失性语义和弱易失性语义的文章,并且 C# 遵循强语义,无论它是否是一个volatile
字段,每次写入都将始终直接进入主内存。我对这一切感到非常困惑。
c++ - 多线程环境中初始化的内存语义(C++)
我不确定 C++ 初始化过程的内存语义。假设我们有以下程序。
新线程会看到正确初始化的数组吗?或者我是否需要在两者之间插入某种内存屏障。C++ 语言如何定义初始化的内存语义?
我担心的是对数组a[10] 的所有写入都可能位于一个 cpu 的写入缓冲区中,并且我们在不同的 cpu 上启动一个新线程,这可能不会观察到初始化写入。
我们是否需要用于初始化的内存栅栏才能被稍后在不同 CPU 上运行的线程观察到?
c++ - 如果我在 _mm_clflushopt() 之后不发出 _mm_sfence() 会发生什么(坏事)?
在释放内存之前,我正在从 CPU 缓存中清除内存范围。理想情况下,我只想放弃这些缓存行而不将它们保存到内存中。因为没有人会使用这些值,而谁再次获得该内存范围(在malloc()
/ new
/_mm_malloc()
等之后)将首先用新值填充内存。正如这个问题所暗示的,目前似乎没有办法在 x86_64 上实现理想。
因此我在做_mm_clflushopt()
. 据我了解,在_mm_clflushopt()
我需要调用_mm_sfence()
以使其非临时存储对其他内核/处理器可见之后。但在这种特定情况下,我不需要它的商店。
所以,如果我不打电话_mm_sfence()
,会不会有什么不好的事情发生?例如,如果其他一些核心/处理器设法足够快地再次分配该内存范围,并开始用新数据填充它,是否会发生新数据同时被当前核心刷新的旧缓存覆盖?
编辑:快速的后续分配不太可能,我只是在描述这种情况,因为我需要程序在那里也正确。
c++ - C++ 无锁队列与多线程崩溃
我试图在为多线程编码时更好地理解控制内存顺序。我过去经常使用互斥锁来序列化变量访问,但我试图尽可能避免使用互斥锁以提高性能。
我有一个指针队列,可能被许多线程填充并被许多线程消耗。它适用于单个线程,但当我使用多个线程运行时会崩溃。看起来消费者可能会得到指针的重复,这导致它们被释放两次。有点难以判断,因为当我输入任何打印语句时,它运行良好而不会崩溃。
首先,我使用预先分配的向量来保存指针。我保留 3 个原子索引变量来跟踪向量中需要处理的元素。值得注意的是,我尝试使用 _queue 类型,其中元素本身是原子的,但这似乎没有帮助。这是更简单的版本:
并且来自同一个班级
我应该强调,我真的很想了解为什么这不起作用。实施其他一些预制包可以让我克服这个问题,但不会帮助我避免以后再次犯相同类型的错误。
更新 我将 Alexandr Konovalov 的回答标记为正确(请参阅我在下面的回答中的评论)。如果有人遇到此页面,“写入”部分的更正代码是:
java - 非易失性写入的可见性
假设我有一个int
影响类行为的静态。
系统中只有一个线程发生了变化classFlag
,并且/*myFlag-dependent behaviour*/
不需要classFlag
所有线程立即看到更新。
因此,我想保留classFlag
非易失性以避免引入昂贵且完全不必要的内存屏障。
我可以依靠更新来classFlag
最终可见吗?
c++ - 原子写入之后对同一变量进行原子读取的屏障有多有效?
考虑以下:
我的想法是 var 的虚拟负载应该防止 foo 和 bar 的后续变量访问在存储之前被重新排序。
代码似乎为重新排序设置了障碍——至少在 x86 上,发布和获取不需要特殊的屏蔽指令。
这是编写完整围栏(LoadStore/StoreStore/StoreLoad/LoadLoad)的有效方法吗?我错过了什么?
我认为该版本创建了 LoadStore 和 StoreStore 障碍。获取创建了一个 LoadStore 和 LoadLoad 屏障。并且两个变量访问之间的依赖关系创建了一个 StoreLoad 屏障?
编辑:将障碍改为全围栏。制作片段 C++。
c++ - std::mutex 是否足以使所有先前的读写发生在同一线程中的所有读写操作之前?
以下函数是否总是在写入 y[100] 之前写入 x[100]?
或者即使对于这种单线程场景,也总是需要在端点之后解锁互斥锁,还是我们必须使用 atomic_thread_fence?
我的目的是告诉 CPU 和编译器,它们不允许在同步点周围重新排序任何加载/存储,以便在任何 y 数组操作开始之前完成所有 x 数组操作。我需要分离读/写块,以便像Kahan-Summation这样的算法不会被编译器或 CPU 的重新排序破坏。
c++ - C++ 中的 std::memory_order 究竟提供了哪些栅栏?
据我所知 std::memory_order 枚举提供内存栅栏,但我需要确定每个 std::memory_order 枚举元素提供的栅栏。下面我解释一下,因为我了解每个 std::memory_order 枚举元素:
- std::memory_order_relaxed - 没有提供栅栏
- std::memory_order_acquire - LoadLoad_LoadStore
- std::memory_order_release - LoadStore_StoreStore
- std::memory_order_consume - 通常等于 memory_order_acquire
- std::memory_order_acq_rel - LoadLoadLoadStore_LoadStoreStoreStore ???
- std::memory_order_seq_cst - StoreLoad_StoreLoad ???
关于前 4 个元素,我不确定。但是关于最后两个元素,我什么都不知道。
任何人都知道吗?
另外,我需要知道在使用 std::atomic 或 std::atomic_flag 时编译器将内存栅栏放在哪个位置?
据我了解,使用原子栅栏意味着应用栅栏并执行操作。我对吗?例如:
意味着应用 memory_order_acquire 围栏并以原子方式加载数据?