【问题标题】:Boost MSM - clearer提升 MSM - 更清晰
【发布时间】:2012-03-22 13:15:06
【问题描述】:

我想使用 boost msm 状态机,但我很难想象它是如何工作的。假设我们只有 2 个状态(s1,s2),要从 s1 转到 s2,您需要触发事件 e1,而要返回则需要另一个 e2。 e1 和 e2 只能分别从 s1 和 s2 内触发。

现在在 main() 中,我首先启动状态机 (start()),然后会有一个 while 循环,每 1 分钟将返回到状态机,但必须从它离开的地方继续。ie

main()
{
 MSM.start(); //start state machine

 while (a_condition)
 {
 ProcessInputsfromIO();
 Go_backtoStatemachine(); //how can i do this?
 delay(1min)
 }
 MSM.stop();
}

所以基本上当一个状态完成执行时,状态机将退出,然后会有 1 分钟的延迟,然后 while 循环需要将我带回到我退出之前的状态,或者我认为这就是我们的方式应该实现一个状态机。

我的要求有什么不同吗?如果是,那么人们如何实现非阻塞状态机?如果没有,那我该如何实现 Go_backtoStatemachine()?

【问题讨论】:

  • 显然状态机上的状态在 start() 和 process_event() 等调用之间持续存在。状态机不会在像 start() 这样的调用之后退出,它只有在达到终止状态时才会“退出”(或者更好的是,它会终止)。

标签: c++ boost boost-msm


【解决方案1】:

这里有一个相当简单的例子:

MSM Simple Tutorial

state machine 是一个抽象概念。它有状态、事件等。它并没有真正的阻塞、非阻塞等概念。在Boost MSM框架内可以调用start()进入初始状态,process_event()注入事件,@ 987654325@停止。状态机只是简单地捕获系统状态,并且可以在系统改变状态时调用一些函数。如何使用它取决于应用程序。

【讨论】:

  • 那么我没有办法退出一个状态,然后在不经过初始化状态的情况下重新进入它?
  • @user1248779:您可以在任何状态之间移动并返回,也可以有一个事件使状态机保持在相同的状态。您只需要拥有正确的转换表。更仔细地研究这个例子。例如。请注意,当您在停止状态下收到停止事件时,您仍处于停止状态。当您不断收到 open_close 事件时,您将在 Empty 和 Open 状态之间不断转换。
  • 伙计,谢谢你的帮助,你不知道我对此有多感激。但也许我没有正确解释自己。如果我从不退出状态机,在状态之间移动甚至保持相同状态都没有问题。但是假设我处于状态 S1,并且我从 S1 退出并基本上退出状态机(但我不会停止它),我可以重新进入状态机的唯一方法是触发一个事件。所以如果我正确地设计了状态表,也许我会在每个状态中添加一个事件,让你回到相同的状态,并且在我的 while 循环结束时调用那个事件?
  • 你说“退出”状态机是什么意思。状态机是一个捕获状态并响应事件的对象。虽然 UML 确实允许“退出”状态机,但首先要考虑状态机永远不会退出。不过,这并不意味着您需要处理所有状态下的所有事件,请看示例,并非所有状态都处理所有事件。告诉我更多关于你想要做什么的信息,我可以尝试提出更具体的建议......
  • 我基本上需要实现我在原始帖子中编写的那段代码,我会有一个while循环,每次我调用 Go_backtoStatemachine() 时我都需要回到我离开的状态并再次执行该状态。我将继续这样做,直到某些 IO 更改(ProcessInputsfromIO())然后状态将意识到 IO 条件已更改,并将触发一个事件以在该点进入另一个状态,整个事情再次重复。如果我需要更清楚,请告诉我。
【解决方案2】:

MSM 对线程一无所知,所以当start()process_event(MyEvent()) 被调用时,它们会在当前线程上执行。正如文档 (https://www.boost.org/doc/libs/1_75_0/libs/msm/doc/HTML/ch03s05.html#d0e2668) 中所解释的那样,可以将事件处理推迟到稍后的时刻(这仍然不是线程安全的):

将事件排入队列以供以后处理

调用 process_event(Event const&) 会立即处理事件 具有运行到完成的语义。您还可以将事件排入队列并 通过调用 enqueue_event(Event const&) 来延迟他们的处理。 然后调用 execute_queued_events() 将处理所有排队的事件 (按先进先出顺序)。调用 execute_single_queued_event() 将执行 最早入队的事件。

您可以通过调用 get_message_queue_size() 来查询队列大小。

那么在问题的例子中,你可以

  1. 将 ProcessInputsfromIO 中的事件排入队列
void ProcessInputsfromIO(){
    somethingToDo();
    myfsm.enqueue_event(myEvent1());
    somethingElseToDo();
    etc();
}
  1. Go_backtoStatemachine() 变成了简单的 myfsm.execute_queued_events()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-08-21
    • 1970-01-01
    • 1970-01-01
    • 2016-06-19
    • 2011-08-24
    • 2020-06-22
    • 1970-01-01
    相关资源
    最近更新 更多