问题标签 [happens-before]

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 投票
2 回答
336 浏览

java - 我是否有重新排序问题,是因为引用转义吗?

我有这个类,我在其中缓存实例并在使用它们时克隆它们(数据是可变的)。

我想知道我是否可以面临重新排序的问题。

我已经看过这个答案和 JLS,但我仍然没有信心。

我的想法:运行时可以重新排序构造函数中的语句并在初始化对象之前发布当前DataWrapper实例(放入映射中) 。data第二个线程DataWrapper从映射读取实例并看到空data字段(或部分构造)。

这可能吗?如果是,是否只是由于引用转义?

如果不是,您能否解释一下如何用更简单的术语来推理发生前的一致性?

如果我这样做会怎样:

它仍然容易出现同样的问题吗?

请注意,如果多个线程尝试同时创建并放置相同值的实例,我不介意是否创建了一个或两个额外的实例。

编辑:

如果 name 和 data 字段是 final 或 volatile 怎么办?

还是不安全吗?据我了解,构造函数初始化安全保证仅适用于初始化期间引用未转义的情况。我正在寻找证实这一点的官方消息来源。

0 投票
2 回答
209 浏览

java - 如何在请求处理线程和 SocketChannel 选择器线程之间建立happens-before关系?

考虑一个请求-响应协议。

我们生成一个线程来执行一个select()循环,以便在接受的非阻塞 上进行读取和写入SocketChannel。这可能看起来像

whereContext只是相应的容器SocketChannel,缓冲区和读取它并从中写入的逻辑。可能readRequest看起来像

换句话说,我们从套接字通道读取数据,填充一些缓冲区并将处理交给其他线程。该线程进行处理并准备将其存储在响应缓冲区中的响应。然后它通知选择器它想要写入并唤醒它。

JavadocSelector#wakeup()没有提到任何发生前的关系,所以我担心选择器线程可能会看到响应缓冲区(或某些中间对象)处于不一致的状态。

这是可能的情况吗?如果是,那么将响应写入循环线程SocketChannel的正确方法是什么?Selector(通过某个字段发布响应volatile?使用SelectionKey附件?其他形式的同步?)

0 投票
3 回答
1159 浏览

go - 如何理解 golang 内存模型中的通道通信规则?

在学习golang的过程中,当我试图理解内存模型规范中描述的通道通信时,我有点困惑,如下所示:

  1. 通道上的发送发生在该通道的相应接收完成之前。
  2. 通道的关闭发生在接收返回零值之前,因为通道已关闭。
  3. 来自无缓冲通道的接收发生在该通道上的发送完成之前。
  4. 容量为 C 的通道上的第 k 次接收发生在该通道的第 k+C 次发送完成之前。

前两条规则清晰易懂,而我对第三条规则感到困惑,这似乎与其他规则相反......我是否错过了无缓冲通道的特别之处?或者我是否正确如果我像下面的规范中的示例一样采用它:

对于无缓冲通道,发送操作(B)被阻塞,直到接收器准备好接收值(A)?(如:B 开始,直到 A 执行才返回)它准确吗?

我在Effective Go 规范中找到了以下陈述,但与我的理解仍然存在差异......那么有人可以用简单明了的方式解释一下吗?

接收器总是阻塞,直到有数据要接收。如果通道没有缓冲,发送方会阻塞,直到接收方收到该值。如果通道有缓冲区,发送方只会阻塞,直到值被复制到缓冲区;如果缓冲区已满,这意味着要等到某个接收器检索到一个值。

0 投票
2 回答
416 浏览

java - Happens-before 用于直接 ByteBuffer

我在一个线程中有一个直接的 ByteBuffer(堆外),并使用 JMM 提供给我的一种机制将其安全地发布到另一个线程。之前发生的关系是否扩展到由 ByteBuffer 包装的本机(堆外)内存?如果不是,我如何安全地将直接 ByteBuffer 的内容从一个线程发布到另一个线程?

编辑

这不是Can multiple threads see writes on a direct mapped ByteBuffer in Java? 因为

  • 我说的不是 mmaped() 区域,而是一般的堆外区域
  • 我正在安全地发布 ByteBuffer
  • 我没有同时修改 ByteBuffer 的内容,我只是将它从一个线程转移到另一个线程

编辑 2

这不是使 Java 的 ByteBuffer 线程安全的选项的副本我不想同时从两个不同的线程修改 ByteBuffer。我正在尝试将是否从一个线程移交给另一个线程,并在由直接 ByteBuffer 支持的本机内存区域上获得发生前的语义。一旦移交,第一个线程将不再修改或读取 ByteBuffer。

0 投票
1 回答
391 浏览

