【发布时间】: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