问题 易失性读取是否发生在易失性写入之前?


我试着理解为什么这个例子是一个正确同步的程序:

a - volatile
Thread1:
x=a
Thread2:
a=5

因为存在冲突的访问(存在对a的写入和读取)所以在每个顺序一致性执行中必须发生 - 在该访问之间的关系之前。 假设一个顺序执行:

1. x=a
2. a=5

1发生在2之前,为什么?


4440
2018-05-17 17:54


起源

你指的是一个程序,但我只能看到伪代码根本没有意义。 - home
我是唯一一个问题不明确的人 - stinepike
为什么这个问题的所有答案都很难理解。这不应该是一个清楚解释事情的网站吗? - KyleM


答案:


不,之前的(以同步顺序)易失性读取不一定是相同变量的易失性写入 之前发生 易变写。

这意味着它们可以处于“数据竞争”中,因为它们是“冲突的访问,而不是由先发生过的关系命令”。如果这是真的,几乎所有程序都包含数据竞争:)但它可能是一个规范错误。永远不应将易失性读写视为数据竞争。如果程序中的所有变量都是易失性的,则所有执行都是顺序一致的。看到 http://cs.oswego.edu/pipermail/concurrency-interest/2012-January/008927.html


4
2018-05-17 18:07



谢谢,我很头疼,但现在感觉好多了。 - user2394937
另见 这个古老的帖子 在Java Memory Model邮件列表中。它涵盖了相同的基础。 - Marko Topolnik
谢谢,现在我想知道为什么在规范中仍然是那个bug(这是我从近8年来的理解)? - user2394937
这不是@ user2394937的错误。这是关于规格。 - Gray
@Gray编写规范的人承认这是一个错误,但不容易修复,所以我想我们可以把它称为bug! ;-) - assylias


如果你有一个volatile变量 a 并且一个线程正在从中读取而另一个线程正在写入它,这些访问的顺序可以是  订购。它是一个 竞争条件。这取决于首先启动的操作。

写入可能刚刚发生,读取看到更新的值。或者写入可能在读取之后发生。所以 x 可能是 5 或以前的值 a

每个顺序一致性执行必须在该访问之间的关系之前发生

你在这里误导了。 “关系发生之前” volatile 表示先前所有先前的内存更新  读或写 volatile 变量保证已完成。所以两个线程都有“发生之前”的保证,但这并不能解释两者如何 volatile 访问互动。这取决于竞争条件。读者保证已经看过写,  只有在写入发生在读取之前。


5
2018-05-17 18:07



有人想解释一下downvote吗? - Gray


易失性和发生之前仅在读取字段驱动某些条件时才有用。例如:

volatile int a;
int b =0;
Thread-1:
   b = 5;
   a = 10;
Thread-2
   c = b + a;

在这种情况下,没有发生 - 之前,a可以是10或0,b可以是5或0,因此结果c可以是0,5,10或15.如果读取a意味着其他一些条件然后发生before-before例如:

int b = 0;
volatile int a = 0;
Thread-1:
   b = 5
   a = 10;
Thread 2: 
   if(a == 10){
      c = b + a;
   }

在这种情况下,您将确保c = 15,因为读取 a==10 暗示写的 b = 5 在写之前发生 a = 10

编辑:更新添加顺序,如灰色所示的不一致


2
2018-05-17 18:11



当然,只有当= = 10时,c == 15 :-) - Gray
@Gray我想我的观点是,如果没有某种谓词,就没有发生过 - 之前的关系。因此我的第一个例子。但是在这种情况下,它保证为15,前者可以是(0,5,10,15)内的任何数字。在我的后一个例子中,如果a不是volatile,则c可以是10或15。 - John Vint
等等,实际上第一部分略有不正确。没有办法c可以是10.如果a是10,b必须是5.那 是 发生在之前。 b可以是0或5,但如果a是10,则b必须是5。 - Gray
好的,如果我切换添加 c = a + b 至 c = b + a 然后我的例子更准确。但是你是对的,如果在b之前读取a,则第一部分只能是15,0或5。 - John Vint


抱歉,您无法正确说出JVM如何根据JVM的“内存模型”优化代码。您必须使用Java的高级工具来定义您想要的内容。

所以volatile只意味着没有用于变量的“线程间缓存”。

如果您想要更严格的订单,则必须使用同步块。

http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html


1
2018-05-17 18:06