【问题标题】:How can I run several instance of the same sub state machine with MSM boost library如何使用 MSM boost 库运行同一子状态机的多个实例
【发布时间】:2016-08-05 14:48:59
【问题描述】:

我正在熟悉 MSM boost 库。我发现 questions 关于加入几个正交状态非常有趣。

另外,我在 boost 文档中发现了一种在父状态机中重用子状态机的方法,并且我编写了几个简单的嵌套状态机。

但是,我不知道如何将这两个东西混合在一起。

我的目标是分叉到同一个子状态机的几个独立实例,并等待它们完成,然后再将控制权返回给父状态机。

但是,boost documentation 表示不能直接 fork 到子状态机。

注意(也适用于分叉):目前,不能使用子机作为显式条目的目标。请使用条目伪状态以获得几乎相同的效果。

示例

购买机票可以作为子状态机的模型,你要求一个价格,然后进行一些评估,然后你就可以购买它(取消和不完成订单也可以)。但同样的逻辑也适用于几家航空公司。 现在,假设我们要创建一个软件来扫描市场并从不同的提供商处预订一定数量的门票。 当我们收到客户的订单时,我们查询市场并决定从 4 家不同的航空公司购买(客户不介意)。 现在,4 个子状态机将并行工作,只有当最后一个命令完成时,控制才会返回父状态机。 (我知道这个例子不是很好,但我希望你明白了)。

问题

是否可以分叉并使用同一状态机的多个实例(或使用伪状态实现几乎相同的效果)?状态机如何知道事件指的是哪个子状态机?

如果可能的话,请您指出正确的方向吗?我知道这个 boost 文档 example,但它并没有真正解决我的问题。

我处于项目的早期阶段,因此如果需要,我仍然可以移动到不同的状态机库(提升状态图也在评估中)。

【问题讨论】:

    标签: c++ boost


    【解决方案1】:

    我认为正交状态适用于状态的不同部分,但处理相同的事件。在您的情况下,您需要多个状态机实例。为了解决您的问题,我认为定义两个不同的状态机是更好的方法。它们没有父子关系,但相互发送事件。

    假设父状态机作为管理者,子状态机作为工作者。这是两个独立的状态机:

    worker    
    
        +-----------+
     +--|processing |
     |  |           |
     |  +-----------+
     |        |
     |        | e_found(price) / a_notify(price) (send e_found(price) to the manager
     |        V
     |  +-----------+
     |  |processed  |
     |  +-----------+
     |e_cancel|
     |        V
     |  +-----------+
     +->|end        |
        +-----------+
    
    
    manager
    
        +-------------------------------------------------------+
        |comparing                                              |
        |entry/create 4 workers                                 |
        |e_found(price) / increment count and compare price, etc|
        +-------------------------------------------------------+
              | e_cancel/ propagate e_cancel to all workers
              V
        +-----------+
        |end        |
        +-----------+
    

    我相信状态机说明了您的示例场景。这是代码: http://melpon.org/wandbox/permlink/JLkDaZBpvnAYLn5E

    注意:上面的在线编译输出有时会不稳定,但是我在本地环境中检查了代码,运行正常。

    我在 main() 中发送票价发现事件。这不是真的。也许从系统的其他部分接收价格数据。但这不是重点。

    为了在状态机之间发送事件,我使用了 msm::back::state_machine 的 shared_ptr。我需要让状态机的后端调用process_event,但是模板参数Fsm是前端。所以我将状态机后端的weak_ptr作为成员变量嵌入到状态机的前端。当我想调用process_event()时,使用get_sm()成员函数获取后端的shared_ptr。

    在这种情况下,取消事件从经理发送到工人。并且发现事件从工人发送到经理。

    如果你想将workers作为不同的线程运行,你需要使用mutex,如下:

    http://melpon.org/wandbox/permlink/TrexYnffiwEpazNk

    参见第 100 和 192 行。

    Cancel 事件由经理处理并传播给所有工作人员。要测试取消操作,您可以插入取消事件,如下所示:

    int main() {
        auto m = manager::create();
        m->workers_[0]->process_event(e_found {10});
        m->workers_[1]->process_event(e_found {20});
        m->process_event(e_cancel()); // Cancel !!
        m->workers_[2]->process_event(e_found {30});
        m->workers_[3]->process_event(e_found {40});
        return 0;
    }
    

    【讨论】:

    • 非常感谢您的努力,我想我绝对可以在您的方法的基础上再接再厉。我会仔细研究你的例子,再次感谢。
    猜你喜欢
    • 1970-01-01
    • 2018-11-08
    • 1970-01-01
    • 2017-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-22
    • 1970-01-01
    相关资源
    最近更新 更多