首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ThreadPool异常

ThreadPool异常
EN

Stack Overflow用户
提问于 2011-12-22 20:05:58
回答 1查看 356关注 0票数 4

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

代码语言:javascript
复制
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(数组超出范围)。但我有个条件!如果我在步骤中使用断点,我没有得到异常。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2011-12-22 20:08:29

这是典型的for/capture问题,因为您正在“捕获”j.,而只有一个 j您的所有线程都使用相同的j变量进行处理;它们看到的值是不确定的,但最后几个线程很可能看到循环的exit值,即多了一个。

而是:

代码语言:javascript
复制
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循环中,变量在技术上定义为循环外部的变量。

另一种方法是使用线程池的参数:

代码语言:javascript
复制
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
}

下面是“捕获变量”和匿名方法的工作原理的扩展版本,这是一个过于简化的版本;首先,编译器会为您做这件事:

代码语言:javascript
复制
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在技术上是在循环之外定义的):

代码语言:javascript
复制
var ctx = new CaptureContext();
for (ctx.j = 0; ctx.j < temp; ctx.j++) {
    ThreadPool.QueueUserWorkItem(ctx.SomeMethod);
}

现在,您是否看到只有一个“捕获”对象,并且我们在随机时间点使用它,而ctx.j不一定是我们所认为的那样?修复程序将其重写为:

代码语言:javascript
复制
for (int loopIndex = 0; loopIndex < temp; loopIndex++) {
    var ctx = new CaptureContext();
    ctx.j = loopIndex;
    ThreadPool.QueueUserWorkItem(ctx.SomeMethod);
}

在这里,您可以看到每个迭代都有一个“捕获”对象,这是因为该j循环中被声明为?“什么是新捕获上下文”取决于所捕获变量的作用域。

票数 12
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8603644

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档