正确地异步连续读取串口

Xan*_*ano 6 c# multithreading asynchronous serial-port

我只想说明我刚刚开始尝试使用Async,所以我对我正在做的事情的理解非常有限.

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

现在我只是想学习并确保我正在做所有事情,所以我试图从串口读取数据,并将该数据添加到多行文本框中.这是代码:

连接到串口,如果成功,则调用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
    }
}
Run Code Online (Sandbox Code Playgroud)

这会不断调用ReadLineAsync并将结果添加到文本框中:

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

而这样做ReadAsyncSerialPort.BaseStream,只有当我们得到一个完整的线(换行符表示)返回数据:

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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我做的一切都正确吗?我可以从UI线程调用异步方法吗?视觉工作室告诉我应该使用等待,但它只是暗示.

我希望其他代码在连续读取时在UI线程上运行,所以我不想要await这个UpdateMessageBox功能.如果这是一个线程,我只是希望读取线程在后台运行,我会这样做myReadThread.Start(),是否有类似的异步?

编辑:只是为了澄清,这段代码确实有效,但我想知道这是否是"正确"的方式来做我正在做的事情.

Mic*_*kyD 6

你需要改变:

private void serialConnectClick(object sender, EventArgs e)
Run Code Online (Sandbox Code Playgroud)

private async void serialConnectClick(object sender, EventArgs e)
Run Code Online (Sandbox Code Playgroud)

...并将通话更改UpdateMessageBox();为:

await UpdateMessageBox().ConfigureAwait(true);
Run Code Online (Sandbox Code Playgroud)

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

SerialReadLineAsync,你可以改变:

await serialPort.BaseStream.ReadAsync(buffer, 0, 1);
Run Code Online (Sandbox Code Playgroud)

...至:

await serialPort.BaseStream.ReadAsync(buffer, 0, 1).ConfigureAwait(false);
Run Code Online (Sandbox Code Playgroud)

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

一般尖端"异步一路",这意味着任何方法awaitS上的async方法还需要进行async并依次await编 重复调用堆栈.

  • 你肯定可以。在 UI 方法期间使用 `ConfigureAwait(false)` 时要小心,否则紧随其后的语句可能会在不同的线程上执行。否则,如果您不关心使用什么线程,请使用`ConfigureAwait(false)`。[告诉我更多](https://msdn.microsoft.com/en-us/magazine/jj991977.aspx) (2认同)