TaskCompletionSource保证等待代码是否会在调用TCS.TrySetResult的线程上恢复?

时间:2016-06-08 06:54:48

标签: c# .net async-await

我有一个使用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(但仍然有一些代码无法轻易查看),因此看起来这种行为是有保证的。我是对的吗?

1 个答案:

答案 0 :(得分:1)

  

是否保证了此行为,或者是否存在调用SynchronizationContext(或任何其他线程)的任何情况?

SynchronizationContext(如果存在)始终由等待代码使用(除非GridView另有指定)。这意味着,如果您无法控制等待代码,则无法假设等待代码将在您的主题上运行。

有几个原因可以让你继续不在同一个线程上内联。一个是使用ConfigureAwait(false)。当前的TaskCreationOptions.RunContinuationsAsynchronouslySynchronizationContext等其他人都在IsValidLocationForInlining中:

TaskScheduler