我有一个使用TaskCompletionSource包装回调的方法,如下所示:
public Task<int> TestMethod(int argument)
{
var tcs = new TaskCompletionSource<int>();
var task = tcs.Task;
LegacyMethodWithCallback(argument, (returnValue) => tcs.TrySetResult(returnValue));
return task;
}
然后我等待那个方法:
async int CallingMethod()
{
var returnValue = await TestMethod(5);
Console.WriteLine(returnValue);
return returnValue;
}
编辑:LegacyMethodWithCallback是一种使用网络与服务器通信的方法。回调在属于我们的专有线程池的线程上运行(这是实现自定义SynchronizationContext的一个原因)。自定义SynchronizationContext基本上是空白的,除了它的Post方法将委托排入到线程池中。以下是应该在调用Post时演示的SC的实现:
internal class ServiceSynchronizationContext : SynchronizationContext
{
public override void Post(SendOrPostCallback d, object state)
{
Console.WriteLine("Post " + d + ": " + state + " for " + this.serviceLogic.ServiceLogicId);
// Enqueue the delegate into our thread pool
}
}
我已经实现了自己的同步上下文,但我很惊讶看到CallingMethod似乎立即在调用TrySetResult的同一个线程上恢复(因此调用了回调的同一个线程)。我原本期望继续通过SynchronizationContext进行Post-ed。
是否保证了此行为,或者是否存在调用SynchronizationContext(或任何其他线程)的任何情况?如果这种行为不是完全确定的,我能以某种方式控制它吗?
我在CallingMethod恢复时彻底检查了调用堆栈,看起来甚至没有考虑SynchronizationContext(但仍然有一些代码无法轻易查看),因此看起来这种行为是有保证的。我是对的吗?
答案 0 :(得分:1)
是否保证了此行为,或者是否存在调用SynchronizationContext(或任何其他线程)的任何情况?
SynchronizationContext(如果存在)始终由等待代码使用(除非GridView
另有指定)。这意味着,如果您无法控制等待代码,则无法假设等待代码将在您的主题上运行。
有几个原因可以让你继续不在同一个线程上内联。一个是使用ConfigureAwait(false)
。当前的TaskCreationOptions.RunContinuationsAsynchronously
和SynchronizationContext
等其他人都在IsValidLocationForInlining
中:
TaskScheduler