java - 在 thread.start 之前发生的所有事情对产生的调用 start 的线程可见吗?

现在在 stackoverflow 上已经有了很好的答案,但他们没有给我想要的明确答案。

说你有一个方法

现在同时这个方法正在运行,在调用 thread.start 之前,一些全局非易失性变量 z 从 4 更改为 5。

由于 z 发生在 thread.start 之前,程序是否可以保证打印 5?

此外,如果我们以某种方式谈论它,那么可以肯定地说 thread.start() 永远无法重新排序。

就被称为 start on 的线程而言,这意味着直到该点为止的所有内容都是顺序的。例如说我们有

现在......无论是先调用 start 还是将 k 分配 8,从该线程的角度来看都不会产生影响。所以这可以重新排序,但是由于发生在保证之前,这是不可能的吗?

Java 规范并没有说一个强有力的声明。而是说

当一个语句调用 Thread.start() 时,每个与该语句有发生前关系的语句

然而 k = 8 并没有发生在与该陈述的关系之前......

我什至不确定它们是什么意思,除非您使用相同的监视器锁定,否则在与 start 方法的关系之前发生了某些事情

对于一个更可怕的情况,我们有这个代码

然后新线程碰巧发现该 con 为空?

有人可以就这些话题给我一个明确的答案吗?

0 投票
5 回答
1367 浏览

java - Java 内存模型中的发生前发生规则

我目前正在学习并发编程考试,不明白为什么这个程序的输出是43。为什么x = y + 1之前执行t.start()?我还应该解释我使用了哪些发生之前的规则。

如果我理解程序顺序规则(线程中的每个动作发生 - 在该线程中稍后在程序顺序中出现的每个动作之前)t.start()必须在之前执行,x = y + 1以便线程 t 复制变量x,该变量将为 1。

0 投票
2 回答
92 浏览

java - 我对 JSR-133 Cookbook 中的 Can Reorder 规则有正确的理解吗?

在此链接http://gee.cs.oswego.edu/dl/jmm/cookbook.html中,有一张表说明了哪些可以重新排序,哪些不能。

这是图像

在此处输入图像描述

现在看看来自http://tutorials.jenkov.com/java-concurrency/volatile.html的这句话

“之前和之后的指令可以重新排序,但易失性读或写不能与这些指令混合。”

所以例如说我有代码

从表格告诉我的内容来看,可以重新排序普通存储和可变负载,这意味着

可以重新排序为

这可能意味着程序将在重新排序的情况下打印 2 以外的内容。

这背后的原因是首先 z = 2 进行正常存储,然后 z = someVolatileIntNotTwo 进行易失性加载,然后进行正常存储。虽然不能重新排序后跟普通存储的易失性加载,但在这种情况下不会发生这种情况,因为如果重新排序,我们仍然会得到这个序列。

除了正常加载(int z = 2)和[易失性加载和正常存储](z = someVolatileIntNotTwo)被重新排序之外,第一个操作与第二个操作重新排序,根据表格很好

但是,詹科夫教程说这是不可能的。那么,谁是对的?

0 投票
1 回答
81 浏览

java - 易失性写入 = 易失性读取

我以前见过fld = fld几次类似的情况,但在所有这些情况下,可以通过更好的性能消除虚拟写入。

问题是这种虚拟写入是否有其用例,或者这是一些解决方法?对我来说,这似乎与(因为根据 JMM,没有存储和加载可以在虚拟写入中重新排序)

0 投票
2 回答
794 浏览

c++ - 为什么“获取/发布”不能保证 C++11 中的顺序一致性?

GCC Atomic Wiki段落“Overall Summary”说,上面的代码assert(x.load(memory_order_acquire))可能会失败。但我不明白为什么?

我的理解是:</p>

  1. 由于获取障碍, Thread3无法LoadLoad 重新排序。
  2. 由于释放障碍,Thread1无法StoreStore重新排序。
  3. 当 Thread2 read(x)->10 时,x 必须从 storebuffer 刷新到 Thread1 中的缓存,所以每个线程都知道 x 的值发生了变化,例如使缓存行无效。
  4. Thread3 使用Acquire屏障,因此它可以看到 x(10)。
0 投票
0 回答
74 浏览

java - Java双重检查锁单例必须使用volatile关键字?

嗨,我在单例模式中的双重检查锁定有问题。在以下代码中:

假设现在有两个线程,分别是 A 和 B。之后它们同时执行。根据happens-before的定义,一个线程释放锁后,另一个线程获取锁,那么后者可以看到之前的变化。

如果是这样,我认为不需要 volatile 关键字,那我们为什么要在这里使用 volatile 关键字呢?哪位朋友能解释一下?谢谢您的回答