For PeriodicTimer (AsyncTimer at the time), regarding WaitForNextTickAsync, David Fowler mentioned "The execution context isn't captured" (here) via (here). However, given that was not necessarily the final implementation, I reviewed the PeriodicTimer documentation which makes no mention of context capturing.
Based on Stephen Toub's decade old, but still excellent, "The Task-based Asynchronous Pattern," and the following code:
private CancellationTokenSource tokenSource;
private async void start_Click(object sender, EventArgs e)
{
tokenSource = new CancellationTokenSource();
var second = TimeSpan.FromSeconds(1);
using var timer = new PeriodicTimer(second);
try
{
while (await timer.WaitForNextTickAsync(tokenSource.Token).ConfigureAwait(false))
{
if (txtMessages.InvokeRequired)
{
txtMessages.Invoke(() => txtMessages.AppendText("Invoke Required..." + Environment.NewLine));
}
else
{
txtMessages.AppendText("Invoke NOT Required!" + Environment.NewLine);
}
}
} catch (OperationCanceledException)
{
//disregard the cancellation
}
}
private void stop_Click(object sender, EventArgs e)
{
tokenSource.Cancel();
}
If ConfigureAwait is passed true (or removed entirely), my output is as follows:
Invoke NOT Required!
Invoke NOT Required!
Invoke NOT Required!
Invoke NOT Required!
...
However, if ConfigureAwait is passed false, my output is as follows:
Invoke Required...
Invoke Required...
Invoke Required...
Invoke Required...
...
Unless I'm confusing SynchronizationContext with "executing thread," it seems like the current SynchronizationContext IS captured by default. Can anyone (maybe one of the greats) please clarify?
The new (.NET 6) PeriodicTimer component is not like all other Timer components that raise events or execute callbacks. This one resembles more the Task.Delay method. It exposes a single asynchronous method, the method WaitForNextTickAsync. This method is not special in any way. It returns a standard ValueTask<bool>, not some kind of exotic awaitable like the Task.Yield method (YieldAwaitable).
When you await this task, you control the SynchronizationContext-capturing behavior of the await like you do for any other Task or ValueTask: with the ConfigureAwait method. If you know how to use the ConfigureAwait with the Task.Delay, you also know how to use it with the PeriodicTimer.WaitForNextTickAsync. There is absolutely no difference.
If you don't know what the ConfigureAwait does, or you want to refresh your memory, there is a plethora of good articles to read. For the sake of variance I'll suggest this old 5-minute video by Lucian Wischik: Tip 6: Async library methods should consider using Task.ConfigureAwait(false)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With