Skip to content

Suspension

Freezing a state in place with suspend, immediate suspend and weak suspend, and what that does to its actions and transitions.

Open a microwave halfway through and it stops. Shut the door and it carries on: the timer does not start again from the beginning, and it does not skip ahead either. It was simply paused.

The aborts you have met so far end a state for good. Suspension is a third way to interrupt a state from outside: it stops the state for a tick, or for many ticks, without leaving it. When the suspension lifts, the state continues exactly where it was. (Together, weak aborts, strong aborts and suspension are called preemption: something outside a state takes control away from it.)

Here is a microwave that counts down from 3. Its cooking state carries one extra line, suspend if doorOpen:

MicrowaveSimulation

Diagram

Diagram of MicrowaveStates: Cooking (initial, superstate), Heating (initial), Finished (final), Done (superstate). Transitions: Heating to Heating: 1: remaining > 1 / remaining--; Heating to Finished: 2: remaining == 1 / remaining--; Cooking to Done.Microwaveinput booldoorOpenoutput intremaining = 3output boolbeep = falseCookingsuspenddoorOpenHeatingFinished1: remaining > 1/ remaining--2: remaining == 1/ remaining--Doneentry/ beep = true

Code

scchart Microwave {
input bool doorOpen
output int remaining = 3
output bool beep = false
initial state Cooking {
suspend if doorOpen
initial state Heating
if remaining > 1 do remaining-- go to Heating
if remaining == 1 do remaining-- go to Finished
final state Finished
}
join to Done
state Done {
entry do beep = true
}
}
Tick 0 of 7
Inputs for tick 1 Boolean input: true while on. It keeps its value until you change it.
Timing diagram of Microwave
Tickinput bool doorOpenoutput int remainingoutput bool beepActive state of the chartActive state of the region of Cooking
Click a tick to show it, or use the Left and Right arrow keys to go back and step.
Guided tour, 7 ticks Press Next to run tick 1, or Take over to set the inputs yourself.

Guided tour, 7 ticks:

  1. doorOpen = falseTick 1 enters Cooking and its initial state Heating. The countdown transitions are delayed, so remaining starts at 3.
  2. The door is shut, so Cooking runs normally: the self-loop on Heating counts down to 2.
  3. doorOpen = trueThe door opens. suspend if doorOpen holds, so nothing inside Cooking runs this tick: remaining stays 2 and Heating stays active.
  4. Still open, still frozen. A suspended state keeps its place; it does not restart or move on.
  5. doorOpen = falseThe door shuts and Cooking carries on exactly where it stopped: remaining goes from 2 to 1.
  6. The last step goes to the final state Finished (remaining = 0), so Cooking terminates and join to Done fires in the same tick: beep is true.
  7. In Done. Nothing else happens.
The guided tour opens the door in ticks 3 and 4: remaining stops at 2 and carries on from 2 when the door shuts. After the tour, press Take over to try it yourself: doorOpen stays on until you switch it off.

KIELER’s trace of the tour, with the state and the values after each tick:

Tick doorOpen State remaining beep
1 false Cooking (Heating) 3 false
2 false (held) Cooking (Heating) 2 false
3 true Cooking (Heating) 2 false
4 true (held) Cooking (Heating) 2 false
5 false Cooking (Heating) 1 false
6 false (held) Done 0 true
7 false (held) Done 0 true

In ticks 3 and 4 the self-loop on Heating would normally fire, but Cooking is suspended, so nothing inside it moves. In tick 5 the count resumes from 2. Nothing was lost and nothing restarted.

suspend if c is a state action, written at the top of a state next to its entry, during and exit actions. The diagram lists it with them, as suspend doorOpen.

In every tick in which c holds, the state is suspended, and nothing that belongs to it runs:

  • no transition inside it fires, delayed or immediate;
  • no during action runs, neither the state’s own nor those of the states inside it;
  • no entry or exit action of an inner state runs;
  • count delays inside it (if 3 press) do not count that tick.

