Concurrent Region

Like Nested States, concurrent regions are designed to control the combinatorial explosions that can occur in an FSM.

UML2 refers to Concurrent Regions as 'orthogonal regions' meaning independant regions. Concurrent Region seems more descriptive hence our naming choice.

Concurrent regions allow you to have two or more concurrently active states within your state machine.

FSM2 uses the 'coregion' builder to create a concurrent region.

  machine = StateMachine.create((g) => g
    ..initialState<MaintainAir>()
    ..state<MaintainAir>((b) => b
      ..state<MonitorAir>((b) => b
        ..onFork<OnBadAir>((b) => b
          ..target<HandleFan>()
          ..target<HandleLamp>()
          ..target<WaitForGoodAir>(),
            condition: (s, e) => e.quality < 10))
      ..coregion<CleanAir>((b) => b
        ..state<HandleFan>((b) => b
          ..onEnter((s, e) async => turnFanOn())
          ..onExit((s, e) async => turnFanOff())
          ..onJoin<OnFanRunning, MonitorAir>(condition: ((e) => e.speed > 5))
          ..state<FanOff>((b) => b)
          ..state<FanOn>((b) => b
            ..onEnter((s, e) async => machine.applyEvent(OnFanRunning()))))
        ..state<HandleLamp>((b) => b
          ..onEnter((s, e) async =>  turnLightOn(machine))
          ..onExit((s, e) async =>  turnLightOff(machine))
          ..onJoin<OnLampOn, MonitorAir>()
          ..state<LampOff>((b) => b)
          ..state<LampOn>((b) => b
            ..onEnter((s, e) async => machine.applyEvent(OnLampOn()))))
        ..state<WaitForGoodAir>((b) => b..onJoin<OnGoodAir, MonitorAir>())))
    ..onTransition((s, e, st) {}));

In the above FSM the 'CleanAir' is denoted as a concurrent region via the 'coregion' builder.

Each of 'CleanAir's immediate child states 'HandleFan' and 'HandleLamp' are concurrent states. The FSM can be in both of these states at the same time.

The concurrency of this example makes sense in the real world if you consider that the state of the fan (on/off) is completely independent of the state of the lamp.

If we look at the 'HandleFan' state we see that it has to child states 'FanOff' and 'FanOn'. These are normal nested states and whilst in the 'HandleFan' state we can expect to move between the 'FanOff' and 'FanOn' states.

If you have only used a simple FSM then you may think of an FSM as only being in a single state. With UML2 and FSM2 concurrent regions and nested states create additional states that your FSM can be in simultaneously.

  • Each immediate children of a concurrent region are considered completely independant. There is no limit on the no. of concurrent regions that an FSM may have nor the no. of immediate children.

  • Concurrent regions can be nested within other states and you can nest states within a concurrent region.

  • You enter a concurrent region using the onFork pseudo state which FSM2 models as a transition with multiple target states. This would normally be each of the immediate children.

  • You exit a concurrent region using either the onJoin pseudo state or a simple 'on' transition.

  • When you enter a co-region then you enter EVERY substate.

  • If you use an 'on' transition or an 'onFork' that doesn't explicitly target every sub state then for all other substates their 'initialState' is entered.

  • If a transition causes any state to transition to a start external to the co-region then all of the co-region's substates are exited.

  • Once in a concurrent region, transitions between child states can occur independently of each other.

if you have concurrent regions in you FSM and a concurrent region is active when an event is applied, only one of the active states needs to be able to handle the event.

Last updated