c++ boost状态机简要使用示例

简要介绍

Boost.Statechart是Boost库中的一个用于创建状态机的库。它允许我们定义状态、事件和转变,从而实现复杂的状态机行为。以下是一个简单的例子,展示如何使用Boost.Statechart来创建和使用状态机。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include <iostream>
#include <boost/statechart/state_machine.hpp>
#include <boost/statechart/simple_state.hpp>
#include <boost/statechart/transition.hpp>
#include <boost/statechart/event.hpp>

namespace sc = boost::statechart;

// 事件定义
struct EvStart : sc::event<EvStart> {};
struct EvStop : sc::event<EvStop> {};

// 前向声明状态机和状态
struct Active;
struct MyStateMachine;

// 状态机定义,初始状态设定为Active
struct MyStateMachine : sc::state_machine<MyStateMachine, Active> {};

// 状态Active的定义和行为
struct Active : sc::simple_state<Active, MyStateMachine>
{
// 出现状态时的动作
Active() { std::cout << "Entering Active State\n"; }

// 离开状态时的动作
~Active() { std::cout << "Exiting Active State\n"; }

// 事件处理,EvStop事件使状态机转到Stopped状态
typedef sc::transition<EvStop, class Stopped> reactions;
};

// 状态Stopped的定义和行为
struct Stopped : sc::simple_state<Stopped, MyStateMachine>
{
// 出现状态时的动作
Stopped() { std::cout << "Entering Stopped State\n"; }

// 离开状态时的动作
~Stopped() { std::cout << "Exiting Stopped State\n"; }

// 事件处理,EvStart事件使状态机转回Active状态
typedef sc::transition<EvStart, Active> reactions;
};

int main()
{
// 创建状态机实例
MyStateMachine myMachine;

// 启动状态机,进入初始状态Active
myMachine.initiate();

// 触发EvStop事件,状态机切换到Stopped状态
myMachine.process_event(EvStop());

// 触发EvStart事件,状态机切换回Active状态
myMachine.process_event(EvStart());

return 0;
}

代码解释

  1. 事件定义:

    • EvStartEvStop 是两个事件,继承自 sc::event
  2. 前向声明:

    • Active 状态和 MyStateMachine 状态机进行前向声明。
  3. 状态机定义:

    • MyStateMachine 继承自 sc::state_machine,其初始状态为 Active
  4. 状态定义:

    • ActiveStopped 状态都继承自 sc::simple_state。在构造函数和析构函数中分别定义进入和离开状态时的动作。
    • Active 状态中,通过 typedef sc::transition<EvStop, Stopped> 指定当接收到 EvStop 事件时,会转到 Stopped 状态。
    • Stopped 状态中,通过 typedef sc::transition<EvStart, Active> 指定当接收到 EvStart 事件时,会转回 Active 状态。
  5. 主函数:

    • 创建 MyStateMachine 实例。
    • 调用 initiate() 方法启动状态机,使其进入初始状态 Active
    • 使用 process_event 方法处理事件,触发状态转换。

这个例子展示了如何定义和使用一个简单的状态机。通过事件驱动的方式,可以很方便地管理状态和状态之间的转换。如果需要处理更复杂的状态机行为(如层次状态、并行状态等),可以参考Boost.Statechart的文档获取更多信息。

更多介绍

Boost 状态图库是一个无需代码生成器就可以快速转换 UML 状态图表伪可执行的 C++ 代码框架。由于几乎支持所有 UML的特性直接转换,故所产生的C++代码十分接近于状态表的原文文字描述。

如何阅读参考资料中的官方资料

该资料内容设计为逐步深入。读者可以从合适位置开始读,直到对于解决你的任务为止。特别地:

  • 首先,仅仅有少数几个状态的简单状态机能够通过以下描述合理地实现,基本主题:秒表

  • 其次,达到12个状态的大型状态机请参照以下文章:进阶主题:数码相机应该是很有帮助的。

  • 最后,用户想要创建更加复杂的状态机,请参照:高级主题部分。另外,强烈建议阅读限制条件章节。

hello world

我们将用一个最简单的程序开始第一步,以下为状态表:

图片
该状态图的实现代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <boost/statechart/state_machine.hpp>
#include <boost/statechart/simple_state.hpp>
#include <iostream>

namespace sc = boost::statechart;

// 此处定义为strcut 是为了避免所有成员都要添加 public关键字,如果你不介意,也可以使用class。

// 我们需要提前申明初始化状态,因为其必须在定义状态机的地方定义。
struct Greeting;

// Boost.Statechart 重度使用模板。子类必须总是将该初始化状态作为第一参数传递给基类
// 当状态机进行初始化时,必须被通知进入哪个状态这就是为什么 Greeting 作为第二个参数传递的原因。
struct Machine : sc::state_machine< Machine, Greeting > {};

//对于每个状态都必须指定其所属状态机以及其在状态表中的位置,
//两者是通过simple_state<>的参数来指定。
//因为我们拥有简单的状态机,故其上下文也是状态机。
//相应的,Machine 被当作上下文作为第二参数传递(上下文参数在下文将会进一步说明)。

struct Greeting : sc::simple_state< Greeting, Machine >
{
// 不论何时状态机进入一个状态,就会创建一个相应的状态类的对象。
//该对象将保持只要该状态机保持在此状态。最后,在此状态结束时该对象将销毁。
//因此,进入动作通过定义构造函数来完成,出口动作通过定义析构函数来实现。
Greeting() { std::cout << "Hello World!\n"; } // entry
~Greeting() { std::cout << "Bye Bye World!\n"; } // exit
};

int main()
{
Machine myMachine;
// myMachine 在构造函数调用后并没有运行,我们需要通过调用 initiate() 运行该状态机,
//这将触发 初始状态 Greeting 的构造
myMachine.initiate();
// 当离开 main()时,myMachine 的析构将导致当前激活状态被析构
return 0;
}

执行此程序输出 Hello World! 和 Bye Bye World!

参考资料

The Boost Statechart Library

boost状态图库

boost状态机简介

如果你觉得本文对你有帮助,欢迎打赏