【问题标题】:Is volatile keyword useful with .net core under intel cpu?volatile关键字对intel cpu下的.net core有用吗?
【发布时间】:2019-02-04 16:38:20
【问题描述】:

我已经尝试了一些 volatile 对 .NET Framework 有帮助的问题案例。但是在 .NET Core 下,我还没有发现 volatile 真正有帮助的一个案例。 .NET Core 的内存模型是否比 .NET Framework 更强大,以至于我们不再需要 volatile?

例如,如果您使用发布模式构建以下代码,则使用 .net 框架无限期地阻塞,但它不使用 .net 核心。原因是,在 .net 情况下,值存储在寄存器中并缓存:

    class Program
    {
        static bool complete = false;
        static void Main()
        {

            var t = new Thread(() =>
            {
                bool toggle = false;
                while (!complete) toggle = !toggle;
            });
            t.Start();
            Thread.Sleep(1000);
            complete = true;
            t.Join();        // Blocks indefinitely
        }
    }

【问题讨论】:

  • 大多数人 - 包括我 - 都无法(准确而准确地)解释 volatile 的含义或作用(它不是“确保它得到重新-read”,这是实现的意外副产品);所以,几乎每次我看到有人问 volatile 时,他们都在问错误的问题。这里的“有用”是什么意思?你认为它有什么作用?另请注意:这也与 CPU 和运行时密切相关;例如,x86 上的 .NET Core 与 x64 上的 .NET Core 非常不同(就这一点而言)。然后我们需要谈谈.NET Core的确切版本等等......
  • 我想我们知道。在 CLR 上下文中,volatile 意味着:Yo 编译器不会将数据放入 CPU 缓存中。并且,当您读取该字段时,您的 CPU 会获取一个读栅栏,这样就没有其他指令可以在之前运行,而当您写入该字段时,您会获取一个写栅栏,因此没有其他指令可以进入下面。当然不同的CPU和不同的东西。我的问题是,是否有人知道.net core 内存模型的已知变化。
  • @OnurGumus,这不仅仅是“缓存”。我不知道volatile 在.NET 中的确切含义,但在另一种语言中,它意味着一个线程对变量的更新应该立即对其他线程可见。多处理器计算硬件中的缓存只是造成问题的原因之一。另一个是编译时优化:如果您的代码在没有其他同步的情况下访问非易失性变量,则允许编译器重写您的代码,假设只有一个线程会执行它,并且没有其他线程会触及变量。
  • “我试过了,好像有效”并不是判断多线程代码正确性的方法。不要依赖观察到的实现行为。阅读文档并了解 volatile 的实际含义。您的问题对底层 CPU 架构做了很多假设,.NET Core 或大多数其他运行时环境无法保证。即使在 C 语言中,您也不知道某个特定变量是否最终会出现在寄存器中。更令人担忧的是,您似乎认为volatile 与多线程有关;不是。使用它是一种代码味道。

标签: c# multithreading .net-core volatile


【解决方案1】:

根据this article,C# 中的volatile 告诉编译器/JIT 发出指令以防止指令重新排序。虽然英特尔平台上的 .NET 内存模型通常足够强大,以至于很少发生排序,但在其他平台(例如 ARM)上您永远不知道。

换句话说,很少需要使用volatile,除非您担心重新排序会破坏您的代码。同时,当涉及到多线程时,总是最好是安全的。

【讨论】:

  • 我在问题中添加了一个反例。
  • 在您的示例中, bool 是一个局部变量。因此,它不能是volatile。然后,发生的事情是编译器优化了代码,因此它不会在每次运行时评估complete,尽管它正在“关闭”。这种优化对于 C++ 也是合法的。
  • 没关系。我已将其更改为字段相同的结果。在字段中添加 volatile 可以解决此问题。即使在 .net core 中也不会发生这种情况。
  • 确实如此,因为这并不总是发生。我已经尝试了很多次,但永远无法可靠地重现设置volatile 的需要。
  • 我的印象是你的文章是准确的定义。在英特尔上,不需要 volatile。然而,由于发生上述问题的 JIT 错误(将变量放入寄存器),在 .net 核心中它已被修复。所以我认为我们可以在 intel 平台上得出结论,intel 平台不需要 .net core 下的 volatile。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-02-08
  • 1970-01-01
  • 1970-01-01
  • 2016-02-12
  • 2013-08-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多