The active inner states stay active. In the next tick in which c is false, the state carries on from them as if the suspended ticks had not happened.

Three details complete the rule:

  • A plain suspend is delayed, like a delayed transition: it is not checked in the tick the state is entered, only from the next tick on. Immediate suspend changes that.
  • Only the state that carries the suspend, and what is inside it, freezes. The states around it and the regions next to it keep reacting as usual.
  • Several suspend actions on one state suspend it whenever any of their triggers holds.

Suspension stops behaviour, not time. Whatever looks at “the previous tick” still sees the previous tick, even if that tick was a suspended one. The most important case is pre.

The chart below measures how much sensor changed since the last tick, sensor - pre(sensor), and has a hold input that suspends it. Before you run it, predict what change is in tick 3, and in tick 5, the first tick after the hold. Then open the explanation below.

RateOfChangePrediction

Diagram

Diagram of RateOfChangeStates: Measuring (initial, superstate), Sample (initial). Transitions: Sample to Sample: true / change = sensor - pre(sensor).RateOfChangeinput boolholdinput intsensoroutput intchange = 0MeasuringsuspendholdSampletrue/ change = sensor - pre(sensor)

Code

scchart RateOfChange {
input bool hold
input int sensor
output int change = 0
initial state Measuring {
suspend if hold
initial state Sample
if true do change = sensor - pre(sensor) go to Sample
}
}

hold is true in ticks 3 and 4. In tick 5, does pre(sensor) remember 12 or 20?

Inputs per tick. A value in grey was not set in that tick: it holds from an earlier one.

Tickholdsensor
1false10
2false12
3true15
4true20
5false26
Plays the scenario on the diagram, then marks each answer.
Explanation

In tick 3 nothing runs, so change keeps its old value, 2. In tick 5 the transition runs again, and pre(sensor) is 20, the value sensor had in tick 4. That tick was suspended, but pre does not care: it always means “at the end of the previous tick”. So change is 26 − 20 = 6. If you wanted “the change since the last tick that ran”, you would have to keep that value yourself, in a variable that the transition writes.

Count delays, on the other hand, belong to the state’s behaviour, so they do freeze. A transition if 3 press go to Done inside a suspended state counts only the presses in unsuspended ticks.

The rule fits in a paragraph, but the way KIELER implements it has consequences that catch people out. Suspension does not exist in KIELER’s core language. The compiler rewrites a suspend into a hidden flag, _enabled, which is recomputed in every tick, and adds && _enabled to the trigger of every action and transition that belongs to the state. Each surprise below comes from something that counts as “belonging to the state”.

A suspended state cannot be left by its own transitions

Section titled “A suspended state cannot be left by its own transitions”

The state’s own outgoing transitions belong to it too. While the state is suspended, they cannot fire.

That is a real trap. Give the microwave a cancel button with if cancel go to Idle on Cooking, and cancelling stops working while the door is open. The fix is to put the suspension one level further in: a superstate Oven holds the cancel transition, and only the Cooking inside it is suspended.

CancelTrap and CancelFixedComparison

Diagrams

CancelTrap

Diagram of CancelTrapStates: Cooking (initial, superstate), Heating (initial), Idle. Transitions: Heating to Heating: remaining > 0 / remaining--; Cooking to Idle: cancel.CancelTrapinput booldoorOpen, canceloutput intremaining = 5CookingsuspenddoorOpenHeatingremaining > 0/ remaining--Idlecancel

CancelFixed

Diagram of CancelFixedStates: Oven (initial, superstate), Cooking (initial, superstate), Heating (initial), Idle. Transitions: Heating to Heating: remaining > 0 / remaining--; Oven to Idle: cancel.CancelFixedinput booldoorOpen, canceloutput intremaining = 5OvenCookingsuspenddoorOpenHeatingremaining > 0/ remaining--Idlecancel

Code

CancelTrap

scchart CancelTrap {
input bool doorOpen, cancel
output int remaining = 5
initial state Cooking {
suspend if doorOpen
initial state Heating
if remaining > 0 do remaining-- go to Heating
}
if cancel go to Idle
state Idle
}

