Updating items in a list from a blocking source asynchronously This is a Windows forms application.
this.Server.GetLogMessages() will block if there are no messages to get, so I want this in a separate thread. I'm putting the messages into a ConcurrentStack and then pulling them out on the main thread to output them.
Here is the respective code:
private async Task UpdateLogs()
{
    var logMessages = new ConcurrentStack&lt;string&gt;();

    // assign to `_` to avoid warning
    var _ = Task.Run(async () =&gt;
    {
        await foreach (var message in this.Server.GetLogMessages())
        {
            logMessages.Push(message);
        }
    }, this.CancellationTokenSource.Token);

    await foreach (var message in GetMessages())
    {
        // don't update the UI if task is canceled
        if (this.CancellationTokenSource.Token.IsCancellationRequested)
        {
            break;
        }

        this.textLogs.AppendText($&quot;{message}{Environment.NewLine}&quot;);
    }

    async IAsyncEnumerable&lt;string&gt; GetMessages()
    {
        var message = String.Empty;

        while (!this.CancellationTokenSource.IsCancellationRequested)
        {
            while (!logMessages.TryPop(out message))
            {
                await Task.Delay(100);
            }

            yield return message;
        }
    }
}

It works fine, but seems as if it could be better/cleaner somehow.
My try to simplify and prettify the method.
Avoid using globals in async code, pass Token as argument.
// optimized out async State Machine
private Task UpdateLogsAsync(IProgress&lt;string&gt; status, CancellationToken token) =&gt; Task.Run(async () =&gt;
{
    await foreach (var message in this.Server.GetLogMessages().WithCancellation(token))
    {
        status.Report(message);
    }
}, token);

Usage
// synchronized callback. Create new in UI Thread and its body will be always executed there.
IProgress&lt;string&gt; status = new Progess&lt;string&gt;(message =&gt;
{
    this.textLogs.AppendText($&quot;{message}{Environment.NewLine}&quot;);
});
try
{
    await UpdateLogsAsync(status, this.CancellationTokenSource.Token);
}
catch (OperationCanceledException ex)
{
    status.Report(ex.Message);
}