1

Hello esteemed colleagues, I need to save to a text file every time I get a new message from my serial port into my RichTextBox. I'm trying to use async and await it won't block the UI while saving the text file, but unfortunately I'm doing something wrong because it still blocking. Please, what am I doing wrong?

TextChanged event handler from RichTextBox:

private async void rtb_msg_TextChanged(object sender, EventArgs e)
{
    btn_save.Enabled = true;
    rtb_msg.ScrollToCaret();
    rcvFlag = true;
    await SaveFile();
}

Async SaveFile method:

private async Task SaveFile()
{
    if (_serialPort.BytesToRead == 0 && rcvFlag == true)
    {
        for(int i = 0; i < 10; i++)
        {
            Thread.Sleep(1000);
        }
        using (StreamWriter writer = new StreamWriter(reportFolder + reportFile))
        {
            await writer.WriteAsync(rtb_msg.Text);
        }
        rcvFlag = false;
    }
}
Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104
AlexMacabu
  • 127
  • 9

2 Answers2

2

This part will definitely block your UI thread:

for(int i = 0; i < 10; i++)
{
    Thread.Sleep(1000);
}

Not sure why it's there, but if you replace it with an async version, it should work:

for(int i = 0; i < 10; i++)
{
    await Task.Delay(1000);
}
Stefan
  • 17,448
  • 11
  • 60
  • 79
2

Never use Thread.Sleep in async methods. Use Task.Delay and Task.Run instead

private Task SaveFileAsync()
{
    return Task.Run(async () =>
    {
        if (_serialPort.BytesToRead == 0 && rcvFlag == true)
        {
            for (var i = 0; i < 10; i++)
            {
                await Task.Delay(1000);
            }
            using (var writer = new StreamWriter(reportFolder + reportFile))
            {
                await writer.WriteAsync(rtb_msg.Text);
            }
            rcvFlag = false;
        }
    });
}
Anton23
  • 2,079
  • 5
  • 15
  • 28
  • +1 for the option to do the Task.Run. But keep in mind it only makes sense when you have a lot of CPU bound work, like a enormous calculation. Which does not seem to be the case here. – Stefan Mar 20 '22 at 13:53
  • @Stefan the `Task.Run` also makes sense for I/O-bound work for which an asynchronous API does not exist. In some cases it might even be preferable to use `Task.Run` instead of the existing asynchronous API, because the corresponding synchronous API [is more performant](https://stackoverflow.com/questions/63217657/why-c-sharp-file-readalllinesasync-blocks-ui-thread/63218926#63218926). – Theodor Zoulias Mar 20 '22 at 14:10
  • 1
    @TheodorZoulias: yes, that is entirely correct, I oversimplified. – Stefan Mar 20 '22 at 14:15