The flow module provides two types of flow control tools: multi-level finite state machine (StateMachine) and behavior tree (Action series). StateMachine is used for state-driven business logic, while Action is used for composite complex flows.
In event-driven programming, complex business flows need to manage a large number of states and conditional judgments. StateMachine provides clear state definitions and transition rules, while Action provides composite flow control (sequential, parallel, conditional selection, etc.), separating complex control logic from business code.
#include <tbox/flow/state_machine.h> //! State machine
#include <tbox/flow/action.h> //! Action base class
#include <tbox/flow/action_executor.h> //! Action executor
#include <tbox/flow/event.h> //! Event definitions
#include <tbox/flow/event_publisher.h> //! Event publisher
#include <tbox/flow/event_subscriber.h> //! Event subscriber
#include <tbox/flow/to_graphviz.h> //! Export Graphviz diagram- StateID: State number, 0 is the terminated state, -1 is the invalid state
- EventID: Event number, 0 means any event
- Route: Defines a conditional route that transitions from one state to another upon receiving a specific event
- GuardFunc: Condition judgment function, returns true to indicate the condition is satisfied and the transition can proceed
- EventFunc: Event handler function, returns >=0 to indicate a transition to the specified state is needed
- Sub State Machine: StateMachine supports nesting; inner state machines can independently manage sub-states
Action is the base node of the behavior tree, providing unified lifecycle management:
Action states: kIdle (idle) → kRunning (running) → kFinished (finished)/kStoped (stopped)/kPause (paused)
Action results: kUnsure (unknown) → kSuccess (success)/kFail (failure)
Action has various composite and functional subclasses (see unit test cases in modules/flow/ for complete examples):
- Sequential composition: SequentialAction (execute multiple sub-actions in order)
- Parallel composition: ParallelAction (execute multiple sub-actions simultaneously)
- Conditional selection: IfElseAction (conditional branch), SwitchAction (multi-way selection)
- Loop control: LoopAction (loop execution), WhileAction (conditional loop)
- Decorators: RetryAction (retry on failure), TimeoutAction (timeout control), DelayAction (delayed start)
- Transaction: TransactionAction (commit on all success, rollback on any failure)
struct Event {
using ID = int;
ID id = 0;
const void *extra = nullptr; //! Attached data pointer
};Supports creation from enum types: Event(MyEvent::kTimeout, &data)
See unit test cases in
modules/flow/for complete examples
enum State { kOff = 1, kOn = 2 };
enum Event { kToggle = 10 };
StateMachine sm;
//! Create two states
sm.newState(kOff, [](Event) { LogInfo("enter OFF"); }, [](Event) { LogInfo("exit OFF"); });
sm.newState(kOn, [](Event) { LogInfo("enter ON"); }, [](Event) { LogInfo("exit ON"); });
//! Add transition routes: switch to the other state upon receiving Toggle event from any state
sm.addRoute(kOff, kToggle, kOn, nullptr, nullptr);
sm.addRoute(kOn, kToggle, kOff, nullptr, nullptr);
sm.start(); //! Start from the first state kOff
sm.run(Event(kToggle)); //! OFF → ON
sm.run(Event(kToggle)); //! ON → OFF//! Route with condition judgment: transition only when guard returns true
sm.addRoute(kIdle, kRequest, kBusy,
[](Event ev) { return /* some condition */; },
nullptr
);StateMachine outer_sm;
StateMachine inner_sm;
//! Inner state machine definition
inner_sm.newState(kInnerA, ...);
inner_sm.newState(kInnerB, ...);
//! Attach the inner state machine to a state of the outer state machine
outer_sm.newState(kOuterState, ...);
outer_sm.setSubStateMachine(kOuterState, &inner_sm);See unit test cases in
modules/flow/for complete examples
//! SequentialAction: execute multiple sub-actions in order
//! Sub-action A completes then automatically starts B, B completes then starts C
//! Any failure causes the overall action to failJson js;
sm.toJson(js); //! Export state machine as JSON, can be used for visualization
//! Use to_graphviz.h to convert to Graphviz format- Device state management: e.g., IoT device idle → running → fault → recovery state transitions
- Protocol state machine: e.g., TCP connection states, HTTP request processing states
- Business flow orchestration: e.g., order creation → payment → shipping → completion, rollback on failure
- Conditional branching: Select different execution paths based on sensor data
- Retry mechanism: Use RetryAction to automatically retry on failure
- StateID 0 is the terminated state: The state machine automatically terminates upon reaching state 0, no additional handling needed
- Sub state machine lifetime: The sub state machine passed to setSubStateMachine() must have a longer lifetime than the parent state machine
- Action finish/block: finish() indicates normal completion (success or failure), block() indicates pausing to wait for an external condition
- Event.extra pointer: The data pointed to by the extra pointer must remain valid during event handling
- toJson export: The state machine can be exported as JSON for debugging and visualization
- event: Run state machines and actions based on Loop
- util: Action uses Variables to store variables
- base: Provides Json, Log and other infrastructure


