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)
PeriodicTimercomponent is not like all otherTimercomponents that raise events or execute callbacks. This one resembles more theTask.Delaymethod. It exposes a single asynchronous method, the methodWaitForNextTickAsync. This method is not special in any way. It returns a standardValueTask<bool>, not some kind of exotic awaitable like theTask.Yieldmethod (YieldAwaitable).When you
awaitthis task, you control theSynchronizationContext-capturing behavior of theawaitlike you do for any otherTaskorValueTask: with theConfigureAwaitmethod. If you know how to use theConfigureAwaitwith theTask.Delay, you also know how to use it with thePeriodicTimer.WaitForNextTickAsync. There is absolutely no difference.If you don't know what the
ConfigureAwaitdoes, 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 usingTask.ConfigureAwait(false)