Jakub Arnold Jakub Arnold - 3 months ago 19
C# Question

In which case does TaskCompletionSource.SetResult() run the continuation synchronously?

Initially I thought that all continuations are executed on the threadpool (given a default synchronization context). This however doesn't seem to be the case when I use a

TaskCompletionSource
.

My code looks something like this:

Task<int> Foo() {
_tcs = new TaskCompletionSource<int>();
return _tcs.Task;
}

async void Bar() {
Console.WriteLine(Thread.Current.ManagedThreadId);
Console.WriteLine($"{Thread.Current.ManagedThreadId} - {await Foo()}");
}


Bar
gets called on a specific thread and the
TaskCompletionSource
stays unset for some time, meaning the returned tasks
IsComplete = false
. Then after some time, the same thread would proceed to call
_tcs.SetResult(x)
, which by my understanding should run the continuation on the threadpool.

But what I observed in my application is that the thread running the continuation is in fact still the same thread, as if the continuation was invoked synchronously right as
SetResult
is called.

I even tried setting a breakpoint on the
SetResult
and stepping over it (and having a breakpoint in the continuation), which in turn actually goes on to call the continuation synchronously.

When exactly does
SetResult()
immediately call the continuation synchronously?

Answer

SetResult usually runs continuations from TCS synchronously. There main exception to this is if you explicitly pass in the TaskContinuationOptions.RunContinuationsAsynchronously flag when creating the TCS (new in .NET 452). The other scenario when it runs things asynchronously is if it thinks the current thread is doomed.

This is quite important, because if you're not careful you can end up having calling code take control of a thread that was meant to be doing other work (like: dealing with socket IO).

Comments