2011-12-22 88 views
4

我需要在一次(并行)中使用60个线程,因为我使用ThreadPool。我在这里有例外:线程池例外

temp = 1; 
for (int j = 0; j < temp; j++) { 
    ThreadPool.QueueUserWorkItem(delegate(object notUsed) { 
     RequestToRajons(rajs_ip[j].ToString(),rajs_name[j].ToString(), sql_str, base_str, saveFileDialog1,j); 
    }); 
} 

这让我异常j=1(数组越界)。但我有一个contidion! 如果我用步骤使用断点,我没有发生异常。

回答

12

这是经典的/捕获问题,因为您正在“捕获”j,并且只有一个j。你的所有线程都使用相同的j变量进行处理;它们看到的是不确定的,但最后几个线程很可能会看到循环的值出口,即太多。

相反:

for (int loopIndex = 0; loopIndex < temp; loopIndex++) 
{ 
    int j = loopIndex; 
    // the following line has not changed at all 
    ThreadPool.QueueUserWorkItem(delegate(object notUsed) { RequestToRajons(rajs_ip[j].ToString(),rajs_name[j].ToString(), sql_str, base_str, saveFileDialog1,j); }); 
} 

这听起来很傻,但你现在有一个j每次循环迭代,因为捕获的范围取决于该变量的声明范围。这里,j定义为里面的这个循环。在for循环中,变量在技术上定义为外部循环。


另一种方式做,这是使用参数的线程池:

for(int loopIndex = 0; loopIndex < temp; loopIndex++) 
{ 
    ThreadPool.QueueUserWorkItem(delegate(object ctx) { 
     int j = (int) ctx; 
     // stuff involving j 
    }, loopIndex); // <=== see we're passing it in, rather than capturing 
} 

这里是如何“捕捉变量”的扩展版本和匿名方法的工作,过简化版本;首先,编译器可以实现这个要求:

class CaptureContext { // <== the real name is gibberish 
    public int j; // yes it is a field; has to be, so `ref` and `struct` etc work 
    public void SomeMethod(object notUsed) { 
     RequestToRajons(rajs_ip[j].ToString(),rajs_name[j].ToString(), sql_str, base_str, saveFileDialog1,j); 
    } 
    // it might also be capturing "this"; I can't tell from your example 
} 

和你的方法变(因为j技术上外循环定义):现在

var ctx = new CaptureContext(); 
for (ctx.j = 0; ctx.j < temp; ctx.j++) { 
    ThreadPool.QueueUserWorkItem(ctx.SomeMethod); 
} 

;你能否看到只有一个“捕获”对象,并且我们在随机点使用它的时间不是我们认为的那样?此修复程序重写,作为:

for (int loopIndex = 0; loopIndex < temp; loopIndex++) { 
    var ctx = new CaptureContext(); 
    ctx.j = loopIndex; 
    ThreadPool.QueueUserWorkItem(ctx.SomeMethod); 
} 

在这里,你可以看到有一个“捕获”对象每次迭代,这是因为j声明循环? “什么是新捕获上下文”取决于捕获的变量的范围

+0

起初看起来和我写的一样。但它的工作 - 谢谢。你能否向我解释更多细节? – Oleg 2011-12-22 12:13:13

+0

@Oleg我已经添加了几行试图解释这一点 - 是否还不清楚? – 2011-12-22 12:15:07

+0

不用了,谢谢!这是很好的答案! – Oleg 2011-12-22 12:15:59