CancelFixed

scchart CancelFixed {
input bool doorOpen, cancel
output int remaining = 5
initial state Oven {
initial state Cooking {
suspend if doorOpen
initial state Heating
if remaining > 0 do remaining-- go to Heating
}
}
if cancel go to Idle
state Idle
}
Tick 0 of 7
Inputs for tick 1, for both charts Boolean input: true while on. It keeps its value until you change it. Boolean input: true while on. It keeps its value until you change it.
Timing diagram of CancelTrap and CancelFixed, no ticks yet
Tickinput bool doorOpeninput bool cancelCancelTrap: output int remainingCancelTrap: Active state of the chartCancelTrap: Active state of the region of CookingCancelFixed: output int remainingCancelFixed: Active state of the chartCancelFixed: Active state of the region of OvenCancelFixed: Active state of the region of Oven.Cooking
Click a tick to show it, or use the Left and Right arrow keys to go back and step.
Guided tour, 7 ticks Both charts get the same inputs. Press Next to run tick 1, or Take over to set the inputs yourself.

Guided tour, 7 ticks, the same inputs for both charts:

  1. doorOpen = false, cancel = falseTick 1 enters both ovens with remaining = 5. In CancelTrap the suspend and if cancel go to Idle are both on Cooking. In CancelFixed the cancel transition is on Oven, the state around Cooking.
  2. Both count down: 4.
  3. doorOpen = trueThe door opens and both Cooking states are suspended: remaining stays 4. In CancelFixed, Oven is not suspended: only the state that carries the suspend freezes.
  4. cancel = truecancel is pressed while the door is open. CancelTrap: the cancel transition belongs to the suspended Cooking, so it is frozen with the rest of it, and the press is ignored. CancelFixed: the transition belongs to Oven, which is not suspended, so it fires and the oven goes to Idle.
  5. cancel = falsecancel is released. CancelTrap is still suspended; CancelFixed is in Idle.
  6. doorOpen = falseThe door shuts. CancelTrap carries on cooking (3): the cancel press was lost. CancelFixed stays in Idle, with remaining still 4.
  7. CancelTrap counts on (2). CancelFixed never resumes.
Note: While Cooking is suspended, its own outgoing transitions cannot fire either (CancelTrap)
  • Note in CancelTrap, line 6, column 5KIELER's suspend freezes everything that belongs to Cooking, including the transitions that leave it. To leave a suspended state, put the transition on an enclosing state.
The tour opens the door in tick 3 and presses cancel in tick 4. CancelTrap ignores the press and later carries on cooking; CancelFixed goes to Idle at once.

The rule of thumb: put the suspend on an inner state and the ways out on a state around it. The outer state is never suspended, so its transitions always work.

CancelRejectedChart

Diagram

Diagram of CancelRejectedStates: Cooking (initial, superstate), Heating (initial), Idle. Transitions: Heating to Heating: remaining > 0 / remaining--; Cooking to Idle: cancel.CancelRejectedinput booldoorOpen, canceloutput intremaining = 5CookingsuspenddoorOpenHeatingremaining > 0/ remaining--Idlecancel

Code

scchart CancelRejected {
input bool doorOpen, cancel
output int remaining = 5
initial state Cooking {
suspend if doorOpen
initial state Heating
if remaining > 0 do remaining-- go to Heating
}
if cancel abort to Idle
state Idle
}

KIELER rejects this chart

  • Line 11, column 3The strong abort out of Cooking and Cooking's own suspend depend on each other within the tickKIELER says: The SCG is NOT asc-schedulable!A strong abort is decided before anything inside Cooking runs, but Cooking's suspend also freezes Cooking's own transitions, so the abort waits for Cooking's suspend condition, which is worked out inside Cooking. Move the abort to a state around Cooking: KIELER rejects every abort to out of a state that has its own suspend.About this message
