8

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

int i;
volatile int v;

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

i = 42;
v = 0;

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

int some_local_variable = v;
print(i);

根据 Java 内存模型,v线程 1 中的写入和线程 2 中的读取v确保线程 2 看到i线程 1 中执行的写入,因此打印值 42。

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

4

2 回答 2

16

C# 中“volatile”的语义在C# 6.0 规范的第 7.10 和 14.5.4 节中定义。我鼓励您在规范中查找它们,而不是在这里复制它们,然后确定使用“易失性”太复杂和危险,然后重新使用锁。这就是我一直在做的事情。

请参阅 C# 6.0 规范中的“ 7.10 执行顺序”和“ 14.5.4 可变字段”。


C# 5.0 规范中,参见“3.10 执行顺序”和“10.5.3 Volatile Fields”

于 2011-06-29T20:01:06.177 回答
7

好吧,我相信它可以确保if some_local_variable被读取为0(由于写入v),i将被读取为 42。

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

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

对于非易失性字段,重新排序指令的优化技术可能会导致多线程程序在没有同步的情况下访问字段的意外和不可预测的结果,例如锁定语句(第 8.12 节)提供的那些。这些优化可以由编译器、运行时系统或硬件来执行。对于 volatile 字段,此类重新排序优化受到限制:

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

然后有一个与您的非常相似的示例,但以从 volatile 变量读取的值为条件。

和 Eric 一样,我强烈避免自己依赖 volatile。这很难推理,最好留给世界上的乔·达菲/斯蒂芬·图布斯。

于 2011-06-29T20:00:30.933 回答