问题标签 [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 回答
182 浏览

java - 如果在同步锁周围的循环中使用变量,是否会“从主内存中重新读取”​​?

0 投票
2 回答
44 浏览

java - 使用“volatile”之前发生的关系不能按预期工作

输出: pool-1-thread-1: get start
set start
set end
set start
set end
pool-1-thread-1: z is 0
pool-1-thread-1: x is 2
pool-1-thread-1: y 是 2
pool-1-thread-1: 结束

预期输出: pool-1-thread-1: get start set start
set end
set start
set end
pool-1-thread-1: z is 2
pool-1-thread-1: x is 2
pool-1-thread-1 : y 是 2
pool-1-thread-1: 结束

为什么输出不显示带有 volatile 关键字的 z 的更新值。

0 投票
0 回答
44 浏览

multithreading - 适用于动作而非语句的 Java 内存模型

我从 A. Shipilev 的博客中得知,JMM 适用于动作而不是带有下面提到的代码和语句的语句

…​他们说 g = 1 发生在 int lg = g 之前。通过逻辑上得出结论 int lx = x 将始终看到 x = 1(因为 x = 1 hb g = 1,并且 int lg = g hb int lx = x),这列火车进一步破坏了推理。这是一个非常容易犯的错误,您必须记住,happens-before(以及 JMM 形式主义中的其他顺序)适用于操作,而不是语句。

https://shipilev.net/blog/2016/close-encounters-of-jmm-kind/#pitfall-volatiles-wrong

我的印象是两者都是一样的。我是否缺少任何潜在的差异。

0 投票
1 回答
102 浏览

java - Executor 工作线程的 Java 内存一致性

根据javadoc,实现Executor必须符合:

内存一致性效果:在将 Runnable 对象提交给 Executor 之前,线程 ( A ) 中的操作发生在其执行开始之前,可能在另一个线程 ( B ) 中。

由于我的英语不好,我不清楚B和随后由A提交给同一个 Executor 的另一个潜在线程C之间的内存一致性关系(如果有的话)。我希望下面的例子能澄清我的疑问。

保证emc.a == 2线程执行emc.mr2.run()?(在我的测试中这总是正确的,但是......是的,它们是测试)如果不是,官方 API 中是否有接口可以确保emc.a == 2

0 投票
3 回答
181 浏览

c++ - 修改顺序是否有助于发生之前的关系?

我了解到,如果thread3读取thread1写入的值,则release和acquire操作是同步的,并且thread3的效果A是可见的。
但如果是这样的话怎么办:

  • 修改顺序为x1, 2
  • thread3 读取 thread2 写入的值,因此 2发生在3 之前。

1 和 3 之间是否存在发生之前的关系?
或者本质上,修改顺序是否有助于发生之前的关系?

0 投票
1 回答
171 浏览

go - go 编译器可以重新排序以下代码吗?

最近,我发现一些代码看起来像这样:

这个程序运行良好,但我认为writem函数体可以通过m = tmpm在 for 循环之前移动来重新排序,因为这不会改变这个 goroutine 中的行为。而这种重新排序将导致concurrent map read and map write问题。正如Go 内存模型所说:

只有当重新排序不会改变语言规范所定义的 goroutine 中的行为时,编译器和处理器才可以重新排序在单个 goroutine 中执行的读取和写入

我是对的,还是这样写代码是安全的?

0 投票
1 回答
248 浏览

language-lawyer - 为什么这个包含两个 volatile 写入数据的 Java 程序没有竞争?

考虑以下 Java 程序:

因为shared被标记volatile,我想说这个程序没有数据竞争。但是,如何基于 JLS(例如,版本 11)来激发这一点?

第 17 章告诉我们:

当一个程序包含两个冲突的访问(第 17.4.1 节)时,这些访问没有按发生前的关系排序,则称为包含数据竞争。

我认为这是 JLS 提供的数据竞争的定义。然后我们有第 17.4.1 节告诉我们:

如果至少有一次访问是写入,则对同一变量的两次访问(读取或写入)称为冲突。

好的,所以我们在这里有冲突的访问,因为我们有两次写入shared. 现在我们必须在两个写入之间建立起之前发生的关系,否则我们就会有比赛。然而,我没有设法找到为什么我们在这里有这种关系。第 17 章告诉我:

如果动作 x 与后续动作 y 同步,那么我们也有 hb(x, y)。

同一章告诉我:

对 volatile 变量 v(第 8.3.1.4 节)的写入与任何线程对 v 的所有后续读取同步(其中“后续”根据同步顺序定义)。

但是在将写入关联到 volatile 变量之前,我还没有发现任何事情发生。这是为什么?

0 投票
1 回答
83 浏览

java - 发生前规则与初始化安全规则的关系

我正在阅读Java Concurrency in Practice一书。

在阅读有关 JMM 的章节时,它说:

JMM 为程序中的所有操作定义了一个称为发生前发生的偏序。为了保证执行action B的线程可以看到action A的结果(A和B是否发生在不同的线程中), A和B之间必须存在happens-before关系。

但是,我不能使用任何发生之前的规则来推导“初始化安全”规则:

初始化安全保证对于正确构造的对象,所有线程都将看到构造函数设置的最终字段的正确值,而不管对象是如何发布的。

我们可以使用happens-before规则来推导“初始化安全”规则,还是这两个概念只是同一级别的抽象?

0 投票
2 回答
696 浏览

kotlin - Kotlin 协程“发生在之前”的保证?

Kotlin 协程是否提供任何“之前发生”的保证?

例如,mutableVar在这种情况下,在(可能)其他线程上写入和后续读取之间是否存在“之前发生”的保证:

编辑:

也许额外的例子会更好地阐明这个问题,因为它更像 Kotlin (除了可变性)。此代码是否线程安全:

0 投票
1 回答
633 浏览

c++ - “之前强烈地发生过”是什么意思?

在 C++ 草案标准中多次使用短语“强烈发生在之前”。

例如:终止 [basic.start.term]/5

如果具有静态存储持续时间的对象的初始化完成强烈发生在调用 std​::​atexit 之前(参见 [support.start.term]),则对函数的调用传递给 std​::​atexit在调用对象的析构函数之前排序。如果对 std​::​atexit 的调用强烈发生在具有静态存储持续时间的对象的初始化完成之前,则对对象的析构函数的调用在调用传递给 std​::​atexit 的函数之前排序. 如果对 std​::​atexit 的调用强烈发生在对 std​::​atexit 的另一次调用之前,则对传递给第二个 std​::​atexit 调用的函数的调用在传递给第一个 std​::​atexit 调用。

并在 数据竞赛 [intro.races]/12中定义

评估 A 强烈地发生在评估 D 之前,如果,

(12.1) A 在 D 之前排序,或

(12.2) A 与 D 同步,A 和 D 都是顺序一致的原子操作([atomics.order]),或

(12.3) 有评估 B 和 C 使得 A 在 B 之前排序,B 只是在 C 之前发生,C 在 D 之前排序,或者

(12.4) 有一个求值 B 使得 A 强烈地发生在 B 之前,而 B 强烈地发生在 D 之前。

[注:非正式地,如果 A 强烈地发生在 B 之前,那么在所有情况下 A 似乎在 B 之前被评估。强烈发生在排除消费操作之前。——尾注]

为什么要引入“之前发生的强烈事件”?直观地说,它与“发生在之前”有什么区别和关系?

注释中的“A 似乎在所有情况下都在 B 之前被评估”是什么意思?

(注意:这个问题的动机是 Peter Cordes 在这个答案下的评论。)

附加标准报价草案(感谢 Peter Cordes)

顺序和一致性 [atomics.order]/4

在所有 memory_order​::​seq_cst 操作(包括栅栏)上都有一个总顺序 S,它满足以下约束。首先,如果 A 和 B 是 memory_order​::​seq_cst 操作,并且 A 强烈地发生在 B 之前,那么 A 在 S 中先于 B。其次,对于对象 M 上的每一对原子操作 A 和 B,其中 A 是连贯有序的在B之前,S需要满足以下四个条件:

(4.1) 如果 A 和 B 都是 memory_order​::​seq_cst 操作,则 A 在 S 中先于 B;和

(4.2) 如果 A 是 memory_order​::​seq_cst 操作且 B 发生在 memory_order​::​seq_cst 围栏 Y 之前,则 A 在 S 中先于 Y;和

(4.3) 如果 memory_order​::​seq_cst 栅栏 X 发生在 A 之前且 B 是 memory_order​::​seq_cst 操作,则 X 在 S 中先于 B;和

(4.4) 如果 memory_order​::​seq_cst 栅栏 X 发生在 A 之前,B 发生在 memory_order​::​seq_cst 栅栏 Y 之前,则 X 在 S 中位于 Y 之前。