问题标签 [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.
concurrency - RxJava:当“可观察合同”说“发生在之前”时,它实际上是什么意思?
Observables 必须串行(而不是并行)向观察者发出通知。他们可能会从不同的线程发出这些通知,但通知之间必须有正式的先发生关系。
当它说“happens-before”时,是否意味着上一个 onNext 通知的所有效果(例如更改 Observer.onNext() 方法中的共享状态)对于下一个 onNext 通知将完全可见,就像发生一样-Java 内存模型中的保证之前?
阅读 SerializedObserver(RxJava 版本 3.0.11)的源代码后,我发现在同步代码块中没有调用下游.onNext(t) 方法。那么,我可以说答案不是吗?
java - ConcurrentHashMap 仅通过计算方法读取/更新
我的问题可能很简单,如果我ConcurrentHashMap::compute
只在具有一定价值的读者和作者中使用,是否足以确保可见性?
我确实知道这种compute
方法:
整个方法调用以原子方式执行
这足以保证可见性吗?具体来说,真正的规范/文档是否明智happens-before
?为了简化我的问题,这里有一个例子:
和 :
没有人可以访问CHM
并且只能通过Holder
.
对我来说,答案显然是肯定的,这是安全的,所有读者都会看到最新write
方法的结果。我只是无法将这些点与 的文档联系起来ConcurrentHashMap
,这很可能是显而易见的,但我似乎想念它。
java - Java 是否还保证同步之前的所有变量更改对于在同一对象上同步的下一个线程可见?
在下面的代码中,Java 是否会确保a
调用的线程可以看到最新的副本getAB()
?
我知道返回的值getAB()
可能与设置的不同setAB
,但Java会确保a
其他线程看到的值总是更新或与值一致b
吗?
后续问题:如果我们将arr[0] = a;
语句移到块之后会发生什么synchronized
?
像这样 ...
c++ - 不明白为什么在第 5.3.1 章中的“操作写入值发生在读取该值的操作之前”
我目前在内存模型部分(第 5 章)中阅读了“C++ Concurrency in action”。在第 5.3.1 章中,作者写道:
抛开等待数据准备好的循环的低效率(1),你真的需要它来工作,因为否则在线程之间共享数据变得不切实际:每一项数据都被迫成为原子的。您已经了解到,非原子读取(2)和写入(3)在没有强制排序的情况下访问相同的数据是未定义的行为,因此要使其工作,必须在某处强制排序。
所需的强制排序来自对 std:: 原子变量 data_ready 的操作;它们通过发生在之前和同步的内存模型关系提供必要的排序。数据的写入(3)发生在数据就绪标志(4)的写入之前,标志(1)的读取发生在数据的读取(2)之前。当从 data_ready (1)读取的值为真时,写入与读取同步,创建发生前的关系。因为happens-before是传递性的,所以对数据的写入(3)发生在写入标志(4)之前,发生在从标志(1)读取真值之前,发生在读取之前数据(2),你有一个强制的顺序:数据的写入发生在数据的读取之前,一切正常。图 5。图 2 显示了两个线程中的重要发生之前的关系。我从阅读器线程中添加了几次 while 循环的迭代。
所有这些看起来都相当直观:当然,写入值的操作发生在读取该值的操作之前!对于默认的原子操作,这确实是真的(这就是为什么这是默认的),但它确实需要说明:原子操作还有其他选项来满足排序要求,我很快就会谈到
我很不明白,为什么“所有这些看起来都相当直观:当然,写入值的操作发生在读取该值的操作之前!”,请帮助我理解这句话。
scala - Scala构造函数上的“发生在之前”:最终字段
Java 规范提到,只有final
字段的类的构造函数与读取对该对象的任何引用的任何线程处于发生前关系:换句话说,应用程序不可能看到部分构造的对象。
Scala 通过将初始化提取到单独的方法来破解初始化,以确保在超类中的任何初始化代码之前设置“主构造函数 vals” 。这至少是 Scalafinal val
不总是(或永远?)翻译成 Javafinal
领域的原因之一。
- 有没有办法实现这一点,即确保类客户端及其构造函数之间的发生前关系?
- 哪个是编译器相当稳定的功能?
- 一个不是用Java编写类的?
java - Java 不可变类与可变引用
向其他线程发布值的标准做法是将构造对象分配给volatile
字段:作为双向内存围栏的副作用,通过此类字段读取对象的线程保证不会看到部分构造的对象. 但是,如果一个类中的所有字段都是final
,那么对其构造函数的调用将自动与任何客户端代码处于发生前的关系,而不需要volatile
在引用上使用关键字。
- 后者是否比前者有性能优势(从读者的角度来看)?
- 这是否意味着 final 字段存在性能成本(例如,它实际上等效于 volatile 访问,不仅在语义上,而且在执行上)?
java - 如果 a 易失而 b 不是易失性,“b=3”可以在“a=2+b”之前重新排序吗?
因为 volatile 写入后的普通读写不禁止重排序,所以下面代码中的 b=3 可能会在 a=2+b 之前重排序吗?
java - 可以释放+获取中断发生之前吗?
今天的许多编程语言都有happens-before
关系和release+acquire
同步操作。
其中一些编程语言:
我想知道是否release+acquire
可以违反happens-before
:
- 如果可能的话,那么我想看一个例子
- 如果不可能,那么我想得到简单明了的解释为什么
什么是release+acquire
和happens-before
Release/acquire
建立happens-before
不同线程之间的关系:换句话说,之前release
in的所有内容都Thread 1
保证在Thread 2
after中可见acquire
:
不仅如此,happens-before
还是严格的偏序。
这意味着它是:
- 传递性:
Thread 2
保证不仅可以看到 的写入Thread 1
,还可以Thread 1
看到其他线程的所有写入 - 不对称:
a
happens-beforeb
或b
happens-beforea
都不允许
为什么我认为这release/acquire
可能会破坏happens-before
正如我们从 IRIW 石蕊测试中知道的那样,release/acquire
可能导致两个线程以不同的顺序查看来自不同线程的写入(对于 C++,另请参见此处的最后一个示例,以及来自 gcc wiki的这 两个示例):
这里两个assert
s 都可以通过,这意味着Thread 3
和see 以不同的顺序Thread 4
写入。x
y
据我了解,如果它是普通变量,那么这将违反happens-before的不对称属性。但是因为 x 和 y 是原子的,所以没关系。(顺便说一句,我不确定)
Nate Eldredge在他的回答中证明这个 IRIW 示例是可以的。
但我仍然有一个偷偷摸摸的怀疑,可能存在类似于 IRIW 的东西,它会导致Thread 3
并Thread 4
看到常规写入以不同的顺序发生在发生之前——这会破坏发生在之前(它不再是传递的)。
注1
在cppreference中也有这样的引用:
该实现需要通过在必要时引入额外的同步来确保发生之前的关系是非循环的(只有在涉及消费操作时才需要,参见 Batty 等人)
引用暗示可能存在happens-before
违反并需要额外同步的情况(“无环”意味着发生之前形成有向无环图,相当于说“严格偏序”)。
如果可能的话,我想知道这些情况是什么。
笔记2
由于 java 允许数据竞争,我也对happens-before
仅在存在数据竞争时违反的情况感兴趣。
编辑 1(2021 年 11 月 3 日)
举个例子,这里解释了为什么顺序一致(SC)原子不能违反happens-before
.
(对释放/获取原子的类似解释将是我问题的答案)。
“违反happens-before
”我的意思是“违反 的公理happens-before
,这是一个严格的偏序”。
严格的偏序直接对应于有向无环图 (DAG)。
这是来自 wiki 的 DAG 示例(请注意,它没有循环):
让我们证明 SC 原子happens-before
图保持非循环。
请记住,SC 原子以全局顺序发生(所有线程都相同),并且:
- 顺序与每个线程内的动作顺序一致
- 每个 SC 原子读取都会以这个总顺序看到最新的 SC 原子写入到同一个变量
看这张happens-before
图:
在图表上:
- 时间向下流动
W(x)
并且R(x)
是常规动作:写入和读取x
Sw(a)
并且Sr(a)
是 SC 原子:写入和读取a
- 在每个线程内,操作按程序顺序(
sequenced-before order
在 C++ 中也称为)发生:按照它们在代码中的顺序 - 线程之间
happens-before
由 SC atomics 建立
请注意,图上的箭头始终向下
=> 图不能有环
=> 它始终是 DAG
=>happens-before
不能违反公理
相同的证明不适用于release/acquire
原子,因为(据我所知)它们不会以全局顺序发生=>之间的HB箭头Sw(a)
并且Sr(a)
可能向上=>可能存在循环。(对此我不确定)