如何设计一个状态机非阻塞I / O的脸吗?(How to design a state machin

2019-08-01 00:46发布

我使用Qt框架具有默认非阻塞I / O开发一个应用程序通过多个网页(网上商店)导航和开展在这些网页上不同的动作。 我的“映射”特定的网页,而我通过使用这个页面导航状态机。
此状态机有这些转变;
Connect, LogIn, Query, LogOut, Disconnect
而这些状态;
Start, Connecting, Connected, LoggingIn, LoggedIn, Querying, QueryDone, LoggingOut, LoggedOut, Disconnecting, Disconnected
从* ING转变到*编状态( Connecting->Connected ),是由于LoadFinished当被加载当前所请求的URL从网络对象接收的异步网络事件。 从*版过渡到*荷兰国际集团国( Connected->LoggingIn )是由于事件由我送。
我希望能够到几个事件(命令)发送至本机(如连接,登录,查询(“产品A”),查询(“产品B”),注销,登录,查询(“productC”),注销,断开) 在一次有它处理它们。 我不希望阻止等待机器处理完我发送给它的所有事件。 问题是他们必须与通知有关的机器的URL上述网络事件下载交错。 如果没有交织机无法推进其状态(和处理我的事件),因为从* ING推进到*只接收事件的网络类型后,发生ED。

我怎样才能实现我的设计目标?

编辑

  1. 我使用的状态机都有自己的事件循环和事件不排队就那么可以通过机器,如果他们来当机繁忙错过。
  2. 网络I / O事件不直接发布到既非国家机器或我使用的事件队列。 它们贴到我的代码(处理),我必须处理它们。 我可以把和他们如我所愿,但请心里有句话没有。 1。
  3. 看看我的回答这个问题,我描述了我目前的设计中的细节。 现在的问题是是否以及如何能够通过我使其改善这种设计

    • 更强大
    • 更简单

Answer 1:

听起来像是你想要的状态机有一个事件队列。 排队的事件,开始处理第一个,并且完成拉的下一个事件从队列中,并开始时。 因此,而不是状态机的由客户端代码直接,它是由队列驱动。

这意味着,涉及使用于下一个一个转变的结果的任何逻辑必须在机器中。 例如,如果“登录完成”页面告诉你接下来要去哪里。 如果这是不可能的,那么该事件也许可以包括一个回调该机器可以调用,返回无论它需要知道。



Answer 2:

问这个问题,我已经有了,我不想写不以任何方向倾斜答案工作设计:)我打算在这个伪描述解答一下设计我是。

除了状态机我有事件的队列。 而不是直接发布事件的机器,我将它们放置在队列中。 然而有与是异步的,并提出在任何时候的网络事件问题。 如果队列不为空和网络事件来了,我不能将它放在队列,因为机器会卡在队列中已经在处理事件之前,等待它。 并且机器会一直等下去,因为这个网络事件正在等待放置在队列前面的所有事件的背后。
为了克服这个问题,我有两种类型的消息; 正常优先级者。 正常的是那些由我发送和优先级者都是网络的。 当我得到的网络事件,我不把它放在队列中,而是我直接发送至本机。 这样,它可以从事件队列拉动下一事件之前完成其当前任务和进展到下一个状态。
它的工作原理设计的这种方式只是因为正好是1:1交错我的事件和网络事件。 正因为如此,当机器正在等待网络事件是不忙(因此它已经准备好接受它,并不会错过它),反之亦然 - 当机器等待我的任务它只是在等待我的任务,而不是另一网络之一。

我问,希望这个问题对于一些更简单的设计比我现在有。



Answer 3:

严格地说,你不能。 因为你只有状态“连接”,你不知道你是否需要顶级登录之后。 你不得不引进国家“ConnectingWithIntentToLogin”来表示“连接,然后登录”从开始状态事件的结果。

自然会有很多的“连接”和“ConnectingWithIntentToLogin”状态之间的重叠。 这是最容易由支持国家层次的状态机架构来实现。

---编辑---

读你以后的反应,这是现在很清楚你的实际问题是什么。

你需要额外的状态,很明显,不管是在FSM或外面植根于一个单独的队列。 让我们跟随你喜欢的模式,在队列额外的事件。 这里的麦垛的是,你想知道如何“交叉”,那些排队的事件面对面的人的实时事件。 你不 - 从队列中的事件进入特定状态时,积极提取。 在你的情况,这些将是“* ED”状态,如“已连接”。 只有当队列为空时,你会留在“连接”状态。



Answer 4:

如果您不希望阻止,这意味着你不关心网络回复。 如果在另一方面的答复关心你,你必须阻止等着他们。 试图以其他方式设计自己的FSM将很快导致你的自动机的尺寸达到无穷大。



Answer 5:

如何将状态机移动到不同的线程,即QThread的。 我会implent的状态机输入队列这样我就可以发送查询无阻塞和输出队列读取查询的结果。 你甚至可以通过连接(...)回调开槽功能在你的主线程如果查询的结果到达时,Qt的是线程在这方面是安全的。

这样,你的状态机可以阻止只要需要而不会阻塞你的主程序。



Answer 6:

听起来像是你只想做背景阻塞I / O的列表。

因此,有一个线程执行:

while( !commands.empty() )
{
  command = command.pop_back();
  switch( command )
  {
  Connect: 
    DoBlockingConnect();
    break;
  ...
  }
}
NotifySenderDone();


文章来源: How to design a state machine in face of non-blocking I/O?