我正在开发一个与8个COM端口一起工作的应用程序,当从一个COM端口接收数据时,调用事件处理程序,应用程序为通过COM端口接收的消息创建包装器,并发送它通过TCP到远程主机。事实上,在包装之后,它成为基于以太网的网络中某个设备的命令(开始测量命令)。
我正在使用SerialPort和SerialDataReceivedEventHandler来处理COM端口。问题是我通过表单为每个COM端口指定了不同的超时(0-1000 ms)。在此超时之后,我必须发送另一个命令以从设备获取一些数据(获取数据命令)。
您对超时组织有什么建议吗?感谢。
我有一个想法,但我不确定是否可能: 我为每个COM端口都有8个事件处理函数。
...something
sendFirstCommand();
Thread.Sleep(comPortNTimeout);
sendSecondCommand();
我可以在每一个中使用相同的结构吗?如果在第二个端口的处理程序中调用数据Thread.Sleep(),那么第一个端口的处理程序是否会被冻结?
答案 0 :(得分:2)
1)引入某种CommandSourceContext
类,它封装了与每个COM端口相关的所有参数(见下文)
2)要查看处理程序是否会在引发其他端口事件时冻结 - 只需在调试器中测试它,看看是否在同一个线程中调用了所有端口事件。您可以使用Visual Studio 2010线程窗口,只需在COM端口事件处理程序中放置一个断点,并查看当前的线程ID。如果您使用的是较旧的Visual Studio - 只需记录通过Thread.CurrentThread.ManagedThreadId
访问它的线程ID。因此,如果在同一个线程中调用来自不同端口的事件 - 显然处理程序会阻塞每个端口,否则将在不同线程中调用并行运行。至少MSDN说(参见本答复的底部)数据接收事件不是在主线程中引发的,因此在访问UI控件时必须小心。
interface ICommandSourceContext
{
// Since each port has own specific command
// we can encapsulate it in the context as well
ICommand Command { get; }
int PortNumber { get; }
long TimeIntervalMilliseconds { get; }
Action<SerialDataReceivedEventArgs> Callback { get; }
}
// setup and add all contexts
IList<ICommandSourceContext> contexts = new List<ICommandSourceContext>();
// ideally your main code block should looks like below (this is only pseudo code)
foreach (var context in contexts)
{
// to execute it asyncronously you can use TPL Task.Start()
// so it would not block other handlers in case of single thread
context.Command.Execute();
Thread.Sleep(context.TimeIntervalMilliseconds);
}
SerialPort.DataReceived Event remarks:
当数据出现时,在辅助线程上引发 DataReceived 事件 从SerialPort对象接收。因为这个事件是在一个 辅助线程,而不是主线程,试图修改一些 主线程中的元素,如UI元素,可以引发一个 线程异常。如果有必要修改main中的元素 表单或控件,使用Invoke发回更改请求,这样做 关于正确线程的工作