c# - 连续正确地从串口异步读取

标签 c# multithreading asynchronous serial-port

我只想说我今天才开始尝试使用异步,所以我对我在做什么的理解非常有限。

我之前使用线程从串口读取数据,将数据处理成要写入的数据,然后再写入。我有一个线程读取数据并将其放入缓冲区,另一个线程处理缓冲区中的数据,最后一个线程写入它。这样,如果我点击一个按钮,我就可以发送额外的数据。

现在我只是想学习并确保我做的一切都正确,所以我正在尝试从串行端口读取数据,并将该数据添加到多行文本框。这是代码:

连接串口,如果成功,调用异步的UpdateMessageBox:

private void serialConnectClick(object sender, EventArgs e)
{
    if (!_serialConnected)
    {
        _serialConnected = SerialConnect(portCombo.Text, int.Parse(baudCombo.Text));
        if (!_serialConnected)
        {
            portCombo.SelectedIndex = 0;
            messageTextBox.Text += "Failed to connect.\r\n";
            return;
        }

        serialConnectBtn.Text = "Disconnect";
        serialStatusLabel.Text = "Serial: Connected";
        serialStatusLabel.ForeColor = Color.Blue;
        messageTextBox.Text += "Connected\r\n";
        VDIportCombo.Enabled = false;
        soundSuccess.Play();
        UpdateMessageBox(); // this is an async function
    }
}

这将连续调用 ReadLineAsync 并将结果添加到文本框:

public async Task UpdateMessageBox()
{
    messageTextBox.Text += "Reading data from serial.";
    while (_serialConnected)
    {
        string message = await SerialReadLineAsync(serial);
        messageTextBox.Text += message;
    }
}

这会在 SerialPort.BaseStream 上执行 ReadAsync,并且仅在我们获得整行(由换行符表示)时返回数据:

async Task<string> SerialReadLineAsync(SerialPort serialPort)
{
    byte[] buffer = new byte[1];
    string result = string.Empty;
    Debug.WriteLine("Let's start reading.");

    while (true)
    {
        await serialPort.BaseStream.ReadAsync(buffer, 0, 1);
        result += serialPort.Encoding.GetString(buffer);

        if (result.EndsWith(serialPort.NewLine))
        {
            result = result.Substring(0, result.Length - serialPort.NewLine.Length);
            result.TrimEnd('\r','\n');
            Debug.Write(string.Format("Data: {0}", result));
            result += "\r\n";
            return result;
        }
    }
}

我做的一切都正确吗?我可以从 UI 线程调用异步方法吗? Visual Studios 告诉我应该使用 await,但这只是建议。

我希望在 UI 线程不断读取的同时运行其他代码,因此我不想await UpdateMessageBox 函数。如果这是一个线程,我只想让读线程在后台运行,我就做 myReadThread.Start(),异步有类似的东西吗?

编辑:澄清一下,这段代码确实有效,但我想知道这是否是我正在做的事情的“正确”方式。

最佳答案

你需要改变:

private void serialConnectClick(object sender, EventArgs e)

private async void serialConnectClick(object sender, EventArgs e)

...并将对 UpdateMessageBox(); 的调用更改为:

await UpdateMessageBox().ConfigureAwait(true);

UpdateMessageBox 应使用 ConfigureAwait(true) 以捕获当前上下文 (UI),否则 messageTextBox.Text += message;将在不同的线程上执行:

public async Task UpdateMessageBox()
{
    messageTextBox.Text += "Reading data from serial.";
    while (_serialConnected)
    {
        string message = await SerialReadLineAsync(serial).ConfigureAwait(true);
        messageTextBox.Text += message;
    }
}

SerialReadLineAsync 中,您可以更改:

await serialPort.BaseStream.ReadAsync(buffer, 0, 1);

...到:

await serialPort.BaseStream.ReadAsync(buffer, 0, 1).ConfigureAwait(false);

...因为 SerialReadLineAsync 语句与 UI 无关。

一般提示是“一路异步”,这意味着任何awaitasync 方法的方法也需要制作async 然后 awaited。在调用堆栈中重复此操作。

关于c# - 连续正确地从串口异步读取,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38732358/

相关文章:

c# - 如何等到 await/async 方法完成

c# - 当工作线程和UI线程调用同一方法(包括调用ui控件)时出现死锁

c# - 限制单次执行一个方法的线程数

c# - 在 C# 中使用 "using"关键字

c# - 如何将 LINQ 嵌套 Selectmany 转换为 SQL 正则语句

c# - Sitecore 向标题添加额外的标题

后台线程中的 ASP.NET 异常处理

c++ - 独立的 Windows 应用程序在焦点改变时挂起

javascript - 使用nodejs在异步函数中使用await和async的语法是什么?

c# - 如何模拟函数返回无效任务