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 alock
that spans anawait
, because the compiler knows thatlock
requires 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-opawait
on 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.