问题标签 [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 投票
3 回答
557 浏览

java - 并发收集前发生关系

我现在正在学习并发性,并且我尝试编写一个程序,该程序应该在使用并发收集时演示发生之前的关系。如java.concurrent包中所述:

java.util.concurrent 及其子包中所有类的方法将这些保证扩展到更高级别的同步。特别是:在将对象放入任何并发集合之前的线程中的操作发生在另一个线程中从集合中访问或删除该元素之后的操作之前。

我写了下一节课:

我所做的是启动thread1,它启动thread2。Thread1 检查最初设置为 false 的公共布尔varToHappenBefore 。当 thread1 从集合中保存新的元素时,它将这个布尔值设置为 true。在下一个新元素上。接收这个布尔值是否仍然为真,发生在违规发生之前,并且shouldNotHappen递增。

Thread1 检查并发集合是否有新元素,如果有,将其保存在 temp var 中并增加整体计数器检查。然后它切换原子布尔值以让 thread2 添加新元素。在添加新元素之前,varToHappenBefore设置为 false。由于原子布尔标志,thread2 不会在 thread1 之前运行代码。但是在 thread2 中切换标志是在添加元素和检查varToHappenBefore之前完成的,因为这两个操作(elem add 和 boolean toggle)否则通过 atomic boolean 同步。我确保 thread2 在 thread1 运行后只运行一次。如果varToHappenBefore发生在添加元素之前。在thread2中收集,然后在thread1中读取(thread1检查varToHappenBefore仅当从集合中读取新元素时),那么varToHappenBefore必须在程序结束后保持为 0。但我得到下一个结果:

添加元素次数:~10 000 000

违规前发生次数:0-10

可能我做错了什么,多线程是微妙而复杂的。希望得到您的帮助。

编辑:setFlag(false)我需要在thread1为真之后和获得elem之前 逃避这种情况。从集合中,因为thread2然后可以在从集合中获取元素和varToHappenBefore = true;在线程1中设置之间工作。如果我进行 AtomicBoolean.compareAndSet()检查块,那么我每8mils得到80k失败。它是可预测的和清晰的。但是,当我没有为 thread2 设置这样的窗口以在从集合读取和设置布尔值之间添加其他元素时,当布尔值为 true 并且出现新元素时,我仍然得到很少的顺序读取。

0 投票
2 回答
724 浏览

multithreading - How does a Java virtual machine implement the "happens-before" memory model?

Java's memory model is based on "happens-before" relationship that enforces rules but also allows for optimization in the virtual machine's implementation in terms of cache invalidation.

For example in the following case:

if thread A calls method() and thread B tries to acquire lockA inside method2(), then the synchronization on lockA will require that thread B observes all changes that thread A made to all of its variables prior to releasing its lock, even the variables that were changed in the "code before lock" section.

On the other hand, method3() uses another lock and doesn't enforce a happens-before relatation. This creates opportunity for optimization.

My question is how does the virtual machine implements those complex semantics? Does it avoid a full flush of the cache when it is not needed?

How does it track which variables did change by which thread at what point, so that it only loads from memory just the cache-lines needed?

0 投票
2 回答
496 浏览

java - Java Lock 对象是否强制执行happens-before 关系?

Java 在并发包中提供了一个 Lock 对象,根据文档provides more extensive locking operations than can be obtained using synchronized methods and statements.

除了互斥之外,同步的方法/块还强制执行发生前的关系,确保一个线程对变量所做的更改对另一个线程可见。

使用 Lock 对象时是否会出现这种关系?是否像所有平台的同步块一样保证观察?

0 投票
1 回答
171 浏览

java - Java 编译器在第一次访问后省略 getfield 操作码是否合法?

我正在试验一些 C# 代码的 Java 端口,我惊讶地发现 javac 1.8.0_60getfield每次访问对象字段时都会发出一个操作码。

这是Java代码:

正如 javap 所报告的,javac 1.8.0_60 产生以下字节码:

请注意,getfield每次访问signandbits字段时,编译器都会发出一个操作码。

阅读 JLS8 的§17.4.5, Happens-before Order, 我不明白为什么getfield每次访问signandbits字段时都需要发出操作码(第一次除外)。

Java 编译器只发出两个getfield操作码并将当时可见的字段值保存在帧局部变量中是否合法?

0 投票
1 回答
763 浏览

multithreading - Java:volatile 如何保证这段代码中“数据”的可见性?

它说“如果一个线程读取数据,则从写入到读取存在一个先发生边缘,以保证数据的可见性”

从我的学习中我知道:

  1. volatile 确保每次读/写都在内存中,而不仅仅是在缓存或寄存器中;
  2. volatile 确保重新排序:也就是说,在 setOnce() 方法中 data = o 只能安排在 if(ready) throw... 之后,并且在 ready = true 之前;这保证如果在 get() ready = true 中,数据必须为 o。

我的困惑是

  1. 是否有可能当线程 1 在 setOnce() 中时,到达 data = o 之后的点;准备好之前=真;同时线程2运行get(),read ready为false,返回null。并且 thead 1 继续准备好 = true。在这种情况下,线程 2 没有看到新的“数据”,即使数据已在线程 1 中分配了新值。

  2. get() 不同步,这意味着同步锁无法保护 setOnce(),因为线程 1 调用 get() 不需要获取锁来访问变量就绪数据。所以线程不能保证看到最新的数据值。我的意思是锁只保证同步块之间的可见性。即使一个线程正在运行同步块 setOnce(),另一个线程仍然可以进入 get() 并在不阻塞的情况下访问就绪和数据,并且可能会看到这些变量的旧值。

  3. 在 get() 中,如果 ready = true,则数据必须为 o?我的意思是这个线程可以保证看到数据的可见性?我认为 data 不是 volatile 也不是 get() 同步的。这个线程是否可以看到缓存中的旧值?

谢谢!

0 投票
1 回答
211 浏览

java - 在 Java 中建立之前发生的关系

我知道,有两种方法可以在 java 中建立发生前的关系:同步块和方法,volatile 关键字。(如果我是正确的,它不适用于最终字段)。我的问题是:并发包中的原子变量的行为是否相似?可以由他们建立之前发生的事情吗?

0 投票
0 回答
280 浏览

c++11 - 在 C++11 规范中“发生在之前”是什么意思?

我试图理解在 C++11 规范中发生之前的含义,特别是规范是否假定除了指定的内容之外对该术语有任何非正式的理解。我正在从草案 N3290 开始工作。

一个直截了当的论点是,该术语应仅根据规范本身来解释,即规范实际上是在讨论它自己对该术语的定义。例如,1.10.6:“发生在(定义如下)”或 1.10.11:“‘发生在’关系,定义如下。”

另一方面,1.10.12 读作“评估 A 在评估 B 之前发生,如果:...”如果这是对发生在之前的定义,我希望它读作“当且仅当”。因此,规范似乎定义了发生在关系之前的一些最低要求,但仍对其他因素开放,这些因素可能包括该术语含义的一些非正式概念,或者可能包括规范其他部分中的语言。

然后第 1.10.13 段定义了可见的副作用,或者是吗?它看起来像一个定义,因为可见副作用是斜体字,但定义是根据发生之前发生的,所以这是否应该被解读为对发生之前的进一步限制,因为可见副作用的直观概念?换句话说,如果 B 看到 A,这是否意味着 A 发生在 B 之前(对发生在之前的定义的进一步限制),还是仅意在另一个方向,即当 A 发生在 B 之前,那么 A必须是可见的副作用。

这是一个具体的例子(受这个问题的启发,但在这里我只是想了解之前发生的事情,关于 C++ 而不是 C,因为 C++ 规范似乎更清晰一些):

给定执行标记的行// 3执行,规范是否要求标记的// 1行在程序中的任何其他行之前发生?非正式地, line// 1是 line 可见的副作用// 2,所以这是否意味着// 1发生 before // 2,在这种情况下,等效的参数说// 2发生在 before// 3并且断言不会失败?出于纯粹的外部原因(即理解 NUMA 的工作原理以及假设语言委员会希望为轻松的内存顺序优化留出空间),我认为这些发生在条件可能不成立并且断言可能失败之前。

我的下一个问题是是否取消注释围栏p2并对p3是否// 1在任何其他声明之前发生有任何影响?在这里,我怀疑除非// 1在其他线程之间的连接和代码之间已经发生了一些事情,否则取消注释其他线程中的栅栏不会改变这一点。(虽然这意味着没有办法阻止断言失败,只使用栅栏。)

最后一点,我有这个问题,其中规范包含关于 A、B、M、X、Y 的抽象语言,这似乎暗示一件事,直到我真正去尝试将 A、B 等映射到语句和变量在我的代码中,此时它似乎暗示着别的东西。因此,我希望得到一个答案,将 C++ 规范与示例代码联系起来,看起来可能过于迂腐的细节。(例如,仅仅说明// 1之前// 3由于读读连贯性而发生的事情并不能回答我的问题——我的问题更多的是关于 C++11 规范中读读连贯性的具体定义如何适用于我的具体代码示例,以及关于假设阅读-阅读连贯性的定义支配发生在之前而不是相反的定义的基础是什么。)

0 投票
1 回答
425 浏览

java - Happens-before 保证 Executor.submit()

Executor 接口的 Javadoc 说明如下:

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

Java 语言规范的哪一部分保证了这一点?或者仅仅是因为实现使用了一些内部同步?(如果是这样的话,一个例子会很好。)那么在实现自定义时Executor我应该知道这个要求吗?

0 投票
0 回答
337 浏览

c++ - 是否在等待唤醒之前发生通知?

这个程序是

保证终止或可能陷入僵局?如果有人会使用mem_ord = std::memory_order_relaxed呢?store进入atomic<int>. _ cppreference.com要求必须取消注释带有 lock-guard 的行notify_thread

我希望(使用任何内存顺序)在通知store 之前发生,在中的(潜在)唤醒wait之前发生,load. (我说“潜在的唤醒”是因为notify-thread当然可以在条件变量之前完成,wait在这种情况下永远不会有唤醒)。所以,我会假设(使用任何内存顺序)没有必要取消注释与 lock-guard 的行。

0 投票
1 回答
108 浏览

c++ - UNIX系统调用的排序规范

类 UNIX 操作系统中的系统调用是可重入的(即可以并行执行多个系统调用)。在 C/C++11 发生之前关系的意义上,这些系统调用是否有任何排序约束?

例如,让我们考虑以下具有 3 个线程的程序(在伪代码中):

在这里,假设xy是共享位置,并且所有的loadstores 都具有宽松的顺序。(注意:对于宽松的原子访问,竞态不被视为错误;它们在 C/C++11 语义的意义上是有意store x 1的。)该程序可能会终止,因为 (1) 编译器可能重新排序and store y 2,然后 (2) 执行store y 2, store y 1, store x 2, 然后store x 1, 所以 (3) 线程 3 可以同时读取x = 1y = 1

我想知道以下程序是否也可能终止。这里,在线程 1 和 2 中分别插入了一些系统调用syscall1()& :syscall2()

该程序似乎无法终止。但是,在没有调用的系统调用的排序约束的情况下,我认为这个程序可能会终止。这就是原因。假设syscall1()syscall2()没有被序列化并且可以并行运行。然后,编译器在完全了解 and 的语义的情况下syscall1()syscall2()仍然可以重新排序store x 1& syscall1()and store y 2

所以我想问一下不同线程调用的系统调用是否有任何排序约束。如果可能的话,我想知道这类问题的权威来源。