using System.Threading.Tasks;
using System.Collections.Concurrent;
var thread = Thread.CurrentThread;
string name = thread.IsThreadPoolThread
? "Thread pool" : thread.Name;
if (string.IsNullOrEmpty(name))
name = "#" + thread.ManagedThreadId;
Console.WriteLine("Continuation on: " + name);
public static void Main()
Thread.CurrentThread.Name = "Main thread";
var source = new TaskCompletionSource<int>();
var task = source.Task.ImposeAsync();
Func<Task, Task> testAwait = async (t) =>
source.Task.ContinueWith(delegate
task.ContinueWith(delegate
}, TaskContinuationOptions.ExecuteSynchronously);
source.SetResultAsync(123);
Console.WriteLine("Press [return]");
public static class TaskExt
static readonly ConcurrentDictionary<Task, Thread> s_tcsTasks =
new ConcurrentDictionary<Task, Thread>();
static public void SetResultAsync<TResult>(
this TaskCompletionSource<TResult> @this,
s_tcsTasks.TryAdd(@this.Task, Thread.CurrentThread);
s_tcsTasks.TryRemove(@this.Task, out thread);
static public Task ContinueWithAsync<TResult>(
this Task<TResult> @this,
Action<Task<TResult>> action,
TaskContinuationOptions continuationOptions = TaskContinuationOptions.None)
return @this.ContinueWith((Func<Task<TResult>, Task>)(t =>
s_tcsTasks.TryGetValue(t, out thread);
if (Thread.CurrentThread == thread)
return Task.Run(() => action(t));
var task = new Task(() => action(t));
return Task.FromResult(task);
}), continuationOptions).Unwrap();
static public Task<TResult> ImposeAsync<TResult>(this Task<TResult> @this)
return @this.ContinueWith(new Func<Task<TResult>, Task<TResult>>(antecedent =>
s_tcsTasks.TryGetValue(antecedent, out thread);
if (Thread.CurrentThread == thread)
return antecedent.ContinueWith(t => t, TaskContinuationOptions.None).Unwrap();
}), TaskContinuationOptions.ExecuteSynchronously).Unwrap();