【问题标题】:Starting Tasks inside a for loop: unexpected behaviour [duplicate]在 for 循环中启动任务:意外行为 [重复]
【发布时间】:2016-08-05 06:05:58
【问题描述】:

我正在学习 C# 中的多线程。这让我很难,所以我正在做一些简单的程序来更好地理解它。

我意识到如果我有:

   static void Main()
    {
        Task[] tasks = new Task[4];
        for (int i = 0; i < 4; i++)
        {
            tasks[i] = Task.Factory.StartNew(() => {
                Console.WriteLine(i);
            });
        }
        Console.ReadKey();
    }

输出是 4444,不像我预期的那样是 0123。 为什么会这样?

编辑:

Sadiq 在他的回答中说,这种行为的原因是因为我正在关闭一个循环变量。但是,如果我在 lambda 语句之外和循环内部添加代码 Thread.sleep(500);,我会得到 0123。 那么,为什么添加这行代码不会发生这种所谓的clousures引起的行为?

在我看来,所问行为的原因是其他的。如果你不明白我刚刚写的内容,代码:

static void Main()
    {
        Task[] tasks = new Task[4];
        for (int i = 0; i < 4; i++)
        {
            tasks[i] = Task.Factory.StartNew(() => {
                Console.WriteLine(i);
            });
            Thread.Sleep(500); 
        }
        //Now the output is: 0123
        Console.ReadKey();
    }

【问题讨论】:

  • “为什么在添加这行代码时不会发生这种由clousures引起的行为” - 因为您现在在循环的每次迭代之间等待500毫秒,因此允许Task在循环的下一次迭代更新相同的变量之前,在捕获的变量上运行完成。

标签: c# multithreading for-loop c#-4.0 task


【解决方案1】:

创建一个局部变量 - 将值复制到其中,您应该会得到预期的输出:

static void Main()
{
    Task[] tasks = new Task[4];
    for (int i = 0; i < 4; i++)
    {
        int x = i;
        tasks[x] = Task.Factory.StartNew(() => {
            Console.WriteLine(x);
        });
    }
    Console.ReadKey();
}

得到意外输出的原因是i 被共享。 You are closing over a loop variable.

【讨论】:

  • 感谢您的回答,萨迪克。但关键是为什么这种行为而不是我认为的行为?
  • @PabloDeLuca - 请查看我的编辑。
  • 也请查看我的编辑。
  • @PabloDeLuca - 原因是因为数据竞争 - 您试图避免使用睡眠。在不加锁的情况下修改共享变量总是会导致意想不到的结果。见这里:stackoverflow.com/questions/9992866/…
  • 谢谢。我真的不知道。
猜你喜欢
  • 1970-01-01
  • 2021-03-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-03
  • 2013-01-28
  • 2013-05-30
相关资源
最近更新 更多