2011-06-29 25 views
6

由于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看到在线程1中执行的写入i,因此打印值42。

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

+1

不完全;见http://blogs.msdn.com/b/ericlippert/archive/2011/06/16/atomicity-volatility-and-immutability-are-different-part-three.aspx –

回答

14

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

请参阅3.10 Execution Order10.4.3 Volatile Fields规范。

+0

试图回避C++程序员从“复杂和危险”的细节可能会产生相反的效果;) – fredoverflow

+0

@Fred所以你只是在易变易感兴趣,因为它是复杂和危险的? –

+1

@David:我只是不喜欢不准确的知识,我的印象是'volatile'是有史以来最容易被误解的关键字之一。我想知道东西是如何工作的,这都是:) – fredoverflow

6

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

棘手的部分是“在某个时间点”。虽然通常以“冲洗”写入来讨论波动性,但这不是它在spec(Java或C#)中实际定义的方式。

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

对于非易失性领域,优化技术,指令重新排序可导致访问领域不同步多线程程序意外和不可预知的结果如锁定语句(§8.12)提供的那样。这些优化可以由编译器,运行时系统或硬件来执行。对于易失性字段,此类重新排序优化受到限制:

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

有其然后是相当类似你,但是条件上从易失性可变读出的值的例子。和埃里克一样,我强烈避免依靠易变本人。很难推理,最好留给世界的乔·达菲/史蒂芬·图布斯。

+0

你能更具体地表达你的意思吗尊重Java中的“冲洗”写法?你是否暗示我的代码甚至不能在Java中工作? – fredoverflow

+0

@Fred好吧,如果我们相信Jon的小引用,看起来C#确实可以保证写入的释放语义并获取读取的语义,这意味着该示例在Java和C#中都可以正常工作..现在,您仍然有去读重要章节,以确保不会错过某些角落案例。尽管我完全理解为什么避免不稳定(以及信号量和所有其他低级线程的东西)通常不是一个坏主意,但我也不想在我的知识中出现漏洞 - 而且只是因为你知道如何使用volatile,不会你不需要! – Voo

+0

@Fred:问题是你还没有定义“一段时间后”的含义。你可以保证的是,如果*线程2看到写入volatile变量,那么它将*看到写入非易失性变量。 –