首先:当你使用SerialPort
框架自带的类时,数据接收事件已经是异步的了。当你发送一些东西时,数据是异步传入的。
我要尝试的是:将所有需要等待答案的请求排队。在整个接收处理程序中,检查传入数据是否是其中一个请求的答案。如果是这样,将回复与请求信息一起存储(为此创建某种状态类)。所有其他传入数据均正常处理。
那么,如何让请求等待答复呢?发送命令并返回回复的调用将创建状态对象,将其排队并监视对象以查看是否收到了答案。如果收到应答,则调用返回结果。
一个可能的大纲可以是:
string SendAndWait(string command)
{
StateObject state = new StateObject(command);
state.ReplyReceived = new ManualResetEvent(false);
try
{
SerialPortHandler.Instance.SendRequest(command, state);
state.ReplyReceived.WaitOne();
}
finally
{
state.ReplyReceived.Close();
}
return state.Reply;
}
是什么SerialPortHandler
?我会让它成为一个单例类,其中包含一个Instance
访问单例实例的属性。这个类完成了所有的串口工作。它还应该包含当“带外”信息进入时引发的事件(不是对命令的回复的数据)。
它还包含SendRequest
将命令发送到串行设备、将状态对象存储在内部列表中、等待命令的回复进入并使用回复更新状态对象的方法。
状态对象包含一个调用的等待句柄,它在更改状态对象的属性后ReplyReceived
由 设置。这样你就不需要循环和. 此外,您可以调用几毫秒来等待回复进来,而不是调用。这样,您可以实现某种超时功能。SerialPortHandler
Reply
Thread.Sleep
WaitOne()
WaitOne(timeout)
timeout
这就是它的外观SerialPortHandler
:
void HandlePossibleCommandReply(string reply)
{
StateObject state = FindStateObjectForReply(reply);
if (state != null)
{
state.Reply = reply;
state.ReplyReceived.Set();
m_internalStateList.Remove(state);
}
}
请注意:这是我尝试开始的。我确信这可以得到非常优化,但正如您所见,其中并没有涉及太多“多线程”——只有该SendAndWait
方法应该以某种方式调用,以便多个客户端可以发出命令,而另一个客户端仍在等待它的响应。
编辑
另一个注意事项:您是说该方法应构成 WCF 服务的基础。这使事情变得更容易,就像您配置服务一样,将为每次调用服务创建一个服务类的实例,因此该SendAndWait
方法将“活”在它自己的服务实例中,甚至不需要完全可以重入。在这种情况下,您只需要确保SerialPortHandler
始终处于活动状态(=> 是独立于实际 WCF 服务创建和运行的),无论当前是否存在您的服务类的实例。
编辑 2
我按照评论中的建议将示例代码更改为不循环和睡眠。