Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C#/.Net Using ThreadLocal with Async/Await

Let's imagine code like this:

private static readonly ThreadLocal<int> MyInt = new ThreadLocal<int>(() => 3);

DoSomething()
{
    var A = DoSomethingElse()
    MyInt += A;
}

So, every thread would have a copy of MyInt.

but if we did something like that:

private static readonly ThreadLocal<int> MyInt = new ThreadLocal<int>(() => 3);

async DoSomething()
{
    var A = await DoSomethingElse();
    MyInt += A.Result();
}

Is is possible that, when the execution resumes from the await call, we would be in another thread and MyInt += A would add A to the wrong MyInt?

like image 373
Thomas Avatar asked May 10 '26 02:05

Thomas


2 Answers

Yes, there is no guarantee that execution resumes on the same thread. But you can use AsyncLocal instead
https://msdn.microsoft.com/en-us/library/dn906268(v=vs.110).aspx

like image 158
khoroshevj Avatar answered May 11 '26 15:05

khoroshevj


I think @khoroshevj 's answer is incomplete. It isn't that simple.

If, when you await, there is synchronization context available it will be captured and you will resume on that context because you have not explicitly told it that it doesn't need to with ConfigureAwait(false). Be aware that you may resume on the same context with ConfigureAwait(false) because that is not an instruction to switch context, it is an indication that it is OK to resume on a different context if that is what the runtime decides is best.

So, pretty much if this is not a console app and you have not set a new SynchronizationContext.Current, then you will resume where you left off.

If DoSomethingElse() or anything in it's relative call stack also accesses the threadlocal variable then you will be in trouble.

So for safety you should probably use AsyncLocal but the code you have shown should work as intended.

like image 35
Crowcoder Avatar answered May 11 '26 15:05

Crowcoder