问题标签 [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.

0 投票
1 回答
59 浏览

c++ - 子功能中的内存栅栏与数据更改时相同的功能

如果我在子函数中而不是在使用数据的函数中放置内存栅栏,线程安全性是否存在差异。底部示例包括两个版本。我想知道是否有我不知道的差异。功能A_functionB_function同样线程安全吗?

0 投票
1 回答
79 浏览

c++ - 互斥保护块中的同步模式

http://www.boost.org/doc/libs/1_58_0/doc/html/atomic/usage_examples.html

在上述boost示例的“具有双重检查锁定模式的单例”示例中,_instance的第二次加载的memory_order_consume和_instance的存储的memory_order_release是否必要?我认为 scoped_lock 已经具有获取和释放语义,并且 _instance 的第一次加载具有同步模式 memory_order_consume。

0 投票
1 回答
84 浏览

c++ - 两个线程访问相同的变量,但很少发生一个线程。非原子?

我有两个线程 t1 和 t2,它们访问多个变量(整数和双精度数),我们称它们为 a、b 和 c。t1 在我的关键路径上,并通过昂贵的比较和交换来增加/减少这些变量。

t2 很少发生,但当它发生时,它会将上面提到的变量加在一起。

目前我使用原子。有什么方法可以将变量声明为非原子的,因为 99.999% 的时间它们是从同一个线程和“稀有线程”递增的,我可以使用内存屏障来确保a + b - c在“关键路径”之前无法返回"线程已经写完任何存储?

这将允许我仅在罕见线程执行的偶尔情况下添加延迟。

0 投票
2 回答
1092 浏览

java - Java Unsafe.storeFence() 文档错误?

Java 8 为sun.misc.Unsafe.

阅读他们的文档后,我感到很困惑。

所以,我在网上搜索,找到了这个链接

根据上面的页面,我相信这些方法在实践中几乎没有添加任何东西。如果我错了,请纠正我,粗略地说,loadFence()、storeFence() 和 fullFence() 分别对应于 volatile read、lazy write 和 volatile write,尽管从技术上讲,这些栅栏比 volatile 变量更强大。所以 loadFence() 是一个获取栅栏, storeFence() 是一个释放栅栏,而 fullFence() 是完整栅栏。

但是 storeFence() 的文档看起来很奇怪。

它说,

这看起来不像是释放围栏。它应该如何使用?难道不应该

我假设之前意味着更早,之后意味着更晚。

编辑

当我说这些“围栏在实践中没有添加任何内容”时,我并不是说“我们不会在通常的开发中使用它们”。

我的意思是,即使在 Unsafe 中没有这些方法,我们也可以获得这些“栅栏”。如果我是正确的,在实践中,读取虚拟 volatile 具有 loadFence() 的效果,写入虚拟 volatile 具有 fullFence() 的效果,而 unsafe.putOrderedXXX()(或 AtomicInteger.lazySet())具有效果storeFence() 的。

它们可能有细微的差别,但在当前的实现中,它们是可交换的。(似乎由链接暗示)

这就是我所说的“他们没有添加任何新内容”的意思。

另一个编辑

这已经修复了。

https://bugs.openjdk.java.net/browse/JDK-8038978

谢谢@john-vint

0 投票
1 回答
444 浏览

c# - Is a memory fence required here?

Basically I have the following situation:

Another thread can do stuff like this:

Objects like 'Obj' are only written once, then read by multiple threads (multiple times).

I know that Obj is never null in both threads; I also don't care about the synchronization of 'this.Obj'. What I do care about is that once I read the reference tmp = Obj, the contents (e.g. A and B) are also valid.

My question is: Do I need memory barriers (e.g. Thread.MemoryBarrier();) at the above marked positions to ensure that or is this always implicitly OK?


It seems that people dislike this question.

My question originates from the following. I've read up on memory fences and they guarantee: (quote)

The processor executing the current thread cannot reorder instructions in such a way that memory accesses prior to the call to MemoryBarrier execute after memory accesses that follow the call to MemoryBarrier.

If you look at the code, the CPU / compiler might be able to re-write the code:

and worse:

If another thread picks up the last case, it can read this.Obj from memory, while A and B still have the default value.

Note that it's not just a matter of what the compiler is able to reorder; it's also a matter of what the CPU is allowed to reorder.

In other words: (Thanks @MattBurland )

Is it guaranteed that the object initializer will be run before tmp1 is assigned to this.Obj? Or do I need to use a memory fence to ensure this manually?

0 投票
2 回答
938 浏览

c++ - memory_order_relaxed 负载与易失性负载

atomic_uint用 memory_order_relaxed 读取 a 的值和读取 a 的值有什么区别volatile unsigned int(假设 volatile 操作是原子的)?

具体来说,让我们定义:

解决方案 1

  1. “writer”线程写入atomic_uint(使用任何内存顺序限定符,从 memory_order_relaxed 到 memory_order_seq_cst)
  2. “阅读器”线程在同一个线程上进行原子轻松读取atomic_uint

解决方案 2

  1. “作家”线程写入volatile unsigned int
  2. “读者”线程读取该值

按原样,我知道这两种情况都不能保证读者能够读取作者写入的值。我想了解的是易失性读取和轻松原子读取之间的区别。在考虑写后读一致性时,一个提供什么而另一个不提供什么?

我看到的唯一区别是:

  • volatile 操作不能在它们之间重新排序,而原子负载可以与其他原子操作重新排序

还有别的吗?

0 投票
2 回答
1441 浏览

c++ - 易失性与内存栅栏

下面的代码用于将工作分配给多个线程,唤醒它们,并等待它们完成。在这种情况下,“工作”包括“清理卷”。这个操作到底做了什么与这个问题无关——它只是有助于上下文。该代码是一个庞大的事务处理系统的一部分。

布尔数组中的值_requested_volumes[i]告诉线程是否i有工作要做。完成后,工作线程将其设置为 false 并重新进入睡眠状态。

我遇到的问题是编译器生成一个无限循环,其中变量remains始终为真,即使数组中的所有值都已设置为假。这只发生在-O3.

我尝试了两种解决方案来解决这个问题:

  1. 声明_requested_volumes易失性(编辑:此解决方案确实有效。请参阅下面的编辑)

很多专家表示,volatile与线程同步无关,应该只用在低级硬件访问中。但网上对此有很多争议。我理解它的方式是, volatile 是避免编译器优化对在当前范围之外更改的内存的访问的唯一方法,无论并发访问如何。从这个意义上说,volatile应该可以解决问题,即使我们对并发编程的最佳实践存在分歧。

  1. 引入内存栅栏

该方法在内部wakeup_cleaners()获取 apthread_mutex_t以便在工作线程中设置唤醒标志,因此它应该隐式生成适当的内存栅栏。但我不确定这些栅栏是否会影响调用方方法 ( force_all()) 中的内存访问。因此,我在上面注释指定的位置手动引入了栅栏。这应该确保工作线程执行的写入_requested_volumes在主线程中可见。

令我困惑的是,这些解决方案都不起作用,我完全不知道为什么。内存栅栏和易失性的语义和正确使用现在让我感到困惑。问题是编译器正在应用不需要的优化——因此是不稳定的尝试。但这也可能是线程同步的问题——因此是内存栅栏尝试。

我可以尝试第三种解决方案,其中互斥锁保护_requested_volumes对 . 因此,无论是通过互斥体显式还是隐式完成,都应该没有区别。


编辑:我的假设是错误的,解决方案 1确实有效。但是,我的问题仍然是为了澄清易失性与内存围栏的使用。如果 volatile 是一件坏事,那不应该在多线程编程中使用,我还应该在这里使用什么?内存栅栏也会影响编译器优化吗?因为我认为这是两个正交的问题,因此也是正交的解决方案:用于多线程可见性的栅栏和用于防止优化的 volatile。

0 投票
0 回答
54 浏览

c++ - 双重检查锁定*除了*单例

我已经在互联网上搜索了一段时间,以找到关于不涉及单例模式的 DCL 的讨论。所以相反,我只想问我想知道什么。

DCL在这里合适吗?

任何作家*mybool_smart_ptr都这样做是无锁的。产生的线程所做的工作是全部或全部,这就是它们所等待的。

0 投票
0 回答
271 浏览

c++ - 我需要加载和存储内存屏障(栅栏),还是仅仅一个存储屏障就足够了?

我有std::atomic<int>* key, *val;

我想给两者都写信。有多个线程同时读取这些值。我想确保 val 写在 key 之前。这是确保如果读者看到 key 的新值,他们也必须看到 val 的新值。用旧键查看新 val 或查看两个旧值都很好。代码必须在宽松的处理器架构 (ARM) 上运行。

val->store(x, relaxed), key->store(y, release)通常,执行 (in-order)并使用 (in-order) 加载它们就足够了key->load(acquire), val-load(relaxed)。在 ARM 上,我相信获取插入了一个负载屏障,而释放插入了一个存储屏障。但是,由于各种原因,我没有使用 atomic 来读取 val,并且在每次读取访问时使用屏障会太昂贵。

是否可以在两个商店之间仅使用商店屏障(x86 上的 sfence)来强制订购?请记住,看到 key 和 val 的陈旧值是非常好的,我要确保的是,如果另一个核心看到 key 的新值,它也必须看到 val 的新值。读者总是先读取 key 并且 val 的读取取决于 key 的值(即使它的内存地址也是如此),所以我不相信编译器或处理器都可以重新排序负载使得 val 是在关键之前阅读。它必须读取 key 才能知道在哪里寻找 val。我怀疑正是这个属性允许代码在没有负载障碍的情况下工作。

我对吗?

0 投票
1 回答
137 浏览

multithreading - 释放锁之前的内存栅栏

在 x86-64 上,我对关键部分使用简单的自旋锁:

并退出cs:

在解锁之前是否需要栅栏指令,以便刷新临界区中的存储操作?