【问题标题】:Threads receiving wrong parameters线程接收错误的参数
【发布时间】:2012-09-01 16:44:08
【问题描述】:

我需要在线程中运行具有给定参数的方法。我注意到,当我运行它时, 参数错误。对于给出的示例,我有一个数组int[] output,其数字为 1-7。对于每个数字,我使用方法WriteInt(i) 创建一个线程。我希望输出以任何顺序为 1-7,但我始终看到一些数字丢失而另一些数字重复。发生了什么以及启动这些线程的正确方法是什么?

(该列表仅用于之后加入线程)

class Program
{
    static void Main(string[] args)
    {
        int[] output = { 1, 2, 3, 4, 5, 6, 7 };

        List<Thread> runningThreads = new List<Thread>();

        foreach (int i in output)
        {
            Thread thread = new Thread(() => WriteInt(i));
            thread.Start();
            runningThreads.Add(thread);
        }
        foreach(Thread t in runningThreads)
        {
            t.Join();
        }
    }

    private static void WriteInt(int i)
    {
        Console.WriteLine(i);
    }
}

示例输出:

3
3
4
5
6
7

【问题讨论】:

  • 尝试并行 foreach。这样您就不会创建更多线程并最终造成性能威胁。
  • 不幸的是,我们被困在没有并行 foreach 的 .net 3.5 上。

标签: c# multithreading .net-3.5


【解决方案1】:

由 lambda (() =&gt; WriteInt(i)) 创建的闭包正在关闭变量 i,而不是每次迭代中设置为i 的值。当线程运行时,它使用在该时间点在i 中设置的值,由于foreach 循环处理,该值可能已经更改。

你需要一个临时的:

foreach (int i in output)
{
        int temp = i;
        Thread thread = new Thread(() => WriteInt(temp));
        thread.Start();
        runningThreads.Add(thread);
}

有关正在发生的事情的详细信息,请参阅 Eric Lippert 的帖子,标题为 Closing over the loop variable considered harmful

此外,在 C# 5 (VS2012) 中,这不再是 foreach 循环的问题。但是,它仍然会在 for 循环中发生。

【讨论】:

  • +1。 temp 变量的替代方法是使用 ParameterizedThreadStart 构造函数将 i 作为参数传递。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-09
  • 2011-11-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多