使用挥发性关键字与使用互锁类相比,使用挥发性关键字有任何优势吗?
-
19-09-2019 - |
题
换句话说,我可以用挥发性变量做某事,该变量也无法用正常变量和互锁的类解决吗?
解决方案
编辑:问题很大程度上重写
为了回答这个问题,我在此问题上进一步潜入 volatile
和 Interlocked
我不知道。让我们清楚地说明这一点,不仅对我,而且为此讨论和其他人对此进行了阅读:
volatile
读/写应该不可能重新排序。这个 只要 意味着阅读和写作,确实如此 不是 意味着任何其他行动;- 挥发性 不在CPU上,即硬件级别(X86使用获取和释放围栏 任何 读/写)。它确实可以防止编译器或CLR优化;
Interlocked
使用原子汇编说明进行比较change(cmpxchg
), 增量 (inc
) ETC;Interlocked
确实使用 有时锁: 多处理器系统上的硬件锁;在Uni-Processor系统中,没有硬件锁。Interlocked
与众不同volatile
因为它使用了 全篱笆, ,挥发性使用半栅栏。- 可以重新排序以下读取书面 当您使用时
volatile
. 。它不可能发生Interlocked
.VolatileRead
和VolatileWrite
具有与“挥发性”(Brian Gideon)相同的重新排序问题(链接)。
现在我们有了规则,我们可以定义您的问题的答案:
- 从技术上讲:是的,您可以做一些事情
volatile
你不能做Interlocked
:- 语法:你不能写
a = b
在哪里a
或者b
是动荡的,但这很明显。 - 由于重新排序,您可以在将其写入挥发性变量后读取不同的值。你不能这样做
Interlocked
. 。换句话说:你可以 较少的 安全volatile
那你可以和Interlocked
. - 表现:
volatile
那时更快Interlocked
.
- 语法:你不能写
语义上:不,因为
Interlocked
简单地提供了一台操作的超集,并且可以使用更安全,因为它应用了完整的围栏。你不能做任何事情volatile
你不能做Interlocked
你可以做 很多 和Interlocked
您不能挥发性:static volatile int x = 0; x++; // non-atomic static int y = 0; Interlocked.Increment(y); // atomic
范围:是的,声明变量
volatile
使每个访问权限都波动。不可能采取任何其他方式强迫这种行为volatile
不能替换Interlocked
. 。在其他库,接口或硬件可以访问您的变量并随时更新或需要最新版本的情况下,这是需要的。
如果您要问我,最后一点是真正的真正需求 volatile
并且可能使其成为两个过程共享内存并需要读取或写入而无需锁定的理想之选。声明变量为 volatile
在这种情况下,要安全得多,然后强迫所有程序员使用 Interlocked
(您不能由编译器强迫)。
编辑:以下报价是我原始答案的一部分,我将其放入;-)
来自 C#编程语言 标准:
对于非易失性字段,考虑重新排序指令的优化技术可以在多线程程序中导致意外且不可预测的结果,这些程序访问无同步的字段,例如 锁定。这些优化可以由编译器,运行时系统或硬件执行。对于挥发性领域,此类重新排序的优化受到限制:
读取一个挥发性字段的读物称为 挥发性阅读. 。挥发性读取具有:获取语义“;也就是说,可以保证在指令序列中发生在记忆后发生的任何引用之前发生。
挥发性领域的写作称为 挥发性写作. 。挥发性的文字具有“释放语义”;也就是说,在指令序列中写入指令之前的任何内存引用之后,它可以保证发生。
更新: 问题在很大程度上重写,更正了我的原始答案并添加了一个“真实”答案
其他提示
这是一个相当复杂的话题。我发现约瑟夫·阿尔巴哈里的 写上去 成为.NET框架中多线程概念的更确定和准确的来源之一,这可能有助于回答您的问题。
但是,要快速总结 volatile
关键字和 Interlocked
只要如何使用它们。当然,两者都超越了正常变量可以做的事情。
是的 - 您可以直接查看值。
只要您仅使用联锁类访问变量,就没有区别。什么 易挥发的 确实,它告诉编译器,该变量是特殊的,并且在优化时不应假设该值没有更改。
采用此循环:
bool done = false;
...
while(!done)
{
... do stuff which the compiler can prove doesn't touch done...
}
如果您设置 done
至 true
在另一个线程中,您希望循环退出。但是 - 如果完成的话没有标记为 volatile
然后,编译器可以选择意识到循环代码永远无法更改 done
它可以优化出口的比较。
这是多线程编程的困难之一 - 许多问题的情况只有在某些情况下出现。
是的,您可以使用挥发性变量而不是锁来获得一些性能。
锁定是一个完整的内存屏障,可以为您提供挥发性变量以及许多其他变量的相同特征。正如已经说过的那样,波动性仅确保在多线程的情况下,如果CPU更改其高速缓存线的值,另一个CPU会立即看到该值,但根本不能确保任何锁定语义。
事情是锁比挥发性要强大得多,当您可以避免不必要的锁时,您应该使用挥发性。