Also a note: While Cooking is suspended, its own outgoing transitions cannot fire either
  • Note, line 6, column 5KIELER's suspend freezes everything that belongs to Cooking, including the transitions that leave it. To leave a suspended state, put the transition on an enclosing state.
CancelTrap with abort to in place of go to: KIELER rejects it.

The state’s own entry and exit actions belong to it as well, and here the hidden flag misbehaves: when the state is entered, its entry actions run before the flag has been switched on for the first time. The result is that a state with a suspend skips its own entry actions the first time it is entered, even if the suspend never triggers.

This chart counts cooking sessions with an entry action on Cooking:

SessionCounterSimulation

Diagram

Diagram of SessionCounterStates: Idle (initial), Cooking (superstate), Heating (initial). Transitions: Idle to Cooking: start; Cooking to Idle: stop.SessionCounterinput boolstart, stop, doorOpenoutput intsessions = 0IdleCookingsuspenddoorOpenentry/ sessions++Heatingstartstop

Code

scchart SessionCounter {
input bool start, stop, doorOpen
output int sessions = 0
initial state Idle
if start go to Cooking
state Cooking {
suspend if doorOpen
entry do sessions++
initial state Heating
}
if stop go to Idle
}
Tick 0 of 7
Inputs for tick 1 Boolean input: true while on. It keeps its value until you change it. Boolean input: true while on. It keeps its value until you change it. Boolean input: true while on. It keeps its value until you change it.
Timing diagram of SessionCounter
Tickinput bool startinput bool stopinput bool doorOpenoutput int sessionsActive state of the chartActive state of the region of Cooking
Click a tick to show it, or use the Left and Right arrow keys to go back and step.
Guided tour, 7 ticks Press Next to run tick 1, or Take over to set the inputs yourself.

Guided tour, 7 ticks:

  1. start = false, stop = false, doorOpen = falseTick 1 starts in Idle.
  2. start = trueSurprise: Cooking is entered, but its entry action does not run (sessions stays 0). KIELER guards it with the suspend’s internal flag, which is only switched on after the entry action has looked at it.
  3. start = false, stop = trueBack to Idle.
  4. start = true, stop = falseThe second entry does run the entry action (sessions = 1): the flag kept its value from the last visit.
  5. start = falseCooking.
  6. stop = trueBack to Idle. Two sessions, but sessions says 1.
  7. stop = falseIn Idle.
2 notes
  • Note, line 9, column 5While Cooking is suspended, its own outgoing transitions cannot fire eitherKIELER's suspend freezes everything that belongs to Cooking, including the transitions that leave it. To leave a suspended state, put the transition on an enclosing state.
  • Note, line 10, column 5Because Cooking has a suspend, KIELER skips its entry actions when Cooking is entered for the first timeKIELER guards every action of a suspendable state with a flag that its during actions compute, and they run after the entry actions; before the first tick the flag is false. Later entries run them only if Cooking was not suspended when it was last left. Put the set-up into the transition that enters Cooking, or into an inner state.
The first visit to Cooking (tick 2) leaves sessions at 0; the second (tick 4) counts.

KIELER gives no error and no warning; the count is simply wrong.

The safe habit is to keep entry and exit actions off the state that carries the suspend. Do the set-up on the transition that enters the state (if start do sessions++ go to Cooking), or in an entry action of a state inside it: the entry actions of the inner initial states do run on the first entry, as long as the state is not suspended in that tick.

The join to of a superstate belongs to the superstate, so it gets && _enabled added to its trigger. A termination with a trigger is delayed (see Superstates), so a superstate whose inside finishes in the tick it is entered terminates one tick later once it has a suspend. The two charts below differ only in the line suspend if doorOpen, and the door stays shut throughout:

PreheatPlain and PreheatSuspendComparison

Diagrams

PreheatPlain

Diagram of PreheatPlainStates: Prepare (initial, superstate), Check (initial), Ready (final), Heating (superstate). Transitions: Check to Ready; Prepare to Heating.PreheatPlaininput booldoorOpenoutput boolheater = falsePrepareCheckReadyHeatingentry/ heater = true

