gpt4 book ai didi

c# - SerialPort 上多线程的最佳方法是什么

转载 作者:太空宇宙 更新时间:2023-11-03 10:47:55 26 4
gpt4 key购买 nike

因为我是多线程应用程序的新手,所以我想在开始编写代码之前从更有经验的人那里得到一些建议...

我需要在串口事件中对串口接收到的数据进行排队,以便进一步处理。

所以我有以下事件处理程序:

    void jmPort_ReceivedEvent(object source, SerialEventArgs e)
{
SetStatusLabel("Iddle...", lbStatus);
SetPicVisibility(ledNotReceiving, true);
SetPicVisibility(ledReceiving, false);

String st = jmPort.ReadLine();
if (st != null)
{
lines.Enqueue(st); //"lines" is the ConcurrentQueue<string> object
StartDataProcessing(lines); //???
SetStatusLabel("Receiving data...", lbStatus);
SetPicVisibility(ledNotReceiving, false);
SetPicVisibility(ledReceiving, true);
}
else
{
jmPort.Close();
jmPort.Open();
}
}

在 StartDataProcessing 中,我需要使字符串出队并更新许多 UI 控件(使用 InvokeRequired ......我已经知道了:-))。

实现此目标的最佳方法和无冲突(无死锁)方法是什么?

如何在更多线程中调用 StartDataProcessing 方法并安全地出列 (TryDequeue) 行队列,进行所有需要的计算并更新 UI 控件?

我必须指定通信速度非常快,而且我没有使用标准的 SerialPort 类。如果我只是将所有接收到的字符串写入控制台窗口而不进行进一步处理,它就可以正常工作。

我在 .NET 4.5 中工作。

感谢您的任何建议...

更新的问题:好的,那么使用 TPL 从 datareceived 事件运行任务的最佳方式是什么?是否有必要创建另一个类(对象)来处理数据并使用回调来更新 UI,或者是否可以从事件中加载某种表单方法?如果有人能告诉我在 datareceived 事件中究竟要做什么,我会很高兴。第一步该做什么,因为研究所有可能的方法不是我有时间的解决方案。我需要从一些特定的方式开始......有很多不同的可能的多线程方法,在阅读它们之后我仍然更加困惑,我不知道什么是最好的最快的解决方案......通常的线程(s ), BackgroundWorker, TPL, async-await...? :-( 因为我的应用程序使用 .NET 4.5,所以我想使用一些最先进的解决方案 :-) 感谢您的任何建议...

最佳答案

经过大量尝试,现在它的工作令我满意。最后,我使用了标准的 .NET SerialPort 类,因为第三方 Serial 类会导致波特率较高 (115200) 出现问题。它直接使用 WinAPI,因此最终代码是混合的 - 托管和非托管。现在,即使是标准的 .NET 4.5 SerialPort 类也能正常工作(我已经让我的应用程序成功运行了一整夜)。

因此,对于需要处理 C#SerialPort 和更高速率的每个人(仅作说明 - 向 PC 发送消息的设备是 STM32F407/using USART 2/。我也用 Arduino Due 尝试过,效果也很好)我的数据接收事件现在采用以下形式:

    private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
//the SetXXXXX functions are using the .InvokeRequired approach
//because the UI components are updated from another thread than
//the thread they were created in

SetStatusLabel("Iddle...", lbStatus);
SetPicVisibility(Form1.frm.ledNotReceiving, true);
SetPicVisibility(Form1.frm.ledReceiving, false);
String st = serialPort1.ReadLine();
if (st != null)
{
lines.Enqueue(st);
Task.Factory.StartNew(() => StartDataProcessing(lines)); // lines is global ConcurrentQueue object so in fact there is no need to pass it as parameter
SetStatusLabel("Receiving data...", lbStatus);
SetPicVisibility(Form1.frm.ledNotReceiving, false);
SetPicVisibility(Form1.frm.ledReceiving, true);
}
}

StartDataProcessing 函数中:1. TryDequeue(lines, out str)2. 使用 ThreadPool.QueueUserWorkItem(lCallBack1, tmp); 其中 tmp 是 str 的一部分(没有 EOF,没有消息编号等)

lCallBack1 = new WaitCallback(DisplayData);

DisplayData 函数中,所有 UI 控件都已更新

这种方法混合了 ThreadPool 和 TPL 方式,但这不是问题,因为 TPL 无论如何都会在后台操作中使用 ThreadPool。

我尝试过的另一种工作方法如下:

ThreadPool.QueueUserWorkItem(lCallBack, lines); 

代替:

Task.Factory.StartNew(() => StartDataProcessing(lines));

此方法效果很好,但我没有在夜间运行中对其进行测试。

根据我的主观感受,Task.... 方法更流畅地更新了控件,但这可能只是我个人的感觉:-)

所以,我希望这个答案能帮助一些人,因为我从论坛上了解到,许多人都在处理基于微 Controller 的不可靠通信 <--> PC

我的(令人惊讶的 :-))结论是标准的 .NET SerialPort 即使在更高的波特率下也能够处理消息。如果您仍然遇到缓冲区溢出问题,请尝试使用 SerialPort 缓冲区大小和 SerialPort 阈值。对我来说,设置 1024/500 是令人满意的(微 Controller 发送的消息的最大大小为 255 字节,因此 500 字节意味着在事件触发之前有 2 条消息在缓冲区中。)

您还可以从 datareceived 事件中删除所有 SetXXXX 调用,因为它们并不是真正需要的,它们会稍微减慢通信速度...

我现在非常接近实时数据捕获,这正是我所需要的。

祝大家好运:-)

关于c# - SerialPort 上多线程的最佳方法是什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22728991/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com