I'm working on trying to understand how Task.ContinueWith works. Consider the following code:
private async void HandleButtonClick(object sender, EventArgs e)
{
Console.WriteLine($"HandleButtonClick: a {GetTrdLabel()}");
var t1 = Task.Run(() => DoSomethingAsync("First time"));
Console.WriteLine($"HandleButtonClick: b {GetTrdLabel()}");
await t1;
Console.WriteLine($"HandleButtonClick: c {GetTrdLabel()}");
var t2 = t1.ContinueWith(async (t) =>
{
Console.WriteLine($"t3: a {GetTrdLabel()}");
Thread.Sleep(2000);
Console.WriteLine($"t3: b {GetTrdLabel()}");
await DoSomethingAsync("Second time");
Console.WriteLine($"t3: c {GetTrdLabel()}");
});
Console.WriteLine($"HandleButtonClick: d {GetTrdLabel()}");
await t2;
Console.WriteLine($"HandleButtonClick: e {GetTrdLabel()}");
}
private async Task DoSomethingAsync(string label)
{
Console.WriteLine($"DoSomethingElseAsync ({label}): a {GetTrdLabel()}");
Thread.Sleep(2000);
Console.WriteLine($"DoSomethingElseAsync ({label}): b {GetTrdLabel()}");
await Task.Delay(2000);
Console.WriteLine($"DoSomethingElseAsync ({label}): c {GetTrdLabel()}");
}
private string GetTrdLabel() => $"({Thread.CurrentThread.ManagedThreadId})";
The output is below. My question is about the highlighted lines: why isn't the first one continuing on the captured context after the await
-- i.e. managed thread ID 3
-- since I didn't use .ConfigureAwait(false)
? The second one is continuing as expected -- i.e. thread ID 4
.
I feel like it has something to do with the "...attempt to marshal the continuation back to the original context captured" (emphasis mine) from the documentation, but I don't understand why the attempt fails in the first case.