代码之家  ›  专栏  ›  技术社区  ›  FireAphis david.pfx

Boost状态图与元状态机

  •  136
  • FireAphis david.pfx  · 技术社区  · 14 年前

    显然boost包含两个用于状态机的独立库: Statechart Meta State Machine (男男性接触者)。这些标语给出了非常相似的描述:

    • 任意复杂的有限状态机可以在易于读取和可维护的C++代码中实现。
    • 元状态机-一个用于表示UML2有限状态机的高性能库。

    你知道两者的主要区别是什么吗?在选择两者时需要考虑什么?

    5 回复  |  直到 9 年前
        1
  •  113
  •   Christophe Henry    14 年前

    鉴于大家似乎很感兴趣,请允许我发表我的(明显有偏见的)看法,因此,我的看法应该是有点偏颇的:

    • MSM要快得多
    • MSM不需要RTTI或任何虚拟的东西
    • MSM有一个更完整的UML2支持(例如内部转换、UML一致的正交区域)
    • MSM提供了一种描述性语言(实际上有几种)。例如,使用eUML前端,可以将转换描述为Source+Event[Guard]/Action==Target
    • MSM会让你的编译器在更大的状态机上受挫,所以你需要一个最新的编译器(g++>=4.x,VC>=9)

    你可以通过在MSM的评论中寻找评论来让自己有更好的意见。这个问题在开发人员名单上有很多讨论。

        2
  •  109
  •   user49572user49572    14 年前

    正如Christophe已经提到的,这两个库之间的关键区别之一是运行时性能。虽然MSM可能提供了最好的性能,但Statechart有意识地将内存和处理器周期交换为更好的可伸缩性。

    有了Boost.Statechart,你可以将 布局 在多个转换单元(cpp文件)上的状态机(即状态、转换),使用MSM无法实现。这允许您使大型fsm的实现比MSM更易于维护,并且获得更快的编译速度。

    与MSM相比,Statechart的性能开销是否对您的应用程序有实际意义,当您问自己应用程序每秒要处理多少个事件时,通常很容易回答。

    假设使用Boost.Statechart实现了一个中等复杂的FSM,下面是一些大概的数字:

    • 大多数当前的PC硬件可以轻松处理每秒10万个事件
    • 甚至 非常 资源受限的硬件每秒能够处理几百个事件。

    关于CPU负载,如果要处理的事件数远低于这些数字,那么与MSM相比,Boost.Statechart开销几乎肯定不会显著。如果这个数字高得多的话,你在MSM上肯定会过得更好。

    有关性能/可伸缩性权衡的更深入信息,请参见: http://www.boost.org/doc/libs/1_45_0/libs/statechart/doc/performance.html

        3
  •  10
  •   blaze    14 年前

    在编写自己的PPP实现时,我使用状态图有三个原因: 1)状态图更简单,文档更清晰; 2)我真的不喜欢UML:)

    Boost文档表示,MSM的速度至少是前者的20倍,但对于大型FSM,编译速度相当慢。

        4
  •  4
  •   spider karma    13 年前

    前一段时间,我从Statechart开始,转移到MSM,因为它更易于从单个线程与asio结合使用。我没能用asio将状态图和它的多线程功能结合起来——这可能是我对状态图的一种不理解。我发现MSM更容易使用,因为它没有处理多线程。

        5
  •  2
  •   da77a    9 年前

    作为对蒂姆晚些时候进入讨论的回应(这也解决了列夫早期的评论之一)。

    作为那些主张退出状态图中的析构函数(基于实际用例的参数,关于真实世界的交互,即I/O)的方法之一,当它被提交给Boost时,我同意在析构函数中引入退出逻辑会有问题。大卫·阿布拉罕斯(David Abrahams)也不出所料地提出了关于异常安全的有说服力的论点。出于这些原因,Statechart不需要将逻辑放入析构函数,但它允许您按照通常的建议。

    逻辑应该只作为一个状态的转换的一部分来运行(而不是作为一个整体的状态图对象的破坏)可以(如果还有资源清理要做)可以被分离成一个单独的Ext()动作。

    对于没有活动状态(资源)的“瘦”状态,只需执行输入/退出操作,就可以在CtoR和DoTor中执行这些操作,并确保构造函数和析构函数不会被抛出。他们没有理由——没有任何州可以执行RAII——让这些地方的错误处理引发适当的事件是没有坏处的。您可能仍然需要考虑是否需要退出操作,更改外部状态以运行状态机销毁,但是…如果你不希望他们出现在这种情况下,把它们放在出口行动中…

    状态图将激活建模为对象的实例化,因此,如果您的构造函数有真正的工作/激活/实例化要做,并且如果它能够失败,以致无法输入状态,则状态图通过使您能够将异常映射到事件来支持这一点。这种处理方式是在状态层次结构中查找处理异常事件的外部状态,类似于基于调用堆栈的调用模型的堆栈展开方式。

    这些都有很好的文档记录-我建议你阅读文档并尝试一下。我建议你使用“清理”软件资源和退出行动来执行“现实世界的退出行动”。

    值得注意的是,异常传播在所有事件驱动的环境中都有点问题,而不仅仅是状态图。最好在状态图设计中推理并包含错误/错误,如果并且只有当您不能以另一种方式处理它们时,才使用异常映射。至少这对我有用-嗯。。。。

    推荐文章