public async Task CompletionSourceCompletesResultAsynchronously(bool runAsync) { var steps = new Steps(); var control = new SemaphoreSlim(0); var control2 = new SemaphoreSlim(0); steps.Add("main.start"); var options = runAsync ? TaskCreationOptions.RunContinuationsAsynchronously : TaskCreationOptions.None; var taskCompletionSource = new TaskCompletionSource <int>(options); var task = Task.Run(async() => { steps.Add("task.start"); // some delay to ensure we do not SetResult before awaiting the task completion source, // thus forcing the await on that task to actually await asynchronously //await control.WaitAsync().CfAwait(); control.Wait(); //await Task.Delay(2000).CfAwait(); Thread.Sleep(2000); steps.Add("task.complete"); taskCompletionSource.SetResult(42); steps.Add("task.continue"); // keep running for a while - on the same thread! //await Task.Delay(200).CfAwait(); Thread.Sleep(200); steps.Add("task.end"); }); steps.Add("main.wait"); control.Release(); await taskCompletionSource.Task.CfAwait(); steps.Add("main.resume"); // keep running for a while - on the same thread! //await Task.Delay(200).CfAwait(); Thread.Sleep(200); steps.Add("main.continue"); await Task.Yield(); await task.CfAwait(); steps.Add("main.end"); Console.WriteLine(steps); // FIXME why does it *have* to be "not same thread"? this test can fail on some occasions // task.complete thread 18 == main.resume thread 18 -- for runAsync = true // task.complete and task.continue always run on same thread // task.complete and main.wait always run on different threads steps.AssertSameThread("task.complete", "task.continue"); steps.AssertNotSameThread("task.complete", "main.wait"); // task.complete and main.resume if (runAsync) { steps.AssertNotSameThread("task.complete", "main.resume"); // run on different threads } else { steps.AssertSameThread("task.complete", "main.resume"); // run on same thread } // FIXME if async, order here is not specified! //if (runAsync) // steps.AssertOrder("task.continue", "main.resume"); // main.resume after task.continue since different thread //else if (!runAsync) { steps.AssertOrder("main.resume", "task.continue"); // main.resume before task.continue since same thread } steps.AssertOrder("main.resume", "main.end"); }