挥发性违反其主要工作?

Roy*_*mir 23 .net c# multithreading volatile thread-safety

根据MSDN:

volatile关键字表示某个字段可能被同时执行的多个线程修改.声明为volatile的字段不受编译器优化的约束,这些优化假定由单个线程进行访问.这可确保始终在字段中显示最新值.

请注意最后一句:

这可确保始终在字段中显示最新值.

但是,此关键字存在问题.

我已经读过它可以改变指令的顺序:

First instruction       Second instruction         Can they be swapped?
Read                         Read                         No
Read                         Write                        No
Write                       Write                         No 
Write                       Read                          Yes! <----
Run Code Online (Sandbox Code Playgroud)

这意味着John为一个易变的字段设置了一个值,后来 Paul想要阅读该字段,Paul正在获得旧的价值!

这是怎么回事?这不是主要的工作吗?

我知道还有其他解决方案,但我的问题是关于volatile关键字.

我(作为程序员)是否需要阻止使用此关键字 - 因为这种奇怪的行为?

Til*_*lak 18

那你是对的.在Joseph Albahari线程书/文章中更详细说明.

MSDN文档指出使用volatile关键字可确保始终在字段中显示最新值.这是不正确的,因为正如我们所见,可以重新排序读取后跟读取.

http://www.albahari.com/threading/part4.aspx#_The_volatile_keyword

我(作为程序员)是否需要阻止使用此关键字 - 因为这种奇怪的行为?

只有在知道了这种习惯行为后才能使用它.它不应该用作Magic关键字来在多线程环境中始终检索最新值.

IMO,应避免使用volatile关键字,因为很难找到可能的错误.

  • 我不知道.MSDN在各个地方都是不正确的.我可以看到用户评论指出这一点.在约瑟夫的文章中,结论得到了适当的例子的支持,你可以自己试试. (4认同)
  • 为什么msn写这个奇怪的行为?为什么我需要从约瑟夫那里听到它? (3认同)

Bri*_*eon 7

MSDN文档是错误的.这肯定不是什么volatile.C#规范确切地告诉你什么volatile,并且获得"新读"或"提交写入"不是其中之一.规范是正确的.volatile只保证在写入时读取和释放围栏上的获取范围.这些定义如下.

  • acquire-fence:一种内存屏障,其中不允许其他读写操作在围栏之前移动.
  • release-fence:一种内存屏障,在屏障不允许其他读写操作.

我将尝试使用箭头符号解释表格.↓箭头将标记易失性读数,↑箭头将标记易失性写入.没有指令可以通过箭头移动.把箭头想象成推开一切.

在下面的分析中,我将使用变量; xy.我还假设他们被标记为volatile.

情况1

注意读取后箭头的放置如何x防止读取y向上移动.另请注意,y在这种情况下,波动性无关紧要.

var localx = x;
?
var localy = y;
?
Run Code Online (Sandbox Code Playgroud)

案例#2

请注意读取后箭头的放置如何x防止写入y向上移动.另请注意,在这种情况下,可以省略xy不是两者的波动性.

var localx = x;
?
?
y = 1;
Run Code Online (Sandbox Code Playgroud)

案例#3

注意在写入之前放置箭头是如何y防止写入x向下移动的.请注意,x在这种情况下,波动性无关紧要.

?
x = 1;
?
y = 2;
Run Code Online (Sandbox Code Playgroud)

案例#4

请注意,写入x和读取之间没有障碍y.因此,写入x可以向下浮动或读取y可以浮动.这两种运动都是有效的.这就是为什么可以交换写 - 读案例中的指令.

?
x = 1;
var localy = y;
?
Run Code Online (Sandbox Code Playgroud)

值得注意的提及

同样重要的是要注意:

  • x86硬件在写入时具有易失性语义.
  • 微软的CLI实现(以及可疑的Mono)在写入时具有易失性语义.
  • ECMA规范在写入时没有 volatile语义.