首先:当您使用框架附带的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
的等待句柄,它在更改状态对象的Reply
属性后由SerialPortHandler
设置。这样你就不需要循环和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服务创建和运行的),无论目前是否有服务类实例。
EDIT 2
我改变了我的示例代码不循环和睡眠作为意见提出。
不要“等待”退货。你在一个事件驱动的系统。 – 2012-04-18 11:36:03
来自设备的数据是否具有某种请求ID,以便知道数据的用途? – 2012-04-18 11:36:54
http://en.wikipedia.org/wiki/Actor_model!正如@亨克所说,使其成为基础,大部分的复杂性消失。 – Travis 2012-04-18 11:56:29