从Java 5开始,volatile
关键字具有释放/获取语义,以使副作用对其他线程可见(包括对非易失性变量的赋值!)。取这两个变量,例如:
int i;
volatile int v;
请注意,i
是一个常规的非易失性变量。想象一下线程1执行以下语句:
i = 42;
v = 0;
稍后,线程2执行以下语句:
int some_local_variable = v;
print(i);
根据Java内存模型,在线程1中写入v
,然后在线程2中读取v
,确保线程2看到在线程中执行的i
写入1,所以打印出值42.
我的问题是:volatile
在C#中是否具有相同的发布/获取语义?
答案 0 :(得分:15)
C#中“volatile”的语义在规范的3.10和10.4.3节中定义。我鼓励你在规范中查找它,而不是在这里重现它们,然后决定使用“volatile”过于复杂和危险,然后回到使用锁。这就是我一直以来做的事情。
答案 1 :(得分: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。