PreheatSuspend

Diagram of PreheatSuspendStates: Prepare (initial, superstate), Check (initial), Ready (final), Heating (superstate). Transitions: Check to Ready; Prepare to Heating.PreheatSuspendinput booldoorOpenoutput boolheater = falsePreparesuspenddoorOpenCheckReadyHeatingentry/ heater = true

Code

PreheatPlain

scchart PreheatPlain {
input bool doorOpen
output bool heater = false
initial state Prepare {
initial state Check
immediate go to Ready
final state Ready
}
join to Heating
state Heating {
entry do heater = true
}
}

PreheatSuspend

scchart PreheatSuspend {
input bool doorOpen
output bool heater = false
initial state Prepare {
suspend if doorOpen
initial state Check
immediate go to Ready
final state Ready
}
join to Heating
state Heating {
entry do heater = true
}
}
Tick 0 of 3
Inputs for tick 1, for both charts Boolean input: true while on. It keeps its value until you change it.
Timing diagram of PreheatPlain and PreheatSuspend, no ticks yet
Tickinput bool doorOpenPreheatPlain: output bool heaterPreheatPlain: Active state of the chartPreheatPlain: Active state of the region of PreparePreheatSuspend: output bool heaterPreheatSuspend: Active state of the chartPreheatSuspend: Active state of the region of Prepare
Click a tick to show it, or use the Left and Right arrow keys to go back and step.
Guided tour, 3 ticks Both charts get the same inputs. Press Next to run tick 1, or Take over to set the inputs yourself.

Guided tour, 3 ticks, the same inputs for both charts:

  1. doorOpen = falseIn both charts the inside of Prepare runs straight through to its final state Ready in tick 1. In PreheatPlain, Prepare terminates at once and join to Heating fires: heater = true. In PreheatSuspend the suspend has added a condition to Prepare’s termination, and a termination with a condition is delayed: heater stays false, although the door is shut.
  2. In PreheatSuspend, Prepare terminates now, one tick late: heater = true in both.
  3. Both in Heating.
Note: Because Prepare has a suspend, this join to waits one tick longer when the inside finishes in Prepare's first tick (PreheatSuspend)
  • Note in PreheatSuspend, line 13, column 3The suspend flag becomes part of the termination's trigger, and a termination with a trigger is delayed.
Prepare finishes in its entry tick in both charts, but PreheatSuspend switches the heater on a tick later.

If the inside takes at least one tick to finish, as in the microwave, the timing is the same with or without the suspend.

A plain suspend is not checked in the tick its state is entered; an immediate suspend is. The two charts below differ only in that keyword. Both enter Cooking with the door already open, and the inner transition immediate do heater = true go to Heating runs as soon as it is allowed to:

StartDelayed and StartImmediateComparison

Diagrams

StartDelayed

Diagram of StartDelayedStates: Cooking (initial, superstate), Start (initial), Heating. Transitions: Start to Heating: / heater = true; Heating to Heating: remaining > 0 / remaining--.StartDelayedinput booldoorOpenoutput boolheater = falseoutput intremaining = 3CookingsuspenddoorOpenStartHeating/ heater = trueremaining > 0/ remaining--

StartImmediate

Diagram of StartImmediateStates: Cooking (initial, superstate), Start (initial), Heating. Transitions: Start to Heating: / heater = true; Heating to Heating: remaining > 0 / remaining--.StartImmediateinput booldoorOpenoutput boolheater = falseoutput intremaining = 3Cookingimmediate suspenddoorOpenStartHeating/ heater = trueremaining > 0/ remaining--

Code

StartDelayed

scchart StartDelayed {
input bool doorOpen
output bool heater = false
output int remaining = 3
initial state Cooking {
suspend if doorOpen
initial state Start
immediate do heater = true go to Heating
state Heating
if remaining > 0 do remaining-- go to Heating
}
}

StartImmediate

