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

本文关键字:线程 一个 创建 多线程 覆盖 我的 | 更新日期: 2023-09-27 18:25:51

我想将测试分散在多个线程上,所以首先我将要测试的总数除以我想要的线程数量(包括剩余部分)。然后,我将测试的数字范围分配给每个线程。每次检测结果为阳性时,计数器都会递增。我在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();
}

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

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

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

这是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);
});

由于不同步,您丢失了某个锁定。我以前也遇到过类似的问题,只是我迭代了一个列表,并且我有一个有效的索引值(使用list.Count时不可能超出范围),但事实确实如此。因为我没有合适的锁
问题可能出在CountNumbers方法中。