for循环创建任务超过最终条件

时间:2014-12-17 13:33:11

标签: c# concurrency

我有一个for循环来创建一些参数化的任务:

int count = 16;

List<Tuple<ulong, ulong>> brackets = GetBrackets(0L, (ulong)int.MaxValue, count);
Task[] tasks = new Task[count];

s.Reset();
s.Start();

for(int i = 0; i < count; i++)
{
    tasks[i] = Task.Run(() => TestLoop(brackets[i].Item1, brackets[i].Item2));
}

Task.WaitAll(tasks);

s.Stop();

times.Add(count, s.Elapsed);

然而,当它运行时,For循环内的行抛出一个异常,括号[i]不存在,因为我在那一点是16,即使循环被设置为在i&lt;计数。

如果我将行更改为:

tasks[i] = new Task(() => TestLoop(brackets[0].Item1, brackets[0].Item2));

然后不会抛出任何错误。此外,如果我使用断点遍历循环,则不会抛出任何问题。

对于repro,我还包括GetBrackets,它只是将数字范围分成块:

private List<Tuple<ulong, ulong>> GetBrackets(ulong start, ulong end, int threads)
{
    ulong all = (end - start);
    ulong block = (ulong)(all / (ulong)threads);
    List<Tuple<ulong, ulong>> brackets = new System.Collections.Generic.List<Tuple<ulong, ulong>>();

    ulong last = 0;
    for (int i=0; i < threads; i++)
    {
        brackets.Add(new Tuple<ulong, ulong>(last, (last + block - 1)));
        last += block;
    }

    // Hack
    brackets[brackets.Count - 1] = new Tuple<ulong, ulong>(
        brackets[brackets.Count - 1].Item1, end);

    return brackets;
}

有人可以对此有所了解吗?

1 个答案:

答案 0 :(得分:0)

(这是类似帖子的重复,但它们通常很难找到,症状通常略有不同。)

问题在于您在循环中捕获变量i

for(int i = 0; i < count; i++)
{
    tasks[i] = Task.Run(() => TestLoop(brackets[i].Item1, brackets[i].Item2));
}

你有一个单个 i变量,lambda表达式捕获它 - 所以当你的任务实际开始执行lambda表达式中的代码时,它可能是赢得具有与之前相同的价值。你需要在循环中引入一个单独的变量 ,这样每次迭代都会捕获一个不同的变量:

for (int i = 0; i < count; i++)
{
    int index = i;
    tasks[i] = Task.Run(() => TestLoop(brackets[index].Item1, brackets[index].Item2));
}

或者,使用LINQ创建任务数组:

var tasks = brackets.Select(t => Task.Run(() => TestLoop(t.Item1, t.Item2));
                    .ToArray(); // Or ToList