scchart StartImmediate {
input bool doorOpen
output bool heater = false
output int remaining = 3
initial state Cooking {
immediate suspend if doorOpen
initial state Start
immediate do heater = true go to Heating
state Heating
if remaining > 0 do remaining-- go to Heating
}
}
Tick 0 of 4
Inputs for tick 1, for both charts Boolean input: true while on. It keeps its value until you change it.
Timing diagram of StartDelayed and StartImmediate, no ticks yet
Tickinput bool doorOpenStartDelayed: output bool heaterStartDelayed: output int remainingStartDelayed: Active state of the chartStartDelayed: Active state of the region of CookingStartImmediate: output bool heaterStartImmediate: output int remainingStartImmediate: Active state of the chartStartImmediate: Active state of the region of Cooking
Click a tick to show it, or use the Left and Right arrow keys to go back and step.
Guided tour, 4 ticks Both charts get the same inputs. Press Next to run tick 1, or Take over to set the inputs yourself.

Guided tour, 4 ticks, the same inputs for both charts:

  1. doorOpen = trueThe door is already open in tick 1. StartDelayed: a plain suspend is not checked in the tick Cooking is entered, so the immediate transition from Start runs and switches the heater on. StartImmediate: immediate suspend is checked in the entry tick too, so Cooking is suspended at once and the heater stays off.
  2. From tick 2 on, the plain suspend is checked as well. The door is open, so both charts are frozen.
  3. doorOpen = falseThe door shuts. StartDelayed is already in Heating, so its countdown starts: remaining = 2. StartImmediate now runs the immediate transition that waited: the heater goes on and Heating is entered, but its delayed countdown can only start in the next tick.
  4. Both count down, StartImmediate one tick behind: remaining is 1 and 2.
The door is open in tick 1: StartDelayed switches the heater on anyway, StartImmediate waits until the door shuts in tick 3.

heater and remaining after each tick:

Tick doorOpen Delayed Immediate
1 true true, 3 false, 3
2 true (held) true, 3 false, 3
3 false true, 2 true, 3
4 false (held) true, 1 true, 2

StartImmediate’s countdown also starts a tick later: the transition that waited enters Heating in tick 3, and Heating’s delayed self-loop can only fire from tick 4.

A state whose immediate suspend holds in its entry tick does none of its entry-tick behaviour. Its immediate inner transitions and immediate during actions wait until it resumes, and then run. Its entry actions, and those of its inner initial states, are not postponed: they are skipped for good. Use immediate suspend when a state must do nothing at all while the condition holds, including in the tick it starts, and keep its set-up out of entry actions.

weak suspend if c sounds like a gentler suspend, but it does something quite different. In a tick in which c holds, the inside runs normally: transitions fire, entry and during actions run, and the values they write are kept. Then, at the end of the tick, every inner region is put back into the state it was in at the end of the last tick without weak suspension, and no entry action runs on the way back. The outputs of the tick happen; the moves do not count.

PreviewSimulation

Diagram

Diagram of PreviewStates: Slides (initial, superstate), Page1 (initial), Page2 (superstate), Page3 (superstate). Transitions: Page1 to Page2: next; Page2 to Page3: next.Previewinput boolpreview, nextoutput intpage = 1Slidesweak suspendpreviewPage1Page2entry/ page = 2Page3entry/ page = 3nextnext

Code

scchart Preview {
input bool preview, next
output int page = 1
initial state Slides {
weak suspend if preview
initial state Page1
if next go to Page2
state Page2 {
entry do page = 2
}
if next go to Page3
state Page3 {
entry do page = 3
}
}
}
Tick 0 of 6
Inputs for tick 1 Boolean input: true while on. It keeps its value until you change it. Boolean input: true while on. It keeps its value until you change it.
Timing diagram of Preview
Tickinput bool previewinput bool nextoutput int pageActive state of the chartActive state of the region of Slides
Click a tick to show it, or use the Left and Right arrow keys to go back and step.
Guided tour, 6 ticks Press Next to run tick 1, or Take over to set the inputs yourself.

