具有释放/获取语义的volatile

fre*_*low 6 c# java volatile memory-model java-memory-model

从Java 5开始,volatile关键字具有释放/获取语义,以使副作用对其他线程可见(包括对非易失性变量的赋值!).拿这两个变量,例如:

int i;
volatile int v;
Run Code Online (Sandbox Code Playgroud)

请注意,这i是一个常规的非易失性变量.想象一下线程1执行以下语句:

i = 42;
v = 0;
Run Code Online (Sandbox Code Playgroud)

在稍后的某个时间点,线程2执行以下语句:

int some_local_variable = v;
print(i);
Run Code Online (Sandbox Code Playgroud)

根据Java存储器模型,v线程1中的写入以及线程2中的读取v确保线程2看到i在线程1中执行的写入,因此打印值42.

我的问题是:volatile在C#中是否有相同的发布/获取语义?

Eri*_*ert 15

C#中"volatile"的语义在规范的3.10和10.4.3节中定义.我鼓励你在规范中查找它,而不是在这里重现它们,然后决定使用"volatile"过于复杂和危险,然后回到使用锁.这就是我一直以来所做的.

请参见3.10执行顺序10.4.3易失性字段规范.

  • 试图让 C++ 程序员避开“复杂且危险”的细节可能会产生相反的效果;) (3认同)
  • @David:我只是不喜欢不精确的知识,我的印象是 `volatile` 是有史以来最容易被误解的关键字之一。我想知道东西是如何工作的,仅此而已:) (2认同)

Jon*_*eet 6

好吧,我相信它确保如果 some_local_variable被读取0(由于写入v),i将被读为42.

棘手的部分是"在稍后的某个时间点".虽然通常会在"刷新"写入方面讨论波动性,但这并不是它在规范中实际定义的方式(Java或C#).

从C#4语言规范,第10.5.3节:

对于非易失性字段,重新排序指令的优化技术可能会在多线程程序中导致意外和不可预测的结果,这些程序无需同步即可访问字段,例如lock-statement(第8.12节)提供的字段.这些优化可以由编译器,运行时系统或硬件执行.对于易失性字段,此类重新排序优化受到限制:

  • 读取volatile字段称为volatile读取.易失性读取具有"获取语义"; 也就是说,保证在指令序列之后发生的任何内存引用之前发生.
  • 写入易失性字段称为易失性写入.易失性写入具有"释放语义"; 也就是说,保证在指令序列中的写指令之前的任何存储器引用之后发生.

那么有一个与你的非常相似的例子,但是以从volatile变量读取的值为条件.

和埃里克一样,我强烈避免依赖于挥发自己.这很难推理,最好留给世界上的Joe Duffy/Stephen Toubs.