C++ Boost状态图与元状态机

C++ Boost状态图与元状态机,c++,boost,state-machine,boost-statechart,boost-msm,C++,Boost,State Machine,Boost Statechart,Boost Msm,显然,boost包含两个独立的状态机库:和(MSM)。标语给出了非常相似的描述: 任意复杂的有限状态机可以以易于读取和可维护的C++代码实现。 元状态机-用于表示UML2有限状态机的高性能库 您知道两者之间的主要区别和选择的注意事项吗?在编写自己的PPP实现时,我使用Statechart有三个原因: 1) 状态图更简单,文档更清晰; 2) 我真的不喜欢UML:) Boost docs说MSM的速度至少快20倍,但对于大型FSM来说编译速度相当慢。由于人们似乎对此很感兴趣,请允许我给出我的(明

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

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

您知道两者之间的主要区别和选择的注意事项吗?

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


Boost docs说MSM的速度至少快20倍,但对于大型FSM来说编译速度相当慢。

由于人们似乎对此很感兴趣,请允许我给出我的(明显有偏见的)意见,因此应该对此持保留态度:

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

你可以通过查看MSM审查期间发布的评论来获得更好的意见。开发者列表中对这个主题进行了大量讨论。

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

使用Boost.Statechart,您可以以MSM无法实现的方式将状态机的布局(即状态、转换)分散到多个翻译单元(cpp文件)上。这使得大型FSM的实现比MSM更易于维护,编译速度也更快

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

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

  • 大多数当前的PC硬件可以轻松处理每秒10万次以上的事件
  • 即使资源非常有限的硬件也能每秒处理几百个事件
关于CPU负载,如果要处理的事件数远低于这些数字,那么与MSM相比,Boost.Statechart开销几乎肯定不会明显。如果这个数字更高,那么你和男男性接触肯定会更好

有关性能/可伸缩性权衡的更深入信息,请参见:

不久前,我开始使用Statechart,并转到MSM,因为它更容易从单个线程与asio结合使用。我使用asio并没有将Statechart和它的多线程功能融为一体——这可能是我对Statechart的某种不理解。我发现MSM更容易使用,因为它没有解决多线程问题。

在回答Tim迟来的讨论时(这也解决了Lev的一个早期评论)

作为在状态图中主张从析构函数中分离出口的人之一(基于真实用例的论点,关于与真实世界的交互,即i/O),早在提交Boost时,我就同意在析构函数中放置出口逻辑可能会有问题。大卫·亚伯拉罕(David Abrahams)也毫不奇怪地提出了关于异常安全的有说服力的论点。出于这些原因,Statechart不要求您将逻辑放入析构函数中,但它允许您按照通常的建议将逻辑放入析构函数中

应该只作为状态转换的一部分运行的逻辑(而不是作为整体销毁statechart对象)可以(如果还有资源清理要做的话也应该)被分离到一个单独的exit()操作中

对于没有活动状态(资源)的“精简”状态,只需执行进入/退出操作,您可以在ctor和d'tor中执行这些操作,并确保构造函数和析构函数不会抛出。他们没有理由——没有状态来执行RAII on——让这些地方的错误处理引发适当的事件并不是坏事。您可能仍然需要考虑是否需要退出操作,更改外部状态以运行状态机销毁,但是…如果你不想让它们在这种情况下发生,就让它们退出行动

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

这些都有很好的文档记录——我建议您阅读文档并尝试一下。我建议您使用析构函数来清理“软件资源”,并退出操作来执行“真实世界的退出操作”


值得注意的是,异常传播在所有事件驱动环境中都是一个问题,而不仅仅是在状态图中。最好是在状态图设计中对故障/错误进行推理并将其包括在内,并且当且仅当您无法以另一种方式处理它们时,才求助于异常映射。至少这对我是有效的-YMMV…

Hehe,另一个很有趣的案例,但没有人知道答案…:):D这个问题是我人生经历的顶峰