提升状态图与元状态机

显然,boost包含两个独立的状态机库: 状态图和元状态机 (MSM)。 标语给出了非常相似的描述:

  • Boost.Statechart – 任意复杂的有限状态机都可以用易读和可维护的C ++代码实现。
  • 元状态机(Meta State Machine) – performance力强大的UML2有限状态机的高性能库。

你知道两者之间有什么关键的区别和select的考虑吗?

由于似乎有很大的兴趣,请允许我给出我的(显然是有偏见的)意见,因此应该采取一丝一毫的态度:

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

您可以通过查看在MSM审查期间发布的评论来使自己的意见更好。 这个问题在开发者名单上讨论得很多。

正如Christophe已经提到的那样,两个库之间的主要区别之一是运行时性能。 尽pipeMSM可能提供了最佳的可用性,但状态图有意识地将内存和处理器周期换成更好的可扩展性。

借助Boost.Statechart,您可以以不能使用MSM的方式将状态机的布局 (即状态,转换)分布到多个转换单元(cpp文件)中。 这使得您可以使大型FSM的实现更易于维护,并且比MSM更快地进行编译。

无论Statechart相比MSM的性能开销是否会对您的应用程序真正意义重大,当您问自己应用程序每秒必须处理多less事件时,通常都会很容易回答。

假设用Boost.Statechart实现了一个适度复杂的FSM,这里有几个球场号码:

  • 大多数当前的PC硬件将很容易处理每秒> 100000个事件
  • 即使资源非常有限的硬件也能够每秒处理几百个事件。

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

有关性能/可伸缩性权衡的更深入的信息可以在这里find: http : //www.boost.org/doc/libs/1_45_0/libs/statechart/doc/performance.html

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

提升文档说MSM速度至less快20倍,但对于大型FSM编译速度相当慢。

前一段时间,我开始使用状态图,并转而使用MSM,因为从单个线程更容易与asio结合使用。 我没有设法使用asio来对状态图及其multithreadingfunction进行网格划分 – 这可能是我对Statechart的某种新手不理解。 我发现MSM更容易使用,因为它没有解决multithreading问题。

为了回答Tim迟交的讨论(这也是Lev早期的评论之一)。

作为在状态图中争论退出与析构函数分离的人之一(基于真实用例的论点,关于与真实世界的交互,即I / O),当它被提交给Boost时,我认为可能会有问题将退出逻辑析构函数。 大卫·亚伯拉罕(David Abrahams)也不例外地对exception安全做出了有说服力的论证。 由于这些原因,Statechart并不要求你把逻辑放在析构函数中,但是它可以让你按照惯例提出build议。

逻辑只应该作为一个状态转换的一部分而运行(而不是作为一个整体的状态图对象的销毁)可以(并且如果还有资源清除的话)被分离成一个单独的exit()动作。

对于没有活动状态(资源)的“瘦”状态,只需执行进入/退出动作,就可以在ctor和dtor中执行这些动作,并确保构造函数和析构函数不会抛出。 没有理由让他们 – 没有国家去执行RAII – 在这些地方的error handling没有提出适当的事件是没有罪恶的。 你可能仍然需要考虑是否你想要退出动作,改变外部状态运行在状态机破坏虽然…并把它们在退出行动,如果你不希望他们发生在这种情况下…

状态图模型激活作为一个对象的实例化,所以如果你的构造函数有真正的工作/激活/实例化,如果它能够失败,使状态不能进入状态图支持通过给你的能力,事件。 这是通过一种处理状态层次的方式来处理的,它寻找处理exception事件的外部状态,类似于基于调用堆栈调用模型的堆栈将被解除的方式。

这是所有有据可查的 – 我build议你阅读文档并尝试。 我build议你使用析构函数来清理“软件资源”并退出动作来执行“真实世界的退出动作”。

值得注意的是,exception传播在所有事件驱动的环境中都是一个问题,而不仅仅是状态图。 最好在你的状态图devise中推理和包含错误/错误,并且当且仅当你不能以另一种方式处理它们时才使用exception映射。 至less这对我有用 – ymmmv ….