当我在 debug 模式下运行以下代码时,它将成功完成并退出。但是,如果我在 release 模式下运行以下代码,它将陷入无限循环而永远不会完成。
static void Main(string[] args)
{
bool stop = false;
new Thread(() =>
{
Thread.Sleep(1000);
stop = true;
Console.WriteLine("Set \"stop\" to true.");
}).Start();
Console.WriteLine("Entering loop.");
while (!stop)
{
}
Console.WriteLine("Done.");
}
哪种优化导致它陷入无限循环?
答案 0 :(得分:18)
我的猜测是主线程上stop
变量的处理器缓存。在调试模式下,内存模型更严格,因为调试器需要能够在所有线程中提供变量状态的合理视图。
尝试制作字段并将其标记为volatile:
volatile bool stop = false;
static void Main(string[] args)
{
new Thread(() =>
{
Thread.Sleep(1000);
stop = true;
Console.WriteLine("Set \"stop\" to true.");
}).Start();
Console.WriteLine("Entering loop.");
while (!stop)
{
}
Console.WriteLine("Done.");
}
答案 1 :(得分:11)
因为它不是线程安全的,所以更新子线程内的主线程变量stop
。它永远是不可预测的。要处理此类情况,请查看this article。
volatile关键字指示编译器生成 在每次从该字段读取时获取栅栏,并释放栅栏 每次写入该字段。获取围栏阻止其他 在围栏前移动读/写;释放围栏 防止在围栅后移动其他读/写。这些 “半围栏”比完全围栏更快,因为它们给了 运行时和硬件的优化范围更广。
答案 2 :(得分:0)
线程不安全代码是不可预测的。主要问题是从另一个线程更改一个线程变量。使变量全局或不稳定。您可以按照
进行操作static volatile bool stop = false;
static void Main(string[] args)
{
new Thread(() =>
{
Thread.Sleep(1000);
stop = true;
Console.WriteLine("Set \"stop\" to true.");
}).Start();
Console.WriteLine("Entering loop.");
while (!stop)
{
}
Console.WriteLine("Done.");
}
答案 3 :(得分:0)
看起来对局部变量的值进行某种优化 - 更改为字段使其终止正常(请注意,在实际代码中应使用易失性或正确的锁定):
using System;
using System.Threading;
class Program
{
static bool stop = false;
static void Main(string[] args)
{
new Thread(() =>
{
Thread.Sleep(1000);
stop = true;
Console.WriteLine("Set \"stop\" to true.");
}).Start();
Console.WriteLine("Entering loop.");
while (!stop)
{
}
Console.WriteLine("Done.");
}
}