Guided tour, 6 ticks:

  1. preview = false, next = falseTick 1 enters Slides and Page1; page = 1.
  2. preview = true, next = trueweak suspend holds, but unlike suspend the inside still runs: Page1 goes to Page2 and its entry action sets page = 2. At the end of the tick, though, the region is put back into Page1.
  3. next = falseThe chart is in Page1 while page still says 2: the data change was kept, the state change was not.
  4. preview = falseNo longer suspended. Still in Page1.
  5. next = truePage1 to Page2 again: page = 2.
  6. next is still true, so Page2 moves on to Page3: page = 3.
In tick 2 next moves to Page2 and sets page = 2, but the chart is back in Page1 afterwards. In tick 5 the same transition fires again.

After tick 2, page says 2 while the chart is in Page1: data and control disagree, which is rarely what you want. Unlike suspend, a weak suspend does not block the state’s own outgoing transitions, and immediate weak suspend applies in the entry tick too.

A metronome with a pause

Metronome toggles click in every tick until stop is pressed. Add a pause input that freezes the beat, so that when pause is released the metronome carries on where it was. stop must still work while the metronome is paused: check it by setting pause and then stop.

Show the starter chart
scchart Metronome {
input bool pause, stop
output bool click = false
initial state Running {
initial state Low
do click = true go to High
state High
do click = false go to Low
}
if stop go to Stopped
state Stopped
}
Show a solution
scchart Metronome {
input bool pause, stop
output bool click = false
initial state Running {
initial state Beating {
suspend if pause
initial state Low
do click = true go to High
state High
do click = false go to Low
}
}
if stop go to Stopped
state Stopped
}

Count every session

SessionCounter misses the first cooking session, because the entry action on the suspendable Cooking does not run on its first entry. Change the chart so that sessions counts every visit to Cooking, without removing the suspend.

Show the starter chart
scchart SessionCounter {
input bool start, stop, doorOpen
output int sessions = 0
initial state Idle
if start go to Cooking
state Cooking {
suspend if doorOpen
entry do sessions++
initial state Heating
}
if stop go to Idle
}
Show a solution
scchart SessionCounter {
input bool start, stop, doorOpen
output int sessions = 0
initial state Idle
if start do sessions++ go to Cooking
state Cooking {
suspend if doorOpen
initial state Heating
}
if stop go to Idle
}
State S has suspend if P and an outgoing transition if X go to T. S was entered in tick 1. In tick 5, P and X are both true. What happens in tick 5?
Show the answer

Answer C: S stays where it is and nothing inside it runs: the transition to T is frozen too

S’s own outgoing transitions belong to S, so they are suspended with it. T is reached in the first tick in which X holds and P does not. To be able to leave while suspended, put the suspend on a state inside S and keep the transition on S.

A state with suspend if P (not immediate) is entered in tick 4, and P is true in tick 4. Does the state’s immediate inner behaviour run in tick 4?
Show the answer

Answer A: Yes: a plain suspend is not checked in the tick the state is entered

A plain suspend is delayed, like a delayed transition: it is checked from the tick after the entry on. In the entry tick the state behaves normally (apart from the entry action quirk). immediate suspend if P would suspend it in tick 4 already.

Key ideas

  • suspend if c freezes a state in the ticks in which c holds: nothing inside it runs and nothing is counted, and it resumes where it stopped.
  • A plain suspend is not checked in the entry tick; immediate suspend is, and then swallows the entry actions.
  • pre is not frozen: it always looks at the previous tick, suspended or not.
  • A suspended state cannot be left by its own transitions, and abort to on it is rejected. Put the suspend on an inner state and the ways out on the state around it.
  • Keep entry and exit actions off a state with a suspend: KIELER skips them in some ticks without telling you.
  • weak suspend runs the tick and then forgets the state changes. You will rarely need it.

Next, History and deferred transitions: coming back to a superstate where you left it, and arriving in a state without its arrival behaviour.

Report a mistake on this page