2

我对多线程编程不太满意,当我试图在我的代码中实现它时,遇到了一个我无法弄清楚原因的异常。对此的任何帮助将不胜感激:)
所以,基本上我有这个小代码片段:

string[][] Array1 = new string[thread_count][];

/* Logic to insert data in Array1 */

Thread[] WorkerThreads = new Thread[thread_count];

for (int i = 0; i < thread_count; i++)
{
    /* THE EXCEPTION OCCURS IN THE FOLLOWING LINE */
    WorkerThreads[i] = new Thread(() => GetVal(Array1[i], val, num));
    WorkerThreads[i].Start();
}

for (int i = 0; i < WorkerThreads.Length; i++)
    WorkerThreads[i].Join();  

现在,thread_count 的值设置为 10,我得到了 IndexOutOfRange 异常。调试器将 i 的值显示为 10,而 Array1[10][] 是它试图访问的值。
当循环不应该运行那么远时,我不知道 i 的值如何达到 10。
谁能指出我哪里出错了?我正在使用 C#。

谢谢

4

5 回答 5

3

您有“关闭循环变量”问题,请检查:关闭被认为有害的循环变量以及foreach 标识符和闭包

添加一个临时变量来修复它:

for (int i = 0; i < thread_count; i++)
{
    var j = i;
    /* THE EXCEPTION OCCURS IN THE FOLLOWING LINE */
    WorkerThreads[j] = new Thread(() => GetVal(Array1[j], val, num));
    WorkerThreads[j].Start();
}
于 2013-08-06T03:38:34.410 回答
2

您的问题是您正在创建的 lambda/匿名函数。i在循环退出之前,该变量的值是 10。当您调用 时new Thread(() => GetVal(Array1[i], val, num));,您实际上并没有调用有问题的代码。匿名函数保留对变量的引用i,当您尝试启动线程时,它会查找该引用,发现它的值为 10,然后您会得到异常。

请参阅此网页的“Lambda 表达式中的变量范围”部分:http: //msdn.microsoft.com/en-us/library/vstudio/bb397687.aspx

于 2013-08-06T03:38:39.870 回答
1

您可能会遇到竞争条件,尝试使用System.Collections.Concurrent 命名空间ConcurrentBagBlockingCollection来自System.Collections.Concurrent命名空间,它们使线程编程更容易。

于 2013-08-06T03:37:05.550 回答
1

试试下面

for (int i = 0; i < thread_count; i++)
{
    int copy = i;
    WorkerThreads[copy] = new Thread(() => GetVal(Array1[copy], val, num));
    WorkerThreads[copy].Start();
}
于 2013-08-06T03:38:57.420 回答
0

GetVal(Array[i])导致变量关闭,在i创建线程之前,我将等于 thread_count。在这种情况下,所有线程都会有GetVal(Array[10]),因为它们都引用了最新的i变量。

Array[i]要解决此问题,请在使用它之前创建一个分配给的变量GetVal

for (int i = 0; i < thread_count; i++)
{
    string[] value = Array1[i];

    WorkerThreads[i] = new Thread(() => GetVal(value, val, num));
    WorkerThreads[i].Start();
}
于 2013-08-06T03:42:07.317 回答