gpt4 book ai didi

c++ - C 状态机设计

转载 作者:IT老高 更新时间:2023-10-28 11:27:56 30 4
gpt4 key购买 nike

我正在制作一个混合 C 和 C++ 的小项目。我正在我的一个工作线程的核心构建一个小型状态机。

我想知道您的 SO 专家是否会分享您的状态机设计技术。

注意:我主要追求的是久经考验的实现技术。

更新:根据收集到的关于 SO 的所有重要意见,我决定采用这种架构:

An event pump points to an event integrator which points to a dispatcher. The dispatcher points to 1 through n actions which point back to the event integrator. A transition table with wildcards points to the dispatcher.

最佳答案

我之前设计的状态机(C,不是 C++)都归结为 struct数组和一个循环。该结构基本上由一个状态和事件(用于查找)和一个返回新状态的函数组成,类似于:

typedef struct {
int st;
int ev;
int (*fn)(void);
} tTransition;

然后你用简单的定义来定义你的状态和事件(ANY 是特殊的标记,见下文):

#define ST_ANY              -1
#define ST_INIT 0
#define ST_ERROR 1
#define ST_TERM 2
: :
#define EV_ANY -1
#define EV_KEYPRESS 5000
#define EV_MOUSEMOVE 5001

然后定义转换调用的所有函数:

static int GotKey (void) { ... };
static int FsmError (void) { ... };

所有这些函数都被编写为不接受变量并为状态机返回新状态。在此示例中,全局变量用于在必要时将任何信息传递给状态函数。

使用全局变量并不像听起来那么糟糕,因为 FSM 通常被锁定在单个编译单元中,并且所有变量对于该单元都是静态的(这就是为什么我在上面的“全局”周围使用引号 - 它们更多在 FSM 内部共享,而不是真正的全局性)。与所有全局变量一样,它需要小心。

transitions 数组然后定义所有可能的转换以及为这些转换调用的函数(包括最后一个全能转换):

tTransition trans[] = {
{ ST_INIT, EV_KEYPRESS, &GotKey},
: :
{ ST_ANY, EV_ANY, &FsmError}
};
#define TRANS_COUNT (sizeof(trans)/sizeof(*trans))

这意味着:如果你在 ST_INIT状态,您会收到 EV_KEYPRESS事件,调用GotKey .

FSM 的工作就变成了一个相对简单的循环:

state = ST_INIT;
while (state != ST_TERM) {
event = GetNextEvent();
for (i = 0; i < TRANS_COUNT; i++) {
if ((state == trans[i].st) || (ST_ANY == trans[i].st)) {
if ((event == trans[i].ev) || (EV_ANY == trans[i].ev)) {
state = (trans[i].fn)();
break;
}
}
}
}

如上所述,注意 ST_ANY 的使用作为通配符,无论当前状态如何,都允许事件调用函数。 EV_ANY也可以类似地工作,允许处于特定状态的任何事件调用函数。

它还可以保证,如果您到达转换数组的末尾,您会收到一条错误消息,指出您的 FSM 没有正确构建(通过使用 ST_ANY/EV_ANY 组合。

我在很多通信项目中都使用过类似的代码,例如用于嵌入式系统的通信堆栈和协议(protocol)的早期实现。最大的优势是它的简单性和更改转换数组的相对容易。

我毫不怀疑会有更高层次的抽象,可能更适合现在,但我怀疑它们都会归结为同一种结构。


并且,如 ldog在评论中声明,您可以通过将结构指针传递给所有函数(并在事件循环中使用它)来完全避免全局变量。这将允许多个状态机并行运行而不受干扰。

只需创建一个结构类型来保存特定于机器的数据(至少是状态)并使用它而不是全局变量。

我很少这样做的原因仅仅是因为我编写的大多数状态机都是单例类型(例如一次性、进程启动、配置文件读取),不需要运行更多不止一个实例。但如果你需要运行多个,它就很有值(value)。

关于c++ - C 状态机设计,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1647631/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com