强制一个 .NET,多线程易失性优化错误
Forcing a .NET, multithreaded volatile optimization bug
我正在尝试通过 C# 重现 CLR 中描述的错误。当使用优化编译以下代码时,s_stopWorker
变量仅被检查一次(并且是 false
),因此应用程序永远不会终止。
private static bool s_stopWorker;
public static void Main()
{
Console.WriteLine("Main: letting worker run for 5 seconds");
var t = new Thread(Worker);
t.Start();
Thread.Sleep(5000);
s_stopWorker = true;
Console.WriteLine("Main: waiting for worker to stop");
t.Join();
}
private static void Worker(object o)
{
var x = 0;
while (!s_stopWorker) x++;
Console.WriteLine("Worker: stopped when x={0}", x);
}
这确实是正在发生的事情(在 x86 和 x64 上,与本书相反)。
如果我在 while
中放置一个 Console.Write
然后优化就不会再发生了。
private static bool s_stopWorker;
public static void Main()
{
Console.WriteLine("Main: letting worker run for 5 seconds");
var t = new Thread(Worker);
t.Start();
Thread.Sleep(5000);
s_stopWorker = true;
Console.WriteLine("Main: waiting for worker to stop");
t.Join();
}
private static void Worker(object o)
{
var x = 0;
while (!s_stopWorker)
{
Console.Write(string.Empty); // <-- Added line
x++;
}
Console.WriteLine("Worker: stopped when x={0}", x);
}
现在错误已经消失,应用程序退出就像没有发生优化一样。
Main: letting worker run for 5 seconds
Main: waiting for worker to stop
Worker: stopped when x=130084144
为什么添加 Console.Write
可以修复此错误?
Console.Write
中的代码可以更改静态字段的值。它不知道,但 JIT 不知道。因此它必须生成代码以在每次迭代时加载静态字段。
您可以通过调用未设置内联标志的空方法来实现相同的效果。这是 JIT 的黑匣子。
JIT 可以 分析所有可能被传递调用的代码并得出结论,静态字段不会改变。但这在JIT中并没有实现。
我正在尝试通过 C# 重现 CLR 中描述的错误。当使用优化编译以下代码时,s_stopWorker
变量仅被检查一次(并且是 false
),因此应用程序永远不会终止。
private static bool s_stopWorker;
public static void Main()
{
Console.WriteLine("Main: letting worker run for 5 seconds");
var t = new Thread(Worker);
t.Start();
Thread.Sleep(5000);
s_stopWorker = true;
Console.WriteLine("Main: waiting for worker to stop");
t.Join();
}
private static void Worker(object o)
{
var x = 0;
while (!s_stopWorker) x++;
Console.WriteLine("Worker: stopped when x={0}", x);
}
这确实是正在发生的事情(在 x86 和 x64 上,与本书相反)。
如果我在 while
中放置一个 Console.Write
然后优化就不会再发生了。
private static bool s_stopWorker;
public static void Main()
{
Console.WriteLine("Main: letting worker run for 5 seconds");
var t = new Thread(Worker);
t.Start();
Thread.Sleep(5000);
s_stopWorker = true;
Console.WriteLine("Main: waiting for worker to stop");
t.Join();
}
private static void Worker(object o)
{
var x = 0;
while (!s_stopWorker)
{
Console.Write(string.Empty); // <-- Added line
x++;
}
Console.WriteLine("Worker: stopped when x={0}", x);
}
现在错误已经消失,应用程序退出就像没有发生优化一样。
Main: letting worker run for 5 seconds
Main: waiting for worker to stop
Worker: stopped when x=130084144
为什么添加 Console.Write
可以修复此错误?
Console.Write
中的代码可以更改静态字段的值。它不知道,但 JIT 不知道。因此它必须生成代码以在每次迭代时加载静态字段。
您可以通过调用未设置内联标志的空方法来实现相同的效果。这是 JIT 的黑匣子。
JIT 可以 分析所有可能被传递调用的代码并得出结论,静态字段不会改变。但这在JIT中并没有实现。