我想使用ThreadStatic的现有代码来实现每个线程的单例(如Transaction.Current)
但是,它不适用于在新任务中运行的async / await模型。我知道,由于SynchronizationContext.Current为null,因此使用了ThreadPoolTaskScheduler,并且继续可以在另一个线程中。
例如,如果我执行以下代码:
Task.Factory.StartNew(async () =>
{
Debug.WriteLine("Start on thread {0}", Environment.CurrentManagedThreadId);
await Task.Delay(10);
Debug.WriteLine("Continue on thread {0}", Environment.CurrentManagedThreadId);
});
结果是:
从线程5开始
继续第4课
我的单例实现是这样的:
[ThreadStatic]
private static long? _sessionIndex; // Immutable value
private static ConcurrentDictionary<long, ...> contexts;
public static ... Current
{
get {
return contexts[_sessionIndex ?? (_sessionIndex=Interlocked.Increment(..))];
}
}
Stephen Cleary基于“每个ExecutionContext的单例”提出another solution,它在4.5.1上下文中完美运行但不适用于有限的winrt平台(CallContext不存在)
作为一个解决方案,我会尝试在与主任务相同的线程中强制继续执行,以保持ThreadStatic机制。
实现TaskScheduler可能是一个解决方案,但你不能在winrt中操纵线程。
也许使用特定的SynchronizationContext但我没有找到。 我担心这是不可能的。
有什么想法吗?
答案 0 :(得分:5)
我的AsyncContext
and AsyncContextThread
中有几种类型AsyncEx library,用于定义单线程上下文。他们提供自定义TaskScheduler
和SynchronizationContext
。
AsyncContextThread
通过从线程池中获取任务,安装主循环并保持该任务直到所有异步操作完成为止。 “返回同一个线程”任务调度程序/同步上下文必须以这种方式运行,因为无法将线程池工作排队到特定线程。