我的多线程创建或覆盖额外/现有线程

时间:2015-12-04 18:36:34

标签: c# multithreading

我想在多个线程上传播一个测试,所以首先我将我想测试的总数除以我想要的线程数(包括余数)。然后我将测试范围的数字分配给每个线程。每次测试为正时,计数器都会递增。我在0到123的范围内测试它,因为我知道结果应该是什么,但每当我为任务分配多于1个线程时,我得到错误的结果。在调试时,我注意到在线程启动后,当前行会跳回到分配新线程。我不明白为什么。我有一个锁的保护柜,据我所知,它正常工作。这是相应的代码:

for (int n = 0; n < remainder; n++)
{
      workers[n] = new Thread(() => CountNumbers(startvalue + n * (tasks + 1), startvalue + (n + 1) * (tasks + 1), modulus));
}
for (int m = remainder; m < nrthreads; m++)
{
      workers[m] = new Thread(() => CountNumbers(startvalue + remainder * (tasks + 1) + (m - remainder) * tasks, startvalue + remainder * (tasks + 1) + (m - remainder + 1) * tasks, modulus));
}
for (int k = 0; k < nrthreads; k++)
{
      workers[k].Start();
}
for (int k = 0; k < nrthreads; k++)
{
      workers[k].Join();
}

&#34;问题&#34;当workers[k].Start()为所有k完成时出现,然后由于某种原因覆盖workers中的最后一个线程。

我对C#比较陌生,所以我很难找到这个缺陷。这是为了学校,所以正确方向的暗示可能更适合干净的答案。

2 个答案:

答案 0 :(得分:3)

这是C#并行编程中的常见错误。当您通过lambda表达式声明匿名函数时,它们会捕获它们引用的任何变量(而不是值)。在您的情况下,您的所有线程都在为nm计数器捕获相同的变量实例,导致其所有执行都看到它的最后一个值。

解决此问题的一种简单方法是在循环范围内声明另一个变量,并将计数器复制到它。由于范围仅限于循环,因此不会在您的线程中共享变量。

for (int nOuter = 0; nOuter < remainder; nOuter++)
{
    int n = nOuter;
    workers[n] = new Thread(() => CountNumbers(startvalue + n * (tasks + 1), startvalue + (n + 1) * (tasks + 1), modulus));
}
for (int mOuter = remainder; mOuter < nrthreads; mOuter++)
{
    int m = mOuter;
    workers[m] = new Thread(() => CountNumbers(startvalue + remainder * (tasks + 1) + (m - remainder) * tasks, startvalue + remainder * (tasks + 1) + (m - remainder + 1) * tasks, modulus));
}

编辑:如果切换到使用PLINQ或TPL构造,则可以简化代码。以下内容应与您的整个逻辑相同:

Parallel.For(0, nrthreads, k =>
{
    if (k < remainder)
        CountNumbers(startvalue + k * (tasks + 1), startvalue + (k + 1) * (tasks + 1), modulus);
    else
        CountNumbers(startvalue + remainder * (tasks + 1) + (k - remainder) * tasks, startvalue + remainder * (tasks + 1) + (k - remainder + 1) * tasks, modulus);
});

答案 1 :(得分:0)

由于您不同步,您错过了对某事的锁定。我曾经有过同样的问题,之前我只是在迭代一个列表而且我有一个有效的索引值(当你使用list.Count时不可能超出范围)但它确实如此。因为我没有合适的锁 问题可能在您的CountNumbers方法中。

相关问题