At first, I thought that all continuations are done in threadpool (given the default synchronization context). This, however, does not seem to be the case when I use TaskCompletionSource.
Actually, when using await most continuations are executed synchronously.
Mark's answer is great; I just wanted a little more ...
TaskCompletionSource<T> by default will work synchronously when calling Set* . Set* will complete the task and return the extensions in a single method call. (This means that calling Set* while holding a lock is a recipe for locks.)
I use the strange phrase “release sequels” there because it may or may not actually be executed; more on this later.
The TaskCreationOptions.RunContinuationsAsynchronously flag tells TaskCompletionSource<T> to continue asynchrony. This breaks the completion of the task (which is still executed immediately by Set* ) from issuing continuations (which is caused only by calling Set* ). Thus, with RunContinuationsAsynchronously calling Set* will only do the task; it will not perform continuation synchronously. (This means that calling Set* while maintaining the lock is safe.)
But back to the default case, which synchronously issues the continuation.
Each continuation also has a flag; By default, the continuation is asynchronous, but can be made synchronous using TaskContinuationOptions.ExecuteSynchronously . (Note that await uses this flag - a link for my blog, technically this is an implementation detail and is not officially documented).
However, even if ExecuteSynchronously specified, there are a number of situations where the continuation is not performed synchronously :
- If there is a
TaskScheduler associated with the continuation, this scheduler is given the option of rejecting the current thread, in which case the task is queued on the TaskScheduler instead of synchronous execution. - If the current thread is interrupted, the task is queued elsewhere.
- If the current thread stack is too deep, the task is queued elsewhere. (This is only a heuristic and is not guaranteed to avoid a
StackOverflowException ).
These are quite a few conditions, but they all come across with your simple test console application Console:
TaskCompletionSource<T> does not indicate RunContinuationsAsynchronously .- A continuation (
await ) indicates ExecuteSynchronously . - The sequel does not specify
TaskScheduler . - The target thread is able to continue (not interrupted, the stack is in order).
Generally, I would say that any use of TaskCompletionSource<T> should indicate TaskCreationOptions.RunContinuationsAsynchronously . Personally, I believe that semantics are more appropriate and less surprising with this flag.
Stephen cleary
source share