Lv.的博客

Qt状态机框架——如何避免状态爆炸


前几节讲述了如何在Qt状态机框架下如何建立一个状态机,如何迁移状态,如何中断状态机,如何分组状态。本节要先看一个“异常”情况,假设我们有一个状态机,状态机有两种属性,这两种属性互不相关,比如汽车有两种属性,干净和脏,移动和静止是两组不同的属相且不相关,如果按照前几节的内容进行建模,这个状态机中有四种状态和八个状态迁移才能保证在进入所有状态,状态图如下:


如果此时状态机发生了变化,需要增加一个属性,比如颜色,那状态数量就要翻倍(2*2*2)达到8种,如果再增加属性比如是否有天窗,那状态数量再增加一本(2*2*2*2)达到16种……如此下去,这个状态机就会发生状态爆炸了——状态数量太多了,状态迁移也太多了。
如何避免状态爆炸呢?很幸运,Qt状态机框架提供的并行模型可以解决状态爆炸的问题。我们上每个独立的属性单独作为一个状态分组,状态分组维护自己的子状态迁移,这样即使属性增加,状态和状态迁移增加数量也是线性的,不会产生爆炸的结果,状态如类似于下面这样:



我们如何使用Qt状态机框架如何建立并行模型呢?很简单,只需要创建状态QState时传入一个参数QState::ParallelStates即可
QState *s1 = new QState(QState::ParallelStates);
// s11 and s12 will be entered in parallel
QState *s11 = new QState(s1);
QState *s12 = new QState(s1);
machine.addState(s1);
Qt状态机并行模型的特殊要注意的地方:当进入并行状态S1时,S11和S12同时进入,然后每个子状态(S11和S12)中的状态迁移则是正常操作;然后如果其中一个子状态退出并行状态,那么所有子状态都会退出。
Qt状态机框架遵循交错语义,所有并行操作以事件处理的原子步骤被执行,没有事件能够中断并行操作。然而,事件处理本身是顺序执行的,因为状态机本身在一个单独的线程里。考虑这样一个例子:有两个状态迁移能够退出并行状态,当这两个条件同时为真是,这个状态迁移中的第二个将不会起作用,因为第一个条件已经触发退出了并行状态,第二个迁移不会被处理。
void MainWindow::CreateParallelStateMachine(void)
{
QState *s1 = new QState(QState::ParallelStates);
// s11 and s12 will be entered in parallel
QState *s11 = new QState(s1);
QState *s12 = new QState(s1);
connect(s11, SIGNAL(entered()), this, SLOT(OnEnterS11()));
connect(s11, SIGNAL(exited()), this, SLOT(OnExitS11()));
connect(s12, SIGNAL(entered()), this, SLOT(OnEnterS12()));
connect(s12, SIGNAL(exited()), this, SLOT(OnExitS12()));
machine.addState(s1);
machine.setInitialState(s1);
machine.start();
}
void MainWindow::OnEnterS11(void)
{
qDebug() << "Enter S11";
}
void MainWindow::OnEnterS12(void)
{
qDebug() << "Enter S12";
}
void MainWindow::OnExitS11(void)
{
qDebug() << "Exit S11";
}
void MainWindow::OnExitS12(void)
{
qDebug() << "Exit S12";

}

posted @ 2020-10-29 15:39  Avatarx  阅读(757)  评论(0编辑  收藏  举报