根据MSDN:
volatile关键字表示字段可能被修改 多个线程同时执行。是的领域 声明的volatile不受编译器优化的限制 假设由单个线程访问。这确保了最多 字段中始终存在最新值。
请注意最后一句:
这可确保始终在字段中显示最新值。
但是,此关键字存在问题。
我read它可以改变指令的顺序:
First instruction Second instruction Can they be swapped? Read Read No Read Write No Write Write No Write Read Yes! <----
这意味着John将值设置为易失性字段,稍后 Paul想要读取该字段, Paul正在获得旧值!
这是怎么回事?这不是主要的工作吗?
我知道还有其他解决方案,但我的问题是关于volatile关键字。
我(作为程序员)是否需要阻止使用此关键字 - 因为这种奇怪的行为?
答案 0 :(得分:18)
你是对的。约瑟夫·阿尔巴哈里(Joseph Albahari)更加详细地阐述了book/article。
MSDN文档指出使用volatile关键字可确保始终在字段中显示最新值。这是不正确的,因为正如我们所看到的,可以重新排序读取后写入。
http://www.albahari.com/threading/part4.aspx#_The_volatile_keyword
我(作为程序员)是否需要阻止使用此关键字 - 因为这种奇怪的行为?
只有在了解了这种疲惫的行为后才能使用它。它不应该用作Magic关键字来在多线程环境中一直检索最新值。
IMO,应该避免使用volatile关键字,因为很难找到可能的错误。
答案 1 :(得分:7)
MSDN文档错误。这肯定不是volatile
所做的。 C#规范准确地告诉你volatile
做了什么,获得“新读”或“提交写入”不是其中之一。规范是正确的。 volatile
仅保证读取时的获取范围和写入时的释放范围。这些定义如下。
我将尝试使用箭头符号解释表格。 ↓箭头将标记易失性读数,↑箭头将标记易失性写入。没有指令可以通过箭头移动。把箭头想象成推开一切。
在下面的分析中,我将使用变量; x
和y
。我还假设它们被标记为volatile
。
案例#1
请注意阅读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;
↓
值得注意的提及
同样重要的是要注意:
答案 2 :(得分:4)
Joseph Albahari提出的另一个观点是,流程架构会对易失性产生负面影响,即AMD尤其会导致值被交换。
由于您可能不知道应用程序将在生产中运行哪种系统类型,因此最好始终避免使用volatile关键字。
稍微偏离主题你应该总是避免ReaderWriterLock类,因为在多处理器系统上负载很重,这可能允许同时采用多个写锁please see here,这将导致应用程序挂起,这将导致根本原因非常困难< / p>