You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于boost::ext SML的状态机:双事件触发转换最佳实践咨询

事件驱动状态机处理多条件触发的标准方案(基于boost::ext SML)

对于这种需要同时满足多个事件/条件、且事件顺序不确定的场景,绝对不要把临时条件编码成独立状态(也就是你提到的openNotClear/openClear这类拆分方式)——这是典型的状态膨胀反模式,会大幅提升维护成本。下面是两种行业通用的标准解决方案,适配boost::ext SML的特性:

方案一:守卫条件+内部状态跟踪

核心思路是用一个内部标志跟踪持久化的条件状态(比如用户是否远离门),在触发状态转换时通过守卫条件检查所有必要条件是否满足,不用拆分状态。

这种方案能完美处理userClear在任意状态触发(包括进入open前)、甚至不触发的场景:

#include <boost/sml.hpp>

struct open {};
struct close {};
struct userClear {};
struct closed_ok {};

struct door_fsm {
  // 内部跟踪用户是否远离,初始默认用户不在门附近
  bool is_user_clear = true;

  auto operator()() const {
    using namespace boost::sml;
    return make_transition_table(
      // 初始状态:关闭
      *"closed"_s + event<open> = "open"_s,

      // 在关闭状态时收到userClear,更新标志(不转换状态)
      "closed"_s + event<userClear> / [this] { is_user_clear = true; } = "closed"_s,

      // 开门状态下收到userClear,更新安全标志
      "open"_s + event<userClear> / [this] { is_user_clear = true; } = "open"_s,
      // 开门状态下收到close指令,仅当安全条件满足时才转换到关闭中状态
      "open"_s + event<close> [this] { return is_user_clear; } = "closing"_s,

      // 关闭完成后回到关闭状态,重置安全标志(可选,根据业务需求)
      "closing"_s + event<closed_ok> / [this] { is_user_clear = true; } = "closed"_s
    );
  }
};

优势

  • 状态数量极少,逻辑清晰,避免状态爆炸
  • 能长期跟踪条件状态,适配跨状态的事件触发场景
  • 代码可读性高,维护成本低

方案二:利用SML的延迟事件(Deferred Events)

如果你的场景更偏向「等待某个事件来触发之前未完成的指令」,可以用SML的延迟事件特性:当close指令到来但安全条件不满足时,将该事件延迟,直到userClear触发后再自动处理延迟的close事件。

示例代码:

#include <boost/sml.hpp>

struct open {};
struct close {};
struct userClear {};
struct closed_ok {};

struct door_fsm {
  bool is_user_clear = true;

  auto operator()() const {
    using namespace boost::sml;
    return make_transition_table(
      *"closed"_s + event<open> = "open"_s,

      "closed"_s + event<userClear> / [this] { is_user_clear = true; } = "closed"_s,

      "open"_s + event<userClear> / [this] { is_user_clear = true; } = "open"_s,
      // 安全条件不满足时,延迟close事件
      "open"_s + event<close> [!this->is_user_clear] = defer,
      // 安全条件满足后,处理延迟的close事件(或直接处理新的close事件)
      "open"_s + event<userClear> + event<close> = "closing"_s,
      "open"_s + event<close> [this->is_user_clear] = "closing"_s,

      "closing"_s + event<closed_ok> / [this] { is_user_clear = true; } = "closed"_s
    );
  }
};

优势

  • 无需手动维护等待逻辑,SML自动管理延迟事件队列
  • 代码更简洁,适合一次性的事件等待场景
  • 天然适配事件顺序不确定的情况

方案选择建议

  • 如果条件状态需要在多个状态之间保持(比如用户是否远离的状态可能在开门、关门、关闭状态都需要跟踪),优先选方案一
  • 如果只是临时等待某个事件来触发特定指令,优先选方案二

内容的提问来源于stack exchange,提问作者Nicolas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 08:40:16