C# - 作为关键字真的需要“易变”吗?

时间:2010-08-21 08:26:33

标签: c# .net multithreading jit volatile

当我更深入地阅读volatile关键字的含义时,我一直对自己说“这是进入实施的方式,这不应该是高级别的一部分编程语言“。
我的意思是,CPU缓存数据这一事实应该对JIT编译器感兴趣,而不是C#程序员。

可选的替代方案可能是属性(例如,VolatileAttribute)。

您怎么看?

5 个答案:

答案 0 :(得分:8)

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

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

答案 1 :(得分:5)

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

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

不幸的是,在非常选择的情况下,volatile仍然在x86核心上很重要。我还没有找到任何证据表明它在x64核心上很重要。据我所知,并且SSCLI20中的源代码支持,Opcodes.Volatile指令是x64抖动的无操作,既不改变编译器状态也不改变任何机器代码。那是正确的方向。

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

答案 2 :(得分:4)

使用属性是可以接受的,如果是相反的方式,也就是说,编译器会假设所有变量都是易失性的,除非明确标记一个属性,说它是安全的。这对于表现来说是非常不利的。

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

然而,可能在一个程序中发生,因此语言本身必须有一种显示方式。

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

答案 3 :(得分:2)

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

另一方面,C#中volatile的大多数实际用途无论如何最好被理解为线程锁定,因此volatile的选择可能有点不幸。

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

答案 4 :(得分:2)

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

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