Alain Metge
Alain Metge

Reputation: 31

Thread affinity with Async in WinRT context

I want use an existing code using ThreadStatic for implementing a per thread singleton (like Transaction.Current)

However, it doesn't work with the async/await model running in a new Task. I know that since SynchronizationContext.Current is null, ThreadPoolTaskScheduler is used and the continuation can be in another thread.

For exemple, if i execute the following code :

Task.Factory.StartNew(async () =>
{                    
   Debug.WriteLine("Start on thread {0}", Environment.CurrentManagedThreadId);
   await Task.Delay(10);
   Debug.WriteLine("Continue on thread {0}", Environment.CurrentManagedThreadId);
});

The result is :

Start on thread 5

Continue on thread 4

My singleton implementation is something like this :

[ThreadStatic]
private static long? _sessionIndex; // Immutable value
private static ConcurrentDictionary<long, ...> contexts;
public static ... Current 
{
  get { 
    return contexts[_sessionIndex ?? (_sessionIndex=Interlocked.Increment(..))];
  }
}

Stephen Cleary propose another solution based on a "singleton per ExecutionContext" which works perfectly in a 4.5.1 context but doesn't work with the limited winrt platform (CallContext doesn't exist)

As a solution, i would try to force the continuation execution in the same thread than the main task to keep the ThreadStatic mechanism.

Implementing a TaskScheduler could be a solution but you can not manipule thread in winrt.

Perhaps with a specific SynchronizationContext but i don't found how. I'm afraid that is not possible.

Any idea ?

Upvotes: 3

Views: 580

Answers (1)

Stephen Cleary
Stephen Cleary

Reputation: 457057

I have a couple types AsyncContext and AsyncContextThread in my AsyncEx library which define a single-threaded context. They provide a custom TaskScheduler and SynchronizationContext.

The AsyncContextThread works by taking a task from the thread pool, installing a main loop, and keeping that task until all the asynchronous operations complete. A "return to the same thread" task scheduler / synchronization context must operate this way because there is no way to queue thread pool work to a specific thread.

Upvotes: 5

Related Questions