【问题标题】:Starting threads in a loop passing array elements to each在循环中启动线程,将数组元素传递给每个线程
【发布时间】:2013-07-20 00:45:57
【问题描述】:

我在一个循环中启动 4 个线程。每个线程获取对数组元素的引用以写入结果。

但是在我创建每个线程的那一行,我得到一个System.IndexOutOfRangeException。我很惊讶索引“i”超出了范围。

这是一个例子:

void ThreadsStarter()
{
    double[] data = new double[4];

    for(int i = 0; i < 4; i++)
    {
        Thread my_thread = new Thread(() => Work(data[i]));
        my_thread.Start();
    }
}

void Work(double data)
{
}

为什么会这样?

【问题讨论】:

  • 我已从您的示例/标题中删除了与问题无关的 ref - 请随时编辑/回滚。注意ref 通常很难使用/理解,尤其是当您开始使用更灵活的集合(如List&lt;double&gt; 而不是Array)时。尽量避免使用ref - 即在这种情况下,Tuple.Create(data, i) 可能是一个选项(显然是在 lambda 之前创建以避免您现在遇到的问题)。
  • 谢谢。现在我也知道那个结构的名称(闭包/lambdas)。我确实尽量避免参考。我会考虑改用元组,这看起来更干净。这是一篇好文章 Blorgbeard。

标签: c# arrays multithreading indexoutofboundsexception ref


【解决方案1】:

这是一个常见错误:i 在线程启动时被评估,这发生在循环结束后。创建一个 temp,将 i 分配给它,然后在 lambda 中使用 temp 而不是 i 来解决问题:

void ThreadsStarter()
{
    double[] data = new double[4];

    for(int i = 0; i < 4; i++)
    {
        var temp = i;
        Thread my_thread = new Thread(() => Work(ref data[temp]));
        my_thread.Start();
    }
}

void Work(ref double data)
{
}

【讨论】:

  • 这是有效的,因为当您重新创建临时变量时,编译器会检测到闭包在每次循环传递时都“附加”到不同的变量,并将生成一个“new DisplayClass ()" 代码(它封装了闭包)在每一次传递中。如果没有 temp 变量,它将在所有循环传递中使用相同的 DisplayClass(其中包含 i 变量的成员)。 (类似于 c# 5 为 foreach 循环生成的代码 - 请参阅示例 here)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-08
  • 2016-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多