multi-threading and lambda variable scope

2019-01-28 08:58发布

问题:

I am using a class that manages a pool of threads to run actions. Originally it was coded to take an Action (with no parameter) and I was calling it like this:

void LoadTasks()
{
   string param;

   // some code loops and changes param
   {
      threadPool.EnqueueTask(() => SomeMethod(param));
   }
}

As the threads ran some were fine, but occasionally the param variable was not what I expected ... it was a "newer" value and not what I intended to send to the method.

Changing the thread pool to accept Action<Object> and calling without a lambda -- like this threadPool.EnqueueTask(SomeMethod, param) -- worked around my problem.

I see quite a few questions about C# lambdas about thread-safety. For example, an accepted answer of lambdas are much less likely to be thread safe than you would expect. I'm finding other questions and answers about lambdas/closures/scoping to be confusing. So I am looking for an explanation of lambdas and variable scope, ideally relating to the problem in my example.

回答1:

So the problem is that you're closing over variables that you don't mean to. The easy fix in most all cases is to create a new local variable, copy the variable you were once closing over, and then close over that instead.

So instead of:

for(int i = 0; i < number; i++)
{
    threadPool.EnqueueTask(() => SomeMethod(someList[i]));
}

You can just do:

for(int i = 0; i < number; i++)
{
    int copy = i;
    threadPool.EnqueueTask(() => SomeMethod(someList[copy]));
}

Now each lambda is closing over it's own variable, rather than having all of them close over the same one variable.