【问题标题】:C# - Is "volatile" really needed as a keyword?C# - 真的需要“volatile”作为关键字吗?
【发布时间】:2010-08-23 05:56:22
【问题描述】:

随着我越来越深入地了解volatile 关键字的含义,我不断对自己说“这是进入实现的方式,这不应该是高级编程语言的一部分"。
我的意思是,CPU 缓存数据这一事实应该对 JIT 编译器感兴趣,而不是 C# 程序员。

一个相当大的替代方案可能是一个属性(例如,VolatileAttribute)。

你怎么看?

【问题讨论】:

  • +1 我认为 VolatileAttribute 在这种情况下是可以的。但我不知道为什么 MS 把它作为关键字。
  • C#应该和C++类似,C++已经有了volatile。既然他们决定需要这个功能(我同意),并且关键字已经在“相似”集中,为什么不直接使用它呢?
  • @Blindy:C++ volatile 有不同的使用模式,所以我会避开它。
  • 这并没有什么不同,从语义上讲,它们实际上非常相似,并且已经存在。为什么要把事情复杂化?
  • @Blindy:因为在 C/C++ 中,`volatile 是 explicitly not 用于多线程。但这只是我的看法。

标签: c# .net multithreading jit volatile


【解决方案1】:

我认为你走偏了。所有关于缓存等技术的东西都是试图用低级术语解释它的一部分。 volatile 的功能描述是“我可能被共享”。鉴于默认情况下线程之间不能共享任何内容,这并不奇怪。而且我认为基本足以保证关键字优于属性,但我认为它在很大程度上受到历史决策(C++)的影响

替换/优化它的一种方法是使用 VolatileRead() 和 VolatileWrite() 调用。但这更像是“实施”。

【讨论】:

    【解决方案2】:

    嗯,我当然同意,暴露出这样的实现细节是非常可怕的。然而,它与 lock 关键字公开的细节完全相同。我们距离那个要从我们的代码中完全删除的错误生成器还很远。

    硬件人员有很多工作要做。 volatile 关键字对许多内存模型较弱的 CPU 内核很重要。市场对他们不友好,Alpha 和 Itanium 表现不佳。不完全确定为什么,但我怀疑为这些内核编写可靠的线程代码的难度与此有很大关系。出错对调试来说是一场噩梦。 MSDN 库文档中关于 volatile 的措辞适用于这类处理器,否则它对于 x86/x64 内核是非常不合适的,并且听起来该关键字的作用远远超过它的实际作用。 Volatile 只是防止变量值存储在这些内核上的 CPU 寄存器中。

    不幸的是,在 非常 特定情况下,易失性在 x86 内核上仍然很重要。我还没有发现任何证据表明它对 x64 内核很重要。据我所知,并由 SSCLI20 中的源代码支持,Opcodes.Volatile 指令对于 x64 抖动是无操作的,既不改变编译器状态也不发出任何机器代码。这是正确的方向。

    一般建议是,无论您在考虑使用 volatile,都应该首先考虑使用 lock 或其中一个同步类。避免他们尝试优化您的代码是一种微优化,当您的程序出现线程竞争问题时,您将失去睡眠量。

    【讨论】:

    • Thread.VolatileRead 和 Thread.VolatileWrite 方法包括对 Thread.MemoryBarrier 的调用。如果 volatile 关键字是空操作,这意味着 volatile 关键字的工作方式与 VolatileRead 和 VolatileWrite 方法不同。哎呀! (不,Thread.MemoryBarrier 最好不要是空操作。x86 和 x64 CPU 具有存储缓冲区,这可能导致存储重新排序,然后加载。存储后加载是 Dekker 的核心,所以 Dekker 在这些拱门上的休息时间如果没有使用内存屏障。好的资源是cl.cam.ac.uk/~pes20/weakmemory/cacm.pdf.)
    • 它们不包括屏障,钛金属比那更易变。刷新挂起的读取和写入是分开的。也有收购废话。我想,我从来没有故意在 500 英里半径范围内。感觉不像是损失。
    【解决方案3】:

    使用属性是可以接受的,如果反过来,编译器会假定所有变量都是易变的,除非明确地用属性标记说它是安全的。这将对性能产生难以置信的影响。

    因此假设,由于在编译器视图之外更改变量的值是一种异常,编译器会假设它没有发生。

    但是,这可能发生在程序中,因此语言本身必须有一种方式来表明这一点。

    此外,您似乎对“实施细节”感到困惑。该术语指的是编译器在你背后做的事情。这不是这里的情况。 您的代码正在修改编译器视图之外的变量。因为它在你的代码中,它永远是正确的。因此,语言必须能够表明这一点。

    【讨论】:

      【解决方案4】:

      volatile 在 c# 中发出正确的屏障或栅栏,这对程序员进行多线程工作很重要。请记住,编译器、运行时和处理器都可以在某种程度上重新排序读/写(每个都有自己的规则)。虽然 CLR 2.0 具有比 CLI ECMA 指定的更强大的内存模型,但 CLR 内存模型仍然不是最严格的内存模型,因此您需要 C# 中的volatile。

      作为属性,我认为不能在方法体内使用属性,所以关键字是必须的。

      【讨论】:

        【解决方案5】:

        IIIRC,在 C++ 中 volatile 主要是关于内存映射 I/O 而不是缓存。如果您两次读取相同的端口,您会得到不同的答案。不过,我同意您的评估,即这在 C# 中作为属性更清晰地表达。

        另一方面,在 C# 中 volatile 的大多数实际使用无论如何都可以更好地理解为线程锁,因此选择 volatile 可能有点不幸。

        编辑:只是添加:两个链接以显示在 C/C++ 中 `volatile 是 explicitly not 用于多线程。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-09-15
          • 2018-09-25
          • 2017-09-29
          • 2015-10-10
          • 1970-01-01
          • 1970-01-01
          • 2014-01-16
          相关资源
          最近更新 更多