24

根据MSDN

volatile 关键字表示一个字段可能被同时执行的多个线程修改。声明为 volatile 的字段不受假设由单个线程访问的编译器优化的影响。这确保了字段中始终存在最新的值。

请注意最后一句话:

这可确保字段中始终存在最新的值。

但是,这个关键字有一个问题。

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

First instruction       Second instruction         Can they be swapped?
Read                         Read                         No
Read                         Write                        No
Write                       Write                         No 
Write                       Read                          Yes! <----

这意味着 John 为一个 volatile 字段设置了一个值,后来Paul 想要读取该字段,Paul 正在获取值!

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

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

我(作为程序员)是否应该因为这种奇怪的行为而阻止使用这个关键字?

4

3 回答 3

18

好吧,你是对的。Joseph Albahari threading book/article对此进行了更详细的阐述。

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

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

我应该(作为程序员)因为这种奇怪的行为而需要阻止使用这个关键字吗?

只有在知道这种奇怪的行为之后才应该使用它。在多线程环境中,它不应该一直用作 Magic 关键字来检索最新值。

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

于 2012-05-17T07:41:14.830 回答
7

MSDN 文档是错误的。那肯定不是volatile。C# 规范准确地告诉您做什么volatile,并且获得“新读取”或“提交写入”不是其中之一。规范是正确的。volatile只保证读取时的获取栅栏和写入时的释放栅栏。这些定义如下。

  • acquire-fence:一个内存屏障,不允许其他读写在栅栏之前移动。
  • release-fence:一个内存屏障,不允许其他读写在栅栏之后移动。

我将尝试使用我的箭头符号来解释该表。↓ 箭头将标记易失性读取,↑ 箭头将标记易失性写入。没有指令可以穿过箭头。把箭头想象成把一切都推开。

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

情况1

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

var localx = x;
↓
var localy = y;
↓

案例#2

注意读取后箭头的位置如何x防止写入y向上移动。另请注意,在这种情况下,可能会省略x或的波动性,但不能同时省略两者。y

var localx = x;
↓
↑
y = 1;

案例#3

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

↑
x = 1;
↑
y = 2;

案例#4

x请注意,对 . 的写入和读取之间没有障碍y。因此,要么写入x可以浮动,要么读取y可以浮动。任何一种运动都是有效的。这就是为什么可以交换写读情况下的指令的原因。

↑
x = 1;
var localy = y;
↓

值得注意的提及

还需要注意的是:

  • x86 硬件在写入时具有可变语义。
  • Microsoft 的 CLI 实现(以及可疑的 Mono 的)在写入时具有可变语义。
  • ECMA 规范在写入时没有可变语义。
于 2012-05-17T14:05:58.040 回答
4

Joseph Albahari 提出的另一点是进程架构会对 volatile 产生不利影响,即 AMD 尤其会导致值被交换。

由于您可能不知道您的应用程序将在生产环境中运行什么系统类型,因此最好始终避免使用 volatile 关键字。

同样稍微偏离主题,您应该始终避免使用 ReaderWriterLock 类,因为在多处理器系统上负载过重,这可能允许多个写锁,请参阅此处同时采用这将导致应用程序挂起,这将是极难解决的根本原因

于 2012-05-17T08:08:48.793 回答