I'm using a variable with [ThreadStatic] attribute to store the current active Session for each socket (I'm using WebSocket as the connection type). In the beginning of socket connect, I assign its value with a new Session object, and then executing a Task method to get an output. After the Task is completed, the Session value become null.
ThreadStatic declaration:
public class Session
{
...
[ThreadStatic] public static Session _session;
}
Task method to call:
public async Task<string> Connect()
{
var path = Path.Combine(Directory.GetCurrentDirectory(), "storyboard", "1.json");
var json = await File.ReadAllTextAsync(path, Encoding.UTF8);
return $"\"i\":{this.id},\"m\":\"build\",\"a\":{json}";
}
The task execution part:
// Session._session == null ? --> false (here, the value still exists)
var res = await obj.Item1.Execute(met, args); // execute a method with async call
await Session._session.Send(res); // Session._session == null ? --> true
What's wrong here?
Tasks and threads are largely unrelated concepts, and importantly: in most interesting scenarios, any time you
await, you are inherently potentially changing thread. Incidentally, that is why you can't have alockthat spans anawait, because the compiler knows thatlockrequires the same thread at both sides.Because of this, anything that is thread-specific, such as
[ThreadStatic], is probably going to be invalid when you get back from theawait(unless it happens to be a no-opawaiton a synchronous or completed operation, or if there is a sync-context in play that is reliably pushing work back to the same thread).There is an
AsyncLocal<T>that is probably more suitable for your scenario, and can largely be swapped forThreadLocal(with some caveats around directionality), but to be honest it would be simpler to just pass the state along explicitly, rather than ambiently.