Justinus Hermawan
Justinus Hermawan

Reputation: 1214

Losing [ThreadStatic] value after calling a Task

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?

Upvotes: 2

Views: 852

Answers (1)

Marc Gravell
Marc Gravell

Reputation: 1064114

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 a lock that spans an await, because the compiler knows that lock 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 the await (unless it happens to be a no-op await 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 for ThreadLocal (with some caveats around directionality), but to be honest it would be simpler to just pass the state along explicitly, rather than ambiently.

Upvotes: 4

Related Questions