3

大家好,

我花了很长时间弄清楚在我当前的工作项目中使用哪种多线程方法。由于我一生中从未编写过多线程应用程序,因此这一切都令人困惑且非常压倒性。事不宜迟,这是我的背景故事:

我被指派在我公司的研发实验室中接管一个测试设备的控制应用程序的工作。该程序必须能够半并发地与三个不同的设备发送和接收串行通信。原始程序是用 VB 6(无多线程)编写的,我确实计划将其修改为与需要测试的较新产品一起使用,直到它在测试期间由于过多的串行通信而导致 UI 锁定时造成安全隐患. 这导致部分测试仪硬件崩溃,所以我决定尝试在 VB.Net 中重写应用程序,因为我一开始对它更满意,而且我认为多线程可能有助于解决这个问题。

我的计划是从主应用程序线程向其他设备发送命令,并将接收端旋转到它们自己的线程中,这样主线程就不会在时间紧迫时锁定。但是,我还没有接受我的选择。为了增加我的问题,我需要在接收到的单独富文本框中显示接收到的通信,而来自一个特定设备的数据需要由主程序解析,但只有来自最新测试的文本(我需要文本框来包含所有接收到的数据)。

到目前为止,我已经调查了委托,自己处理线程,并且刚刚开始研究 BackgroundWorkers。我今天早些时候尝试使用代表,但无法找到更新文本框的方法。我是否需要使用回调函数来执行此操作,因为我无法在委托函数本身的主体中执行此操作?我自己处理线程时看到的问题是弄清楚如何在线程和程序的其余部分之间来回传递数据。BackgroundWorkers,正如我所说,我刚刚开始调查,所以我还不确定如何看待它们。

我还应该注意,该计划是让生成的线程连续运行,直到以某种方式触发停止。上述任何选项都可以做到这一点吗?还有其他我还没有发现的选择吗?

对不起,我似乎在散布一些杂乱无章的信息,但我的期限很紧,压力大到我无法思考的地步!任何建议/信息/链接都非常感谢。我只需要帮助权衡选项,这样我就可以选择一个方向并继续前进。感谢所有花时间阅读这个烂摊子的人!

4

1 回答 1

4

好的,串行端口、线程间通信、在 RichTextBox 等 GUI 组件中显示内容,需要快速解析传入数据以解码协议并触发状态机。

所有三个串行端口都将触发到同一个“processControl”状态机吗?

如果是这样,那么您可能应该通过组装事件/数据对象并将它们排队到由一个线程运行的状态机来做到这一点(参见 BlockingCollection)。这比用互斥锁锁定状态引擎要安全得多,也更容易理解/调试。

定义一个“comms”类来保存数据并在系统中携带它。它应该有一个“命令”枚举,以便获得一个的线程可以通过打开枚举来做正确的事情。一个“事件”成员,可以设置为状态引擎使用的任何内容。一个 'bool loadChar(char inChar)' 可以将 char-by-char 数据投入其中,并且仅当一个完整的、经过验证的协议单元已被组装、检查并解析为数据文件时才会返回“true”。一个“字符串 textify()”方法,它以文本形式转储有关包含数据的信息。保存文本内容的通用“状态”字符串。'errorMess' 字符串和异常成员。

你可能明白了——这个 comms 类可以在系统中传输任何东西。它被封装,因此线程可以使用它的数据和方法,而无需参考任何其他 comms 实例——它不需要任何锁定。它可以排队以在阻塞集合上工作线程并 BeginInvoked 到 GUI 线程以显示内容。

在 serialPort 对象中,在启动时创建一个 comms 并使用 serialPort 实例加载一个成员。并且,当 DataReceived 事件触发时,一次从 args 中获取数据并触发到 comms.loadChar()。如果 loadChar 调用返回 true,则将 comms 实例排队到状态机输入 BlockingCollection,然后立即创建另一个 comms 并开始为新的 comms 加载数据。一直这样做——用字符加载通信实例,直到它们有一个经过验证的协议单元并将它们排队到状态机。可能每个串行端口都有自己的协议 - 好的,因此您可能需要三个覆盖 loadChar 的通信后代才能正确解码自己的协议。

在状态机线程中,只需从输入中获取()通信对象并使用当前状态和来自通信对象的事件来执行状态引擎的事情。如果 SM 动作例程决定显示某些东西,BeginInvoke comms 到 GUI 线程,命令设置为“displaySomeStuff”。当 GUI 线程获得通讯时,它可以切换命令来决定显示什么/什么。

无论如何,这就是我构建所有过程控制类型应用程序的方式。数据在“通讯”对象实例中在系统中流动,没有通讯对象一次被超过一个人操作。如果转到 GUI 线程,这一切都是通过 BlockingCollection(或类似的)、队列或 BeginInvoke() 上的消息传递来完成的。

唯一的锁在队列中,因此被封装。根本没有显式锁。这意味着根本不存在显式死锁。我确实会头疼,但我不会被锁定。

哦 - 不要靠近 'Thread.Join()'。

于 2012-04-25T23:29:45.340 回答