2

我有以下示例程序:

using System;
using System.Threading;
using System.Threading.Tasks;

namespace StackoverflowExample
{
    class Program
    {
        static int value = 1;
        static void Main(string[] args)
        {
            Task t1 = Task.Run(() =>
            {
                if (value == 1)
                {
                    Thread.Sleep(1000);
                    value = 2;
                }
            });

            Task t2 = Task.Run(() =>
            {
                value = 3;
            });

            Task.WaitAll(t1, t2);
            Console.WriteLine(value);
            Console.ReadLine();
        }
    }
}

我希望这段代码能够输出2。我想t1会看到该值为1,然后休眠一秒钟,在此时间t2将值设置为3,然后t1将其更改回2

这是附加调试器时发生的行为(在 Visual Studio 中按 F5)。但是,当我在没有附加调试器的情况下运行该程序(Visual Studio 中的 Ctrl + F5)时,输出为3.

为什么?

4

3 回答 3

2

t2 没有理由不能在 t1 之前开始运行。使用 TPL 库的情况更可能出现(任务首先被推送到 LIFO 堆栈上)。

调试器可以延迟/更改足以产生另一个结果的东西。

任务和线程通常会以这种方式产生误导。

于 2013-07-23T15:07:10.577 回答
1

t2之前开始t1,因此if (value == 1)返回 false。

无法保证线程将按顺序启动。

于 2013-07-23T15:06:23.200 回答
0

你有所谓的“竞争条件”。您有两个动作可能需要不确定的时间,并且取决于谁先开始/结束,您会得到不同的结果。

为避免此类情况,您需要确保您的代码在使用多个线程时在适当的位置使用等待。

using System;
using System.Threading;
using System.Threading.Tasks;

namespace StackoverflowExample
{
    class Program
    {
        static AutoResetEvent sequenceLock = new AutoResetEvent(false);
        static int value = 1;
        static void Main(string[] args)
        {
            Task t1 = Task.Run(() =>
            {
                if (value == 1)
                {
                    sequenceLock.Set(); //lets t2 past the WaitOne()
                    Thread.Sleep(1000);
                    value = 2;
                }
            });

            Task t2 = Task.Run(() =>
            {
                sequenceLock.WaitOne(); //Waits for t1 to set the flag.
                value = 3;
            });

            Task.WaitAll(t1, t2);
            Console.WriteLine(value);
            Console.ReadLine();
        }
    }
}
于 2013-07-23T15:11:35.370 回答