Unexpected behaviour for ThreadPool.QueueUserWorkItem

孤者浪人 提交于 2019-12-01 05:16:08
Ani

This is the old modified closure problem. You might want to look at: Threadpools - possible thread execution order problem for a similar question, and Eric Lippert's blog post Closing over the loop variable considered harmful for an understanding of the issue.

Essentially, the lambda expression you've got there is capturing the variable s rather than the value of the variable at the point the lambda is declared. Consequently, subsequent changes made to the value of the variable are visible to the delegate. The instance of Sample on which the RunCount method will run will depend on the instance referred to by the variable s (its value) at the point the delegate actually executes.

Additionally, since the delegate(s) (the compiler actually reuses the same delegate instance) are being asynchronously executed, it isn't guaranteed what these values will be at the point of each execution. What you are currently seeing is that the foreach loop completes on the main-thread before any of the delegate-invocations (to be expected - it takes time to schedule tasks on the thread-pool). So all the work-items end up seing the 'final' value of the loop-variable. But this isn't guaranteed by any means; try inserting a reasonable-duration Thread.Sleep inside the loop, and you will see a different output.


The usual fix is to:

  1. Introduce another variable inside the loop-body.
  2. Assign that variable to the current value of the loop-variable.
  3. Capture the 'copy' variable instead of the loop-variable inside the lambda.

    foreach (Sample s in arrSample)
    {
        Sample sCopy = s;
        ThreadPool.QueueUserWorkItem(callback => sCopy.RunCount());
    }
    

Now each work-item "owns" a particular value of the loop variable.


Another option in this case is to dodge the issue completely by not capturing anything:

ThreadPool.QueueUserWorkItem(obj => ((Sample)obj).RunCount(), s);
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!