5

交换两行代码我有两个不同的结果(done = true 与 Console.Write() one

如果我把done = true,首先,结果将是: True

否则,如果我先放置 Console.WriteLine(),结果将是: False False

为什么?(仔细看,那个 bool 变量是静态的!)

using System;
using System.Threading;

class Program
{
    static bool done;

    static void Main(string[] args)
    {
        new Thread(test).Start();
        test();
    }

    static void test()
    {
        if (!done)
        {
            done = true;
            Console.WriteLine(done);
        }
    }
}
4

4 回答 4

8

我敢打赌,当第二次调用有机会执行时,这Console.WriteLine将足以让线程保持忙碌。test()

所以基本上调用WriteLine延迟了done足够长的设置,以便第二次调用test能够测试done并发现它仍然设置为false.

如果您将其保留为如图所示,done = true;在写入控制台之前,它将几乎立即设置,因此对 test 的第二次调用将发现done设置为true,因此不会执行Console.WriteLine.

希望一切都说得通。


我刚刚发现它包含的代码非常像你的问题。如果你还没有从这个页面得到你的问题,那么我建议你阅读一下,因为它更详细地解释了这种影响的原因。

使用以下密钥提取:

在单处理器计算机上,线程调度程序执行时间片——在每个活动线程之间快速切换执行。在 Windows 下,时间片通常在几十毫秒范围内——比在一个线程和另一个线程之间实际切换上下文的 CPU 开销(通常在几微秒范围内)要大得多。

所以本质上调用需要Console.WriteLine足够长的时间让处理器决定是时候让主线程在允许你的额外线程继续之前再进行一次(并最终设置done标志)

于 2012-08-17T08:17:18.777 回答
4

您的代码不是线程安全的,结果将是不可预测的。

读取/写入静态布尔值时需要锁定访问权限,如下所示:

    static bool done;
    static readonly object _mylock = new object();
    static void Main()
    {
        //Application.EnableVisualStyles();
        //Application.SetCompatibleTextRenderingDefault(false);
        //Application.Run(new Form1());
        new Thread(test).Start();
        test();
        Console.ReadKey();
    }

    static void test()
    {
        lock (_mylock)
        {
            if (!done)
            {
                Console.WriteLine(done);
                done = true;
            }
        }
    }

编辑:只读感谢@d4wn

于 2012-08-17T08:24:19.803 回答
1

看起来调度程序只是在调用后从一个线程中减少 CPU 时间,Console.Writeline然后将其交给另一个线程,之前done都设置为true.

您确定它总是在您分配之前False\nFalse调用时打印吗?据我了解,这应该是相当随机的。Console.Writelinedone = true;

于 2012-08-17T08:19:40.737 回答
0

每次共享线程之一访问共享变量时,都必须明确地受到同步技术之一的保护。环境(clr..)并没有为我们做这件事,因为在多线程的整个可能的复杂性中,这是不可能的。所以这个绝对负责且不容易的任务必须由开发人员完成,编写多线程代码。

我想你可以在那里找到大量必要的信息: Thread Synchronization (C# Programming Guide)

于 2012-08-17T14:56:10.370 回答