换句话说,我可以用挥发性变量做某事,该变量也无法用正常变量和互锁的类解决吗?

有帮助吗?

解决方案

编辑:问题很大程度上重写

为了回答这个问题,我在此问题上进一步潜入 volatileInterlocked 我不知道。让我们清楚地说明这一点,不仅对我,而且为此讨论和其他人对此进行了阅读:

  • volatile 读/写应该不可能重新排序。这个 只要 意味着阅读和写作,确实如此 不是 意味着任何其他行动;
  • 挥发性 不在CPU上,即硬件级别(X86使用获取和释放围栏 任何 读/写)。它确实可以防止编译器或CLR优化;
  • Interlocked 使用原子汇编说明进行比较change(cmpxchg), 增量 (inc) ETC;
  • Interlocked 确实使用 有时锁: 多处理器系统上的硬件锁;在Uni-Processor系统中,没有硬件锁。
  • Interlocked 与众不同 volatile 因为它使用了 全篱笆, ,挥发性使用半栅栏。
  • 可以重新排序以下读取书面 当您使用时 volatile. 。它不可能发生 Interlocked. VolatileReadVolatileWrite 具有与“挥发性”(Brian Gideon)相同的重新排序问题(链接)。

现在我们有了规则,我们可以定义您的问题的答案:

  • 从技术上讲:是的,您可以做一些事情 volatile 你不能做 Interlocked:
    1. 语法:你不能写 a = b 在哪里 a 或者 b 是动荡的,但这很明显。
    2. 由于重新排序,您可以在将其写入挥发性变量后读取不同的值。你不能这样做 Interlocked. 。换句话说:你可以 较少的 安全 volatile 那你可以和 Interlocked.
    3. 表现: 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...
}

如果您设置 donetrue 在另一个线程中,您希望循环退出。但是 - 如果完成的话没有标记为 volatile 然后,编译器可以选择意识到循环代码永远无法更改 done 它可以优化出口的比较。

这是多线程编程的困难之一 - 许多问题的情况只有在某些情况下出现。

我不会试图成为这个问题的权威,但我强烈建议您看看 本文 由乔恩·斯基特(Jon Skeet)吹嘘的。

还要看一下的最后一部分 这个答案 哪个详细说明 volatile 应该使用。

是的,您可以使用挥发性变量而不是锁来获得一些性能。

锁定是一个完整的内存屏障,可以为您提供挥发性变量以及许多其他变量的相同特征。正如已经说过的那样,波动性仅确保在多线程的情况下,如果CPU更改其高速缓存线的值,另一个CPU会立即看到该值,但根本不能确保任何锁定语义。

事情是锁比挥发性要强大得多,当您可以避免不必要的锁时,您应该使用挥发性。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top