我想在多个线程上传播一个测试,所以首先我将我想测试的总数除以我想要的线程数(包括余数)。然后我将测试范围的数字分配给每个线程。每次测试为正时,计数器都会递增。我在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#比较陌生,所以我很难找到这个缺陷。这是为了学校,所以正确方向的暗示可能更适合干净的答案。
答案 0 :(得分:3)
这是C#并行编程中的常见错误。当您通过lambda表达式声明匿名函数时,它们会捕获它们引用的任何变量(而不是值)。在您的情况下,您的所有线程都在为n
或m
计数器捕获相同的变量实例,导致其所有执行都看到它的最后一个值。
解决此问题的一种简单方法是在循环范围内声明另一个变量,并将计数器复制到它。由于范围仅限于循环,因此不会在您的线程中共享变量。
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方法中。