简体   繁体   English

正确地异步连续读取串口

[英]Continuously reading from serial port asynchronously properly

I'm just going to preface this by saying I just started trying to use Async today, so I have a very limited understanding of what I am doing. 我只想说明我刚刚开始尝试使用Async,所以我对我正在做的事情的理解非常有限。

I was previously using threads to read data from a serial port, process that data into data to write, and then writing it. 我之前使用线程从串行端口读取数据,将数据处理成要写入的数据,然后编写它。 I had 1 thread reading data and placing it into a buffer, another thread processing data from a buffer, and a final thread writing it. 我有1个线程读取数据并将其放入缓冲区,另一个线程处理缓冲区中的数据,最后一个线程写入它。 This way if I clicked a button, I could send additional data. 这样,如果我点击一个按钮,我就可以发送更多数据。

Now I am just trying to learn and ensure I am doing everything properly, so I am trying to read data from the serial port, and add that data to a multilined textbox. 现在我只是想学习并确保我正在做所有事情,所以我试图从串口读取数据,并将该数据添加到多行文本框中。 Here's the code: 这是代码:

Connect to serial port, if successful, call UpdateMessageBox which is async: 连接到串口,如果成功,调用异步的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
    }
}

This continuously calls ReadLineAsync and adds the result to the textbox: 这会不断调用ReadLineAsync并将结果添加到文本框中:

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

And this does ReadAsync on the SerialPort.BaseStream , and only returns data when we get a full line (denoted by a newline character): 这会在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;
        }
    }
}

Am I doing everything correctly? 我做的一切都正确吗? Can I call an async method from the UI thread? 我可以从UI线程调用异步方法吗? Visual studios is telling me I should use await, but it is just suggesting that. 视觉工作室告诉我应该使用等待,但它只是暗示。

I want other code to run on the UI thread while it is continuously reading, so I don't want to await the UpdateMessageBox function. 我希望其他代码在连续读取时在UI线程上运行,所以我不想await UpdateMessageBox函数。 If this were a thread, I would just want the read thread to operate in the background, and I would just do myReadThread.Start() , is there something similar for async? 如果这是一个线程,我只希望读取线程在后台运行,我只是做myReadThread.Start() ,是否有类似的异步?

EDIT: Just to clarify, this code does work, but I want to know if it's the "proper" way to do what I am doing. 编辑:只是为了澄清,这段代码确实有效,但我想知道这是否是“正确”的方式来做我正在做的事情。

You need to change: 你需要改变:

private void serialConnectClick(object sender, EventArgs e)

to

private async void serialConnectClick(object sender, EventArgs e)

...and change the call to UpdateMessageBox(); ...并将调用更改为UpdateMessageBox(); to: 至:

await UpdateMessageBox().ConfigureAwait(true);

UpdateMessageBox should use ConfigureAwait(true) in order to capture the current context (UI) else the messageTextBox.Text += message; UpdateMessageBox应该使用ConfigureAwait(true)来捕获当前上下文(UI),否则使用messageTextBox.Text += message; would execute on a different thread: 将在不同的线程上执行:

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

In SerialReadLineAsync , you can change: SerialReadLineAsync ,您可以更改:

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

...to: ...至:

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

...because SerialReadLineAsync statements are not related to the UI. ...因为SerialReadLineAsync语句与UI无关。

The general tip is "async all the way" which means any method that await s an async method also needs to be made async and in turn await ed. 一般提示是“一直异步” ,这意味着任何await async方法的方法也需要async进行,然后await编辑。 Repeat this up the call-stack. 重复调用堆栈。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM