首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Boost Statechart - Local转换

Boost Statechart - Local转换
EN

Stack Overflow用户
提问于 2012-07-06 20:19:07
回答 2查看 2.2K关注 0票数 7

我希望有人能帮助我解决这个问题,或者至少指出我的方法的错误……

作为我的问题的一个简单说明,考虑应用程序的一部分,在那里您可以进入操作的“函数模式”状态。然后,根据用户按下的功能键F1-F4,有四个子模式可用。默认情况下,将进入F1模式。状态图开始如下所示:

用户可以随时按F1-F4切换到相应的模式。将这些转换添加到内部状态会导致以下结果:

显然,这是(a)一团糟,(b)有很多转换需要定义。如果在某一时刻我想添加一个F5Mode,那么...好吧,你明白了。为了避免这种情况,我想执行以下操作:

Boost Statechart允许我定义从FunctionMode到任何内部状态的转换,但结果并不是我所期望的。实际结果如下:

即按F1-F4切换模式导致退出和重新进入外部FunctionMode状态,同时触发不想要的退出和进入动作。

早在2006年,库作者和用户之间的this thread似乎就描述了同样的问题。我认为作者建议做以下工作作为变通办法:

然而,这种变通方法对我来说似乎并不是很有吸引力:它增加了一个要编译的额外状态级别,代码的可读性变得越来越差,必须使用深层历史记录才能返回到任何函数模式子状态,并且中间状态对象正在不必要地被析构和重新构造。

所以..。我哪里错了?或者,还有其他选择吗?我对Boost Meta State Machine (msm)进行了简单的介绍,但从目前为止我所看到的情况来看,我更喜欢Statechart的外观。

我很惊讶,更多的用户没有面临同样的问题……这让我觉得我的方法可能是完全错误的!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-07-27 20:45:20

您看过statechart tutorial中解释的in-state reaction了吗?它似乎正在做你正在寻找的事情。

由于您正在寻求替代方案,因此在这段时间内,我将评估各种C++ Harel状态图实现。我研究了Boost statechart和Boost MSM。我用这两个都写了代码。它们伤害了我虚弱的大脑:-)

然后我发现了Machine Objects (Macho),非常简单和小巧,我喜欢它。它支持分层状态机、进入/退出操作、历史记录、状态机快照、保护、内部转换、事件延迟、状态-本地存储(具有可选的持久性),因此对我来说,它是一个令人满意的Harel状态图实现。

此代码使用Macho实现状态图的FunctionMode部分:

代码语言:javascript
复制
#include "Macho.hpp"

#include <exception>
#include <iostream>
using namespace std;

namespace FunctionMode {

struct FunctionMode;
struct F1Mode;
struct F2Mode;

// The Top state, containing all the others.
TOPSTATE(Top) {
    STATE(Top)
    // All the events of the state machine are just virtual functions.

    // Here we throw to mean that no inner state has implemented the event
    // handler and we consider that an error. This is optional, we could
    // just have an empty body or log the error.
    virtual void evF1() { throw std::exception(); }
    virtual void evF2() { throw std::exception(); }
    // evF3 and so on...
private:
    void init() { setState<FunctionMode>(); } // initial transition
};

SUBSTATE(FunctionMode, Top) {
    STATE(FunctionMode)
    virtual void evF1() { setState<F1Mode>(); }
    virtual void evF2() { setState<F2Mode>(); }
    // evF3, ...
private:
    void entry() { cout << "FunctionMode::entry" << endl; }
    void exit() { cout << "FunctionMode::exit" << endl; }
    void init() { setState<F1Mode>(); } // initial transition
};

SUBSTATE(F1Mode, FunctionMode) {
    STATE(F1Mode)
    virtual void evF1() {} // make the event an internal transition (by swallowing it)
private:
    void entry() { cout << "F1Mode::entry" << endl; }
    void exit() { cout << "F1Mode::exit" << endl; }
};

SUBSTATE(F2Mode, FunctionMode) {
    STATE(F2Mode)
    virtual void evF2() {} // make the event an internal transition (by swallowing it)
private:
    void entry() { cout << "F2Mode::entry" << endl; }
    void exit() { cout << "F2Mode::exit" << endl; }
};

} // namespace FunctionMode

int main() {

    Macho::Machine<FunctionMode::Top> sm;
    // Now the machine is already in F1Mode.

    // Macho has 2 methods for synchronous event dispatching:
    // First method:
    sm->evF1(); // <= this one will be swallowed by F1Mode::evF1()
    // Second method:
    sm.dispatch(Event(&FunctionMode::Top::evF2));

    return 0;
}

运行它时,输出为:

代码语言:javascript
复制
FunctionMode::entry
F1Mode::entry
F1Mode::exit
F2Mode::entry
F2Mode::exit
FunctionMode::exit

这表明转换是内部的。

在我看来,干净,容易和紧凑的代码:-)

EDIT1代码的第一个版本没有执行FunctionMode -> F1Mode的初始转换。现在它做到了。

票数 1
EN

Stack Overflow用户

发布于 2019-11-14 19:30:36

我知道这是一个古老的问题,这些退出->进入相同的状态是恼人的。

看来,为了防止重新进入self,你需要: 1.在"self state“中编写自定义处理程序2.在触发重新进入子状态的父处理程序中写入防护。

我认为这是StateChart的一个缺陷,我还没有找到一个很好的解决方案--在状态机对象上调用“跳过重入状态转换”的属性就很好了。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11362065

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档