3

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

1 Answer 1

2

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.

Sign up to request clarification or add additional context in comments.

3 Comments

Please correct me if I am wrong: I understand that the variables in a lambda function are evaluated when that function is called. So in my case the 'param' string was still in scope in one thread, and when the lambda executed in another thread it would use and whatever value 'param' had at that moment. So in response to your statement "now each lambda is closing over it's own variable", I ask what makes a variable "owned" by a lambda? Is it owned if it is not in scope anywhere else?
@jltrem The lambda doesn't "own" it, it's simply a question of whether two lambdas are closing over the same one variable, or whether there are two variables so that each variable is only ever closed over by one lambda. In some cases it's desirable for multiple lambdas to close over one variable, you have indicated that, in this case, you don't want that, so the way to avoid it is to create new variables.
Really my confusion was not understanding the concept of closure. I did not fully comprehend the connection between 1) lambda expressions capture variables, and 2) captured variables are not evaluated until the code is invoked. It just hadn't sunk in. Rookie mistake. Thanks for setting me in the right direction.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.