ThreadPool exception

I need to use 60 threads at a time (in parallel), and for this I use ThreadPool. I have an exception:

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

This gives me the exception that j=1 (an array is out of range). But I have an end! If I use a breakpoint with a step, I have no exception.

+4
source share
1 answer

This is a classic problem for / capture, because you capture j , and there is only one j . All your threads are processed using the same j variable; the value they see is undefined, but the last few threads most likely see the exit value of the loop, that is, too much.

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 now you have iteration j on each loop, because the capture area depends on the variable declaration area. Here j is defined inside the loop. In a for loop, a variable is technically defined outside the loop.


Another way to do this is to use a parameter in 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 is an extended version of how the "captured variables" and anonymous methods work, a more 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 (since j technically defined outside the loop):

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

currently; you see that there is only one β€œcapture” object, and we use it at random points at times when ctx.j not necessarily what we thought it was? The fix overwrites this as:

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

here you see that there is a capture object to iterate because j declared internally in a loop? β€œWhat is the new capture context” depends on the scope of the captured variables.

+12
source

Source: https://habr.com/ru/post/1387555/


All Articles