【发布时间】:2015-10-22 12:18:31
【问题描述】:
我有一类 NonVolatileTest :
public class NonVolatileTest
{
public bool _loop = true;
}
我有两个代码示例:
1:
private static void Main(string[] args)
{
NonVolatileTest t = new NonVolatileTest();
Task.Run(() => { t._loop = false; });
while (t._loop) ;
Console.WriteLine("terminated");
Console.ReadLine();
}
2:
private static void Main(string[] args)
{
NonVolatileTest t = new NonVolatileTest();
Task.Run(() => { t._loop = false; });
Task.Run(() =>
{
while (t._loop) ;
Console.WriteLine("terminated");
});
Console.ReadLine();
}
在第一个示例中,所有工作都按预期工作,并且“while”循环永远不会终止,但在第二个示例中,所有工作都据称“_loop”字段是可变的。
为什么?
PS。 与 2013、.NET 4.5、x64 释放模式 & Ctrl + F5
假设:
此“错误”可能与 TaskScheduler 有关。我认为,在 JIT 将第二个任务用于编译和运行之前,第一个任务已经完成,所以 JIT 取了更改后的值。
【问题讨论】:
-
字段未标记为 volatile 的事实并不意味着编译器/优化器/抖动不会重新读取它。这也可能很简单,在第一个示例中,代码在任务设法将布尔标志设置为 false 之前设法竞相读取布尔标志,但在第二种情况下,第二个任务在启动时也有开销运行,这意味着第一个任务首先设法将布尔值设置为 false。尝试在第一个任务的开头添加睡眠并重新测试。
-
另外,第一个代码显然是错误的。首先,您永远不会将
loop
设置为true,它在一个地方命名为loop
,在另一个地方命名为_loop
。你能发布正确的代码吗? -
Lasse V. Karlsen,我在开始第二个任务之前延迟修复它:Thread.Sleep(1000)。
-
这个“错误”可能与 TaskScheduler 有关。我认为,在 JIT 将第二个任务用于编译和运行之前,第一个任务已经完成,所以 JIT 取了更改后的值。
-
如果您“解决”了您的问题,或者发布一个解释如何解决问题的答案并在两天限制过后接受它,或者删除问题,不要只在“已解决”部分进行编辑回答你的问题。
标签: c# concurrency task volatile memory-model