I need to use 60 threads in one time(parallelly) and for it I use ThreadPool. I have exception here:
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);
});
}
It's gives me exception that j=1
(array out of range). But I have a contidion!
If I use a breakpoint with step, I haven't got an exception.
This is the classic for/capture issue, because you are "capturing" j
, and there is only one j
. All your threads are processing using the same j
variable; the value they see is indeterminate, but the last several threads will most likely see the exit value of the loop, i.e. one too many.
Instead:
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); });
}
it sounds silly, but you now have a j
per loop iteration, because the scope of the capture depends on the declaration scope of the variable. Here, j
is defined inside the loop. In the for
loop, the variable is technically defined outside the loop.
Another way to do this is to use the parameter to the thread-pool:
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
}
Here's an expanded version of how "captured variables" and anonymous methods work, the over-simplified version; firstly, the compiler does this for you:
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
}
and your method becomes (because j
is technically defined outside the loop):
var ctx = new CaptureContext();
for (ctx.j = 0; ctx.j < temp; ctx.j++) {
ThreadPool.QueueUserWorkItem(ctx.SomeMethod);
}
now; can you see that there is only one "capture" object, and that we're using it at random points in times where ctx.j
is not necessarily what we thought it was? The fix rewrites that as:
for (int loopIndex = 0; loopIndex < temp; loopIndex++) {
var ctx = new CaptureContext();
ctx.j = loopIndex;
ThreadPool.QueueUserWorkItem(ctx.SomeMethod);
}
here, can you see there is a "capture" object per iteration, which is because the j
is declared inside the loop? The "what is a new capture context" depends on the scope of the variables that are captured.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With