1<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 2 3<html> 4<head> 5 <meta http-equiv="Content-Language" content="en-us"> 6 <meta http-equiv="Content-Type" content="text/html; charset=us-ascii"> 7 <meta name="GENERATOR" content="Microsoft FrontPage 6.0"> 8 <meta name="ProgId" content="FrontPage.Editor.Document"> 9 <link rel="stylesheet" type="text/css" href="../../../boost.css"> 10 11 <title>The Boost Statechart Library - Tutorial</title> 12</head> 13 14<body link="#0000FF" vlink="#800080"> 15 <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= 16 "header"> 17 <tr> 18 <td valign="top" width="300"> 19 <h3><a href="../../../index.htm"><img alt="C++ Boost" src= 20 "../../../boost.png" border="0" width="277" height="86"></a></h3> 21 </td> 22 23 <td valign="top"> 24 <h1 align="center">The Boost Statechart Library</h1> 25 26 <h2 align="center">Tutorial</h2> 27 </td> 28 </tr> 29 </table> 30 <hr> 31 32 <p>A Japanese translation of an earlier version of this tutorial can be 33 found at <a href= 34 "http://prdownloads.sourceforge.jp/jyugem/7127/fsm-tutorial-jp.pdf">http://prdownloads.sourceforge.jp/jyugem/7127/fsm-tutorial-jp.pdf</a>. 35 Kindly contributed by Mitsuo Fukasawa.</p> 36 37 <h2>Contents</h2> 38 39 <dl class="page-index"> 40 <dt><a href="#Introduction">Introduction</a></dt> 41 42 <dd><a href="#HowToReadThisTutorial">How to read this tutorial</a></dd> 43 44 <dt><a href="#HelloWorld">Hello World!</a></dt> 45 46 <dt><a href="#BasicTopicsAStopWatch">Basic topics: A stop watch</a></dt> 47 48 <dd><a href="#DefiningStatesAndEvents">Defining states and 49 events</a></dd> 50 51 <dd><a href="#AddingReactions">Adding reactions</a></dd> 52 53 <dd><a href="#StateLocalStorage">State-local storage</a></dd> 54 55 <dd><a href="#GettingStateInformationOutOfTheMachine">Getting state 56 information out of the machine</a></dd> 57 58 <dt><a href="#IntermediateTopicsADigitalCamera">Intermediate topics: A 59 digital camera</a></dt> 60 61 <dd><a href= 62 "#SpreadingAStateMachineOverMultipleTranslationUnits">Spreading a state 63 machine over multiple translation units</a></dd> 64 65 <dd><a href="#DeferringEvents">Deferring events</a></dd> 66 67 <dd><a href="#Guards">Guards</a></dd> 68 69 <dd><a href="#InStateReactions">In-state reactions</a></dd> 70 71 <dd><a href="#TransitionActions">Transition actions</a></dd> 72 73 <dt><a href="#AdvancedTopics">Advanced topics</a></dt> 74 75 <dd><a href="#SpecifyingMultipleReactionsForAState">Specifying multiple 76 reactions for a state</a></dd> 77 78 <dd><a href="#PostingEvents">Posting events</a></dd> 79 80 <dd><a href="#History">History</a></dd> 81 82 <dd><a href="#OrthogonalStates">Orthogonal states</a></dd> 83 84 <dd><a href="#StateQueries">State queries</a></dd> 85 86 <dd><a href="#StateTypeInformation">State type information</a></dd> 87 88 <dd><a href="#ExceptionHandling">Exception handling</a></dd> 89 90 <dd><a href="#SubmachinesAndParameterizedStates">Submachines & 91 Parametrized States</a></dd> 92 93 <dd><a href="#AsynchronousStateMachines">Asynchronous state 94 machines</a></dd> 95 </dl> 96 <hr> 97 98 <h2><a name="Introduction" id="Introduction">Introduction</a></h2> 99 100 <p>The Boost Statechart library is a framework that allows you to quickly 101 transform a UML statechart into executable C++ code, <b>without</b> needing 102 to use a code generator. Thanks to support for almost all UML features the 103 transformation is straight-forward and the resulting C++ code is a nearly 104 redundancy-free textual description of the statechart.</p> 105 106 <h3><a name="HowToReadThisTutorial" id="HowToReadThisTutorial">How to read 107 this tutorial</a></h3> 108 109 <p>This tutorial was designed to be read linearly. First time users should 110 start reading right at the beginning and stop as soon as they know enough 111 for the task at hand. Specifically:</p> 112 113 <ul> 114 <li>Small and simple machines with just a handful of states can be 115 implemented reasonably well by using the features described under 116 <a href="#BasicTopicsAStopWatch">Basic topics: A stop watch</a></li> 117 118 <li>For larger machines with up to roughly a dozen states the features 119 described under <a href="#IntermediateTopicsADigitalCamera">Intermediate 120 topics: A digital camera</a> are often helpful</li> 121 122 <li>Finally, users wanting to create even more complex machines and 123 project architects evaluating Boost.Statechart should also read the 124 <a href="#AdvancedTopics">Advanced topics</a> section at the end. 125 Moreover, reading the <a href= 126 "rationale.html#Limitations">Limitations</a> section in the Rationale is 127 strongly suggested</li> 128 </ul> 129 130 <h2><a name="HelloWorld" id="HelloWorld">Hello World!</a></h2> 131 132 <p>We will use the simplest possible program to make our first steps. The 133 statechart ...</p> 134 135 <p><img alt="HelloWorld" src="HelloWorld.gif" border="0" width="379" 136 height="94"></p> 137 138 <p>... is implemented with the following code:</p> 139 <pre> 140#include <boost/statechart/state_machine.hpp> 141#include <boost/statechart/simple_state.hpp> 142#include <iostream> 143 144namespace sc = boost::statechart; 145 146// We are declaring all types as <code>struct</code>s only to avoid having to 147// type <code>public</code>. If you don't mind doing so, you can just as well 148// use <code>class.</code> 149 150// We need to forward-declare the initial state because it can 151// only be defined at a point where the state machine is 152// defined. 153struct Greeting; 154 155// Boost.Statechart makes heavy use of the curiously recurring 156// template pattern. The deriving class must always be passed as 157// the first parameter to all base class templates. 158// 159// The state machine must be informed which state it has to 160// enter when the machine is initiated. That's why Greeting is 161// passed as the second template parameter. 162struct Machine : sc::state_machine< Machine, Greeting > {}; 163 164// For each state we need to define which state machine it 165// belongs to and where it is located in the statechart. Both is 166// specified with Context argument that is passed to 167// simple_state<>. For a flat state machine as we have it here, 168// the context is always the state machine. Consequently, 169// Machine must be passed as the second template parameter to 170// Greeting's base (the Context parameter is explained in more 171// detail in the next example). 172struct Greeting : sc::simple_state< Greeting, Machine > 173{ 174 // Whenever the state machine enters a state, it creates an 175 // object of the corresponding state class. The object is then 176 // kept alive as long as the machine remains in the state. 177 // Finally, the object is destroyed when the state machine 178 // exits the state. Therefore, a state entry action can be 179 // defined by adding a constructor and a state exit action can 180 // be defined by adding a destructor. 181 Greeting() { std::cout << "Hello World!\n"; } // entry 182 ~Greeting() { std::cout << "Bye Bye World!\n"; } // exit 183}; 184 185int main() 186{ 187 Machine myMachine; 188 // The machine is not yet running after construction. We start 189 // it by calling initiate(). This triggers the construction of 190 // the initial state Greeting 191 myMachine.initiate(); 192 // When we leave main(), myMachine is destructed what leads to 193 // the destruction of all currently active states. 194 return 0; 195} 196</pre> 197 198 <p>This prints <code>Hello World!</code> and <code>Bye Bye World!</code> 199 before exiting.</p> 200 201 <h2><a name="BasicTopicsAStopWatch" id="BasicTopicsAStopWatch">Basic 202 topics: A stop watch</a></h2> 203 204 <p>Next we will model a simple mechanical stop watch with a state machine. 205 Such watches typically have two buttons:</p> 206 207 <ul> 208 <li>Start/Stop</li> 209 210 <li>Reset</li> 211 </ul> 212 213 <p>And two states:</p> 214 215 <ul> 216 <li>Stopped: The hands reside in the position where they were last 217 stopped: 218 219 <ul> 220 <li>Pressing the reset button moves the hands back to the 0 position. 221 The watch remains in the Stopped state</li> 222 223 <li>Pressing the start/stop button leads to a transition to the 224 Running state</li> 225 </ul> 226 </li> 227 228 <li>Running: The hands of the watch are in motion and continually show 229 the elapsed time 230 231 <ul> 232 <li>Pressing the reset button moves the hands back to the 0 position 233 and leads to a transition to the Stopped state</li> 234 235 <li>Pressing the start/stop button leads to a transition to the 236 Stopped state</li> 237 </ul> 238 </li> 239 </ul> 240 241 <p>Here is one way to specify this in UML:</p> 242 243 <p><img alt="StopWatch" src="StopWatch.gif" border="0" width="560" height= 244 "184"></p> 245 246 <h3><a name="DefiningStatesAndEvents" id="DefiningStatesAndEvents">Defining 247 states and events</a></h3> 248 249 <p>The two buttons are modeled by two events. Moreover, we also define the 250 necessary states and the initial state. <b>The following code is our 251 starting point, subsequent code snippets must be inserted</b>:</p> 252 <pre> 253#include <boost/statechart/event.hpp> 254#include <boost/statechart/state_machine.hpp> 255#include <boost/statechart/simple_state.hpp> 256 257namespace sc = boost::statechart; 258 259struct EvStartStop : sc::event< EvStartStop > {}; 260struct EvReset : sc::event< EvReset > {}; 261 262struct Active; 263struct StopWatch : sc::state_machine< StopWatch, Active > {}; 264 265struct Stopped; 266 267// The simple_state class template accepts up to four parameters: 268// - The third parameter specifies the inner initial state, if 269// there is one. Here, only Active has inner states, which is 270// why it needs to pass its inner initial state Stopped to its 271// base 272// - The fourth parameter specifies whether and what kind of 273// history is kept 274 275// Active is the outermost state and therefore needs to pass the 276// state machine class it belongs to 277struct Active : sc::simple_state< 278 Active, StopWatch, Stopped > {}; 279 280// Stopped and Running both specify Active as their Context, 281// which makes them nested inside Active 282struct Running : sc::simple_state< Running, Active > {}; 283struct Stopped : sc::simple_state< Stopped, Active > {}; 284 285// Because the context of a state must be a complete type (i.e. 286// not forward declared), a machine must be defined from 287// "outside to inside". That is, we always start with the state 288// machine, followed by outermost states, followed by the direct 289// inner states of outermost states and so on. We can do so in a 290// breadth-first or depth-first way or employ a mixture of the 291// two. 292 293int main() 294{ 295 StopWatch myWatch; 296 myWatch.initiate(); 297 return 0; 298} 299</pre> 300 301 <p>This compiles but doesn't do anything observable yet.</p> 302 303 <h3><a name="AddingReactions" id="AddingReactions">Adding 304 reactions</a></h3> 305 306 <p>For the moment we will use only one type of reaction: transitions. We 307 <b>insert</b> the bold parts of the following code:</p> 308 <pre> 309<b>#include <boost/statechart/transition.hpp> 310</b> 311// ... 312 313struct Stopped; 314struct Active : sc::simple_state< Active, StopWatch, Stopped > 315{ 316 <b>typedef sc::transition< EvReset, Active > reactions;</b> 317}; 318 319struct Running : sc::simple_state< Running, Active > 320{ 321 <b>typedef sc::transition< EvStartStop, Stopped > reactions;</b> 322}; 323 324struct Stopped : sc::simple_state< Stopped, Active > 325{ 326 <b>typedef sc::transition< EvStartStop, Running > reactions;</b> 327}; 328 329// A state can define an arbitrary number of reactions. That's 330// why we have to put them into an mpl::list<> as soon as there 331// is more than one of them 332// (see <a href= 333"#SpecifyingMultipleReactionsForAState">Specifying multiple reactions for a state</a>). 334 335int main() 336{ 337 StopWatch myWatch; 338 myWatch.initiate(); 339 <b>myWatch.process_event( EvStartStop() ); 340</b> <b>myWatch.process_event( EvStartStop() ); 341</b> <b>myWatch.process_event( EvStartStop() ); 342</b> <b>myWatch.process_event( EvReset() ); 343</b> return 0; 344} 345</pre> 346 347 <p>Now we have all the states and all the transitions in place and a number 348 of events are also sent to the stop watch. The machine dutifully makes the 349 transitions we would expect, but no actions are executed yet.</p> 350 351 <h3><a name="StateLocalStorage" id="StateLocalStorage">State-local 352 storage</a></h3> 353 354 <p>Next we'll make the stop watch actually measure time. Depending on the 355 state the stop watch is in, we need different variables:</p> 356 357 <ul> 358 <li>Stopped: One variable holding the elapsed time</li> 359 360 <li>Running: One variable holding the elapsed time <b>and</b> one 361 variable storing the point in time at which the watch was last 362 started.</li> 363 </ul> 364 365 <p>We observe that the elapsed time variable is needed no matter what state 366 the machine is in. Moreover, this variable should be reset to 0 when we 367 send an <code>EvReset</code> event to the machine. The other variable is 368 only needed while the machine is in the Running state. It should be set to 369 the current time of the system clock whenever we enter the Running state. 370 Upon exit we simply subtract the start time from the current system clock 371 time and add the result to the elapsed time.</p> 372 <pre> 373<b>#include <ctime> 374</b> 375// ... 376 377struct Stopped; 378struct Active : sc::simple_state< Active, StopWatch, Stopped > 379{ 380 <b>public:</b> 381 typedef sc::transition< EvReset, Active > reactions; 382 383 <b>Active() : elapsedTime_( 0.0 ) {} 384</b> <b>double ElapsedTime() const { return elapsedTime_; } 385</b> <b>double & ElapsedTime() { return elapsedTime_; } 386</b> <b>private: 387</b> <b>double elapsedTime_; 388</b>}; 389 390struct Running : sc::simple_state< Running, Active > 391{ 392 <b>public:</b> 393 typedef sc::transition< EvStartStop, Stopped > reactions; 394 395 <b>Running() : startTime_( std::time( 0 ) ) {} 396</b> <b>~Running() 397</b> <b>{</b> 398 // Similar to when a derived class object accesses its 399 // base class portion, context<>() is used to gain 400 // access to the direct or indirect context of a state. 401 // This can either be a direct or indirect outer state 402 // or the state machine itself 403 // (e.g. here: context< StopWatch >()). 404 <b>context< Active >().ElapsedTime() += 405</b> <b>std::difftime( std::time( 0 ), startTime_ ); 406</b> <b>} 407</b> <b>private: 408</b> <b>std::time_t startTime_; 409</b>}; 410 411// ... 412</pre> 413 414 <p>The machine now measures the time, but we cannot yet retrieve it from 415 the main program.</p> 416 417 <p>At this point, the advantages of state-local storage (which is still a 418 relatively little-known feature) may not yet have become apparent. The FAQ 419 item "<a href="faq.html#StateLocalStorage">What's so cool about state-local 420 storage?</a>" tries to explain them in more detail by comparing this 421 StopWatch with one that does not make use of state-local storage.</p> 422 423 <h3><a name="GettingStateInformationOutOfTheMachine" id= 424 "GettingStateInformationOutOfTheMachine">Getting state information out of 425 the machine</a></h3> 426 427 <p>To retrieve the measured time, we need a mechanism to get state 428 information out of the machine. With our current machine design there are 429 two ways to do that. For the sake of simplicity we use the less efficient 430 one: <code>state_cast<>()</code> (StopWatch2.cpp shows the slightly 431 more complex alternative). As the name suggests, the semantics are very 432 similar to the ones of <code>dynamic_cast</code>. For example, when we call 433 <code>myWatch.state_cast< const Stopped & >()</code> <b>and</b> 434 the machine is currently in the Stopped state, we get a reference to the 435 <code>Stopped</code> state. Otherwise <code>std::bad_cast</code> is thrown. 436 We can use this functionality to implement a <code>StopWatch</code> member 437 function that returns the elapsed time. However, rather than ask the 438 machine in which state it is and then switch to different calculations for 439 the elapsed time, we put the calculation into the Stopped and Running 440 states and use an interface to retrieve the elapsed time:</p> 441 <pre> 442<b>#include <iostream> 443 444</b>// ... 445 446<b>struct IElapsedTime 447{ 448</b> <b>virtual double ElapsedTime() const = 0; 449}; 450 451</b>struct Active; 452struct StopWatch : sc::state_machine< StopWatch, Active > 453{ 454 <b>double ElapsedTime() const 455</b> <b>{ 456</b> <b>return state_cast< const IElapsedTime & >().ElapsedTime(); 457</b> <b>} 458</b>}; 459<b> 460</b>// ... 461 462struct Running : <b>IElapsedTime,</b> 463 sc::simple_state< Running, Active > 464{ 465 public: 466 typedef sc::transition< EvStartStop, Stopped > reactions; 467 468 Running() : startTime_( std::time( 0 ) ) {} 469 ~Running() 470 { 471 <b>context< Active >().ElapsedTime() = ElapsedTime(); 472</b> } 473<b> 474</b> <b>virtual double ElapsedTime() const 475</b> <b>{ 476</b> <b>return context< Active >().ElapsedTime() + 477</b> <b>std::difftime( std::time( 0 ), startTime_ ); 478</b> <b>} 479</b> private: 480 std::time_t startTime_; 481}; 482 483struct Stopped : <b>IElapsedTime,</b> 484 sc::simple_state< Stopped, Active > 485{ 486 typedef sc::transition< EvStartStop, Running > reactions; 487 488 <b>virtual double ElapsedTime() const 489</b> <b>{ 490</b> <b>return context< Active >().ElapsedTime(); 491</b> <b>} 492</b>}; 493 494int main() 495{ 496 StopWatch myWatch; 497 myWatch.initiate(); 498 <b>std::cout << myWatch.ElapsedTime() << "\n"; 499</b> myWatch.process_event( EvStartStop() ); 500 <b>std::cout << myWatch.ElapsedTime() << "\n"; 501</b> myWatch.process_event( EvStartStop() ); 502 <b>std::cout << myWatch.ElapsedTime() << "\n"; 503</b> myWatch.process_event( EvStartStop() ); 504 <b>std::cout << myWatch.ElapsedTime() << "\n"; 505</b> myWatch.process_event( EvReset() ); 506 <b>std::cout << myWatch.ElapsedTime() << "\n"; 507</b> return 0; 508} 509</pre> 510 511 <p>To actually see time being measured, you might want to single-step 512 through the statements in <code>main()</code>. The StopWatch example 513 extends this program to an interactive console application.</p> 514 515 <h2><a name="IntermediateTopicsADigitalCamera" id= 516 "IntermediateTopicsADigitalCamera">Intermediate topics: A digital 517 camera</a></h2> 518 519 <p>So far so good. However, the approach presented above has a few 520 limitations:</p> 521 522 <ul> 523 <li>Bad scalability: As soon as the compiler reaches the point where 524 <code>state_machine::initiate()</code> is called, a number of template 525 instantiations take place, which can only succeed if the full declaration 526 of each and every state of the machine is known. That is, the whole 527 layout of a state machine must be implemented in one single translation 528 unit (actions can be compiled separately, but this is of no importance 529 here). For bigger (and more real-world) state machines, this leads to the 530 following limitations: 531 532 <ul> 533 <li>At some point compilers reach their internal template 534 instantiation limits and give up. This can happen even for 535 moderately-sized machines. For example, in debug mode one popular 536 compiler refused to compile earlier versions of the BitMachine 537 example for anything above 3 bits. This means that the compiler 538 reached its limits somewhere between 8 states, 24 transitions and 16 539 states, 64 transitions</li> 540 541 <li>Multiple programmers can hardly work on the same state machine 542 simultaneously because every layout change will inevitably lead to a 543 recompilation of the whole state machine</li> 544 </ul> 545 </li> 546 547 <li>Maximum one reaction per event: According to UML a state can have 548 multiple reactions triggered by the same event. This makes sense when all 549 reactions have mutually exclusive guards. The interface we used above 550 only allows for at most one unguarded reaction for each event. Moreover, 551 the UML concepts junction and choice point are not directly 552 supported</li> 553 </ul> 554 555 <p>All these limitations can be overcome with custom reactions. <b>Warning: 556 It is easy to abuse custom reactions up to the point of invoking undefined 557 behavior. Please study the documentation before employing them!</b></p> 558 559 <h3><a name="SpreadingAStateMachineOverMultipleTranslationUnits" id= 560 "SpreadingAStateMachineOverMultipleTranslationUnits">Spreading a state 561 machine over multiple translation units</a></h3> 562 563 <p>Let's say your company would like to develop a digital camera. The 564 camera has the following controls:</p> 565 566 <ul> 567 <li>Shutter button, which can be half-pressed and fully-pressed. The 568 associated events are <code>EvShutterHalf</code>, 569 <code>EvShutterFull</code> and <code>EvShutterReleased</code></li> 570 571 <li>Config button, represented by the <code>EvConfig</code> event</li> 572 573 <li>A number of other buttons that are not of interest here</li> 574 </ul> 575 576 <p>One use case for the camera says that the photographer can half-press 577 the shutter <b>anywhere</b> in the configuration mode and the camera will 578 immediately go into shooting mode. The following statechart is one way to 579 achieve this behavior:</p> 580 581 <p><img alt="Camera" src="Camera.gif" border="0" width="544" height= 582 "317"></p> 583 584 <p>The Configuring and Shooting states will contain numerous nested states 585 while the Idle state is relatively simple. It was therefore decided to 586 build two teams. One will implement the shooting mode while the other will 587 implement the configuration mode. The two teams have already agreed on the 588 interface that the shooting team will use to retrieve the configuration 589 settings. We would like to ensure that the two teams can work with the 590 least possible interference. So, we put the two states in their own 591 translation units so that machine layout changes within the Configuring 592 state will never lead to a recompilation of the inner workings of the 593 Shooting state and vice versa.</p> 594 595 <p><b>Unlike in the previous example, the excerpts presented here often 596 outline different options to achieve the same effect. That's why the code 597 is often not equal to the Camera example code.</b> Comments mark the parts 598 where this is the case.</p> 599 600 <p>Camera.hpp:</p> 601 <pre> 602#ifndef CAMERA_HPP_INCLUDED 603#define CAMERA_HPP_INCLUDED 604 605#include <boost/statechart/event.hpp> 606#include <boost/statechart/state_machine.hpp> 607#include <boost/statechart/simple_state.hpp> 608#include <boost/statechart/custom_reaction.hpp> 609 610namespace sc = boost::statechart; 611 612struct EvShutterHalf : sc::event< EvShutterHalf > {}; 613struct EvShutterFull : sc::event< EvShutterFull > {}; 614struct EvShutterRelease : sc::event< EvShutterRelease > {}; 615struct EvConfig : sc::event< EvConfig > {}; 616 617struct NotShooting; 618struct Camera : sc::state_machine< Camera, NotShooting > 619{ 620 bool IsMemoryAvailable() const { return true; } 621 bool IsBatteryLow() const { return false; } 622}; 623 624struct Idle; 625struct NotShooting : sc::simple_state< 626 NotShooting, Camera, Idle > 627{ 628 // With a custom reaction we only specify that we <b>might</b> do 629 // something with a particular event, but the actual reaction 630 // is defined in the react member function, which can be 631 // implemented in the .cpp file. 632 <b>typedef sc::custom_reaction< EvShutterHalf > reactions;</b> 633 634 // ... 635 <b>sc::result react( const EvShutterHalf & );</b> 636}; 637 638struct Idle : sc::simple_state< Idle, NotShooting > 639{ 640 <b>typedef sc::custom_reaction< EvConfig > reactions;</b> 641 642 // ... 643 <b>sc::result react( const EvConfig & );</b> 644}; 645 646#endif 647</pre> 648 649 <p>Camera.cpp:</p> 650 <pre> 651#include "Camera.hpp" 652 653// The following includes are only made here but not in 654// Camera.hpp 655// The Shooting and Configuring states can themselves apply the 656// same pattern to hide their inner implementation, which 657// ensures that the two teams working on the Camera state 658// machine will never need to disturb each other. 659#include "Configuring.hpp" 660#include "Shooting.hpp" 661 662// ... 663 664// not part of the Camera example 665sc::result NotShooting::react( const EvShutterHalf & ) 666{ 667 return transit< Shooting >(); 668} 669 670sc::result Idle::react( const EvConfig & ) 671{ 672 return transit< Configuring >(); 673} 674</pre> 675 676 <p><b><font color="#FF0000">Caution: Any call to 677 <code>simple_state<>::transit<>()</code> or 678 <code>simple_state<>::terminate()</code> (see <a href= 679 "reference.html#transit1">reference</a>) will inevitably destruct the state 680 object (similar to <code>delete this;</code>)! That is, code executed after 681 any of these calls may invoke undefined behavior!</font></b> That's why 682 these functions should only be called as part of a return statement.</p> 683 684 <h3><a name="DeferringEvents" id="DeferringEvents">Deferring 685 events</a></h3> 686 687 <p>The inner workings of the Shooting state could look as follows:</p> 688 689 <p><img alt="Camera2" src="Camera2.gif" border="0" width="427" height= 690 "427"></p> 691 692 <p>When the user half-presses the shutter, Shooting and its inner initial 693 state Focusing are entered. In the Focusing entry action the camera 694 instructs the focusing circuit to bring the subject into focus. The 695 focusing circuit then moves the lenses accordingly and sends the EvInFocus 696 event as soon as it is done. Of course, the user can fully-press the 697 shutter while the lenses are still in motion. Without any precautions, the 698 resulting EvShutterFull event would simply be lost because the Focusing 699 state does not define a reaction for this event. As a result, the user 700 would have to fully-press the shutter again after the camera has finished 701 focusing. To prevent this, the EvShutterFull event is deferred inside the 702 Focusing state. This means that all events of this type are stored in a 703 separate queue, which is emptied into the main queue when the Focusing 704 state is exited.</p> 705 <pre> 706struct Focusing : sc::state< Focusing, Shooting > 707{ 708 typedef mpl::list< 709 sc::custom_reaction< EvInFocus >, 710 <b>sc::deferral< EvShutterFull ></b> 711 > reactions; 712 713 Focusing( my_context ctx ); 714 sc::result react( const EvInFocus & ); 715}; 716</pre> 717 718 <h3><a name="Guards" id="Guards">Guards</a></h3> 719 720 <p>Both transitions originating at the Focused state are triggered by the 721 same event but they have mutually exclusive guards. Here is an appropriate 722 custom reaction:</p> 723 <pre> 724// not part of the Camera example 725sc::result Focused::react( const EvShutterFull & ) 726{ 727 if ( context< Camera >().IsMemoryAvailable() ) 728 { 729 return transit< Storing >(); 730 } 731 else 732 { 733 // The following is actually a mixture between an in-state 734 // reaction and a transition. See later on how to implement 735 // proper transition actions. 736 std::cout << "Cache memory full. Please wait...\n"; 737 return transit< Focused >(); 738 } 739} 740</pre> 741 742 <p>Custom reactions can of course also be implemented directly in the state 743 declaration, which is often preferable for easier browsing.</p> 744 745 <p>Next we will use a guard to prevent a transition and let outer states 746 react to the event if the battery is low:</p> 747 748 <p>Camera.cpp:</p> 749 <pre> 750// ... 751sc::result NotShooting::react( const EvShutterHalf & ) 752{ 753 if ( context< Camera >().IsBatteryLow() ) 754 { 755 // We cannot react to the event ourselves, so we forward it 756 // to our outer state (this is also the default if a state 757 // defines no reaction for a given event). 758 <b>return forward_event();</b> 759 } 760 else 761 { 762 return transit< Shooting >(); 763 } 764} 765// ... 766</pre> 767 768 <h3><a name="InStateReactions" id="InStateReactions">In-state 769 reactions</a></h3> 770 771 <p>The self-transition of the Focused state could also be implemented as an 772 <a href="definitions.html#InStateReaction">in-state reaction</a>, which has 773 the same effect as long as Focused does not have any entry or exit 774 actions:</p> 775 776 <p>Shooting.cpp:</p> 777 <pre> 778// ... 779sc::result Focused::react( const EvShutterFull & ) 780{ 781 if ( context< Camera >().IsMemoryAvailable() ) 782 { 783 return transit< Storing >(); 784 } 785 else 786 { 787 std::cout << "Cache memory full. Please wait...\n"; 788 // Indicate that the event can be discarded. So, the 789 // dispatch algorithm will stop looking for a reaction 790 // and the machine remains in the Focused state. 791 <b>return discard_event();</b> 792 } 793} 794// ... 795</pre> 796 797 <p>Because the in-state reaction is guarded, we need to employ a 798 <code>custom_reaction<></code> here. For unguarded in-state reactions 799 <code><a href= 800 "reference.html#ClassTemplatein_state_reaction">in_state_reaction</a><></code> 801 should be used for better code-readability.</p> 802 803 <h3><a name="TransitionActions" id="TransitionActions">Transition 804 actions</a></h3> 805 806 <p>As an effect of every transition, actions are executed in the following 807 order:</p> 808 809 <ol> 810 <li>Starting from the innermost active state, all exit actions up to but 811 excluding the <a href="definitions.html#InnermostCommonContext">innermost 812 common context</a></li> 813 814 <li>The transition action (if present)</li> 815 816 <li>Starting from the innermost common context, all entry actions down to 817 the target state followed by the entry actions of the initial states</li> 818 </ol> 819 820 <p>Example:</p> 821 822 <p><img alt="LCA" src="LCA.gif" border="0" width="604" height="304"></p> 823 824 <p>Here the order is as follows: ~D(), ~C(), ~B(), ~A(), t(), X(), Y(), 825 Z(). The transition action t() is therefore executed in the context of the 826 InnermostCommonOuter state because the source state has already been left 827 (destructed) and the target state has not yet been entered 828 (constructed).</p> 829 830 <p>With Boost.Statechart, a transition action can be a member of <b>any</b> 831 common outer context. That is, the transition between Focusing and Focused 832 could be implemented as follows:</p> 833 834 <p>Shooting.hpp:</p> 835 <pre> 836// ... 837struct Focusing; 838struct Shooting : sc::simple_state< Shooting, Camera, Focusing > 839{ 840 typedef sc::transition< 841 EvShutterRelease, NotShooting > reactions; 842 843 // ... 844 <b>void DisplayFocused( const EvInFocus & );</b> 845}; 846 847// ... 848 849// not part of the Camera example 850struct Focusing : sc::simple_state< Focusing, Shooting > 851{ 852 typedef sc::transition< EvInFocus, Focused<b>,</b> 853 <b>Shooting, &Shooting::DisplayFocused</b> > reactions; 854}; 855</pre> 856 857 <p><b>Or</b>, the following is also possible (here the state machine itself 858 serves as the outermost context):</p> 859 <pre> 860// not part of the Camera example 861struct Camera : sc::state_machine< Camera, NotShooting > 862{ 863 <b>void DisplayFocused( const EvInFocus & );</b> 864}; 865</pre> 866 <pre> 867// not part of the Camera example 868struct Focusing : sc::simple_state< Focusing, Shooting > 869{ 870 typedef sc::transition< EvInFocus, Focused<b>,</b> 871 <b>Camera, &Camera::DisplayFocused</b> > reactions; 872}; 873</pre> 874 875 <p>Naturally, transition actions can also be invoked from custom 876 reactions:</p> 877 878 <p>Shooting.cpp:</p> 879 <pre> 880// ... 881sc::result Focusing::react( const EvInFocus & evt ) 882{ 883 // We have to manually forward evt 884 return transit< Focused >( <b>&Shooting::DisplayFocused</b>, evt ); 885} 886</pre> 887 888 <h2><a name="AdvancedTopics" id="AdvancedTopics">Advanced topics</a></h2> 889 890 <h3><a name="SpecifyingMultipleReactionsForAState" id= 891 "SpecifyingMultipleReactionsForAState">Specifying multiple reactions for a 892 state</a></h3> 893 894 <p>Often a state must define reactions for more than one event. In this 895 case, an <code>mpl::list<></code> must be used as outlined below:</p> 896 <pre> 897// ... 898 899<b>#include <boost/mpl/list.hpp> 900</b> 901<b>namespace mpl = boost::mpl; 902</b> 903// ... 904 905struct Playing : sc::simple_state< Playing, Mp3Player > 906{ 907 typdef <b>mpl::list<</b> 908 sc::custom_reaction< EvFastForward >, 909 sc::transition< EvStop, Stopped > <b>></b> reactions; 910 911 /* ... */ 912}; 913</pre> 914 915 <h3><a name="PostingEvents" id="PostingEvents">Posting events</a></h3> 916 917 <p>Non-trivial state machines often need to post internal events. Here's an 918 example of how to do this:</p> 919 <pre> 920Pumping::~Pumping() 921{ 922 post_event( EvPumpingFinished() ); 923} 924</pre> 925 926 <p>The event is pushed into the main queue. The events in the queue are 927 processed as soon as the current reaction is completed. Events can be 928 posted from inside <code>react</code> functions, entry-, exit- and 929 transition actions. However, posting from inside entry actions is a bit 930 more complicated (see e.g. <code>Focusing::Focusing()</code> in 931 <code>Shooting.cpp</code> in the Camera example):</p> 932 <pre> 933struct Pumping : <b>sc::state</b>< Pumping, Purifier > 934{ 935 <b>Pumping( my_context ctx ) : my_base( ctx )</b> 936 { 937 post_event( EvPumpingStarted() ); 938 } 939 // ... 940}; 941</pre> 942 943 <p>As soon as an entry action of a state needs to contact the "outside 944 world" (here: the event queue in the state machine), the state must derive 945 from <code>state<></code> rather than from 946 <code>simple_state<></code> and must implement a forwarding 947 constructor as outlined above (apart from the constructor, 948 <code>state<></code> offers the same interface as 949 <code>simple_state<></code>). Hence, this must be done whenever an 950 entry action makes one or more calls to the following functions:</p> 951 952 <ul> 953 <li><code>simple_state<>::post_event()</code></li> 954 955 <li> 956 <code>simple_state<>::clear_shallow_history<>()</code></li> 957 958 <li><code>simple_state<>::clear_deep_history<>()</code></li> 959 960 <li><code>simple_state<>::outermost_context()</code></li> 961 962 <li><code>simple_state<>::context<>()</code></li> 963 964 <li><code>simple_state<>::state_cast<>()</code></li> 965 966 <li><code>simple_state<>::state_downcast<>()</code></li> 967 968 <li><code>simple_state<>::state_begin()</code></li> 969 970 <li><code>simple_state<>::state_end()</code></li> 971 </ul> 972 973 <p>In my experience, these functions are needed only rarely in entry 974 actions so this workaround should not uglify user code too much.</p> 975 976 <h3><a name="History" id="History">History</a></h3> 977 978 <p>Photographers testing beta versions of our <a href= 979 "#SpreadingAStateMachineOverMultipleTranslationUnits">digital camera</a> 980 said that they really liked that half-pressing the shutter anytime (even 981 while the camera is being configured) immediately readies the camera for 982 picture-taking. However, most of them found it unintuitive that the camera 983 always goes into the idle mode after releasing the shutter. They would 984 rather see the camera go back into the state it had before half-pressing 985 the shutter. This way they can easily test the influence of a configuration 986 setting by modifying it, half- and then fully-pressing the shutter to take 987 a picture. Finally, releasing the shutter will bring them back to the 988 screen where they have modified the setting. To implement this behavior 989 we'd change the state chart as follows:</p> 990 991 <p><img alt="CameraWithHistory1" src="CameraWithHistory1.gif" border="0" 992 width="542" height="378"></p> 993 994 <p>As mentioned earlier, the Configuring state contains a fairly complex 995 and deeply nested inner machine. Naturally, we'd like to restore the 996 previous state down to the <a href= 997 "definitions.html#InnermostState">innermost state</a>(s) in Configuring, 998 that's why we use a deep history pseudo state. The associated code looks as 999 follows:</p> 1000 <pre> 1001// not part of the Camera example 1002struct NotShooting : sc::simple_state< 1003 NotShooting, Camera, Idle, <b>sc::has_deep_history</b> > 1004{ 1005 // ... 1006}; 1007 1008// ... 1009 1010struct Shooting : sc::simple_state< Shooting, Camera, Focusing > 1011{ 1012 typedef sc::transition< 1013 EvShutterRelease, <b>sc::deep_history< Idle ></b> > reactions; 1014 1015 // ... 1016}; 1017</pre> 1018 1019 <p>History has two phases: Firstly, when the state containing the history 1020 pseudo state is exited, information about the previously active inner state 1021 hierarchy must be saved. Secondly, when a transition to the history pseudo 1022 state is made later, the saved state hierarchy information must be 1023 retrieved and the appropriate states entered. The former is expressed by 1024 passing either <code>has_shallow_history</code>, 1025 <code>has_deep_history</code> or <code>has_full_history</code> (which 1026 combines shallow and deep history) as the last parameter to the 1027 <code>simple_state</code> and <code>state</code> class templates. The 1028 latter is expressed by specifying either 1029 <code>shallow_history<></code> or <code>deep_history<></code> 1030 as a transition destination or, as we'll see in an instant, as an inner 1031 initial state. Because it is possible that a state containing a history 1032 pseudo state has never been entered before a transition to history is made, 1033 both class templates demand a parameter specifying the default state to 1034 enter in such situations.</p> 1035 1036 <p>The redundancy necessary for using history is checked for consistency at 1037 compile time. That is, the state machine wouldn't have compiled had we 1038 forgotten to pass <code>has_deep_history</code> to the base of 1039 <code>NotShooting</code>.</p> 1040 1041 <p>Another change request filed by a few beta testers says that they would 1042 like to see the camera go back into the state it had before turning it off 1043 when they turn it back on. Here's the implementation:</p> 1044 1045 <p><img alt="CameraWithHistory2" src="CameraWithHistory2.gif" border="0" 1046 width="468" height="483"></p> 1047 <pre> 1048// ... 1049 1050// not part of the Camera example 1051struct NotShooting : sc::simple_state< NotShooting, Camera, 1052 <b>mpl::list< sc::deep_history< Idle > ></b>, 1053 <b>sc::has_deep_history</b> > 1054{ 1055 // ... 1056}; 1057 1058// ... 1059</pre> 1060 1061 <p>Unfortunately, there is a small inconvenience due to some 1062 template-related implementation details. When the inner initial state is a 1063 class template instantiation we always have to put it into an 1064 <code>mpl::list<></code>, although there is only one inner initial 1065 state. Moreover, the current deep history implementation has some <a href= 1066 "rationale.html#Limitations">limitations</a>.</p> 1067 1068 <h3><a name="OrthogonalStates" id="OrthogonalStates">Orthogonal 1069 states</a></h3> 1070 1071 <p><img alt="OrthogonalStates" src="OrthogonalStates.gif" border="0" width= 1072 "633" height="393"></p> 1073 1074 <p>To implement this statechart you simply specify more than one inner 1075 initial state (see the Keyboard example):</p> 1076 <pre> 1077struct Active; 1078struct Keyboard : sc::state_machine< Keyboard, Active > {}; 1079 1080struct NumLockOff; 1081struct CapsLockOff; 1082struct ScrollLockOff; 1083struct Active: sc::simple_state< Active, Keyboard, 1084 <b>mpl::list< NumLockOff, CapsLockOff, ScrollLockOff ></b> > {}; 1085</pre> 1086 1087 <p>Active's inner states must declare which orthogonal region they belong 1088 to:</p> 1089 <pre> 1090struct EvNumLockPressed : sc::event< EvNumLockPressed > {}; 1091struct EvCapsLockPressed : sc::event< EvCapsLockPressed > {}; 1092struct EvScrollLockPressed : 1093 sc::event< EvScrollLockPressed > {}; 1094 1095struct NumLockOn : sc::simple_state< 1096 NumLockOn, Active<b>::orthogonal< 0 ></b> > 1097{ 1098 typedef sc::transition< 1099 EvNumLockPressed, NumLockOff > reactions; 1100}; 1101 1102struct NumLockOff : sc::simple_state< 1103 NumLockOff, Active<b>::orthogonal< 0 ></b> > 1104{ 1105 typedef sc::transition< 1106 EvNumLockPressed, NumLockOn > reactions; 1107}; 1108 1109struct CapsLockOn : sc::simple_state< 1110 CapsLockOn, Active<b>::orthogonal< 1 ></b> > 1111{ 1112 typedef sc::transition< 1113 EvCapsLockPressed, CapsLockOff > reactions; 1114}; 1115 1116struct CapsLockOff : sc::simple_state< 1117 CapsLockOff, Active<b>::orthogonal< 1 ></b> > 1118{ 1119 typedef sc::transition< 1120 EvCapsLockPressed, CapsLockOn > reactions; 1121}; 1122 1123struct ScrollLockOn : sc::simple_state< 1124 ScrollLockOn, Active<b>::orthogonal< 2 ></b> > 1125{ 1126 typedef sc::transition< 1127 EvScrollLockPressed, ScrollLockOff > reactions; 1128}; 1129 1130struct ScrollLockOff : sc::simple_state< 1131 ScrollLockOff, Active<b>::orthogonal< 2 ></b> > 1132{ 1133 typedef sc::transition< 1134 EvScrollLockPressed, ScrollLockOn > reactions; 1135}; 1136</pre> 1137 1138 <p><code>orthogonal< 0 ></code> is the default, so 1139 <code>NumLockOn</code> and <code>NumLockOff</code> could just as well pass 1140 <code>Active</code> instead of <code>Active::orthogonal< 0 ></code> 1141 to specify their context. The numbers passed to the <code>orthogonal</code> 1142 member template must correspond to the list position in the outer state. 1143 Moreover, the orthogonal position of the source state of a transition must 1144 correspond to the orthogonal position of the target state. Any violations 1145 of these rules lead to compile time errors. Examples:</p> 1146 <pre> 1147// Example 1: does not compile because Active specifies 1148// only 3 orthogonal regions 1149struct WhateverLockOn: sc::simple_state< 1150 WhateverLockOn, Active<b>::</b>orthogonal< <b>3</b> > > {}; 1151 1152// Example 2: does not compile because Active specifies 1153// that NumLockOff is part of the "0th" orthogonal region 1154struct NumLockOff : sc::simple_state< 1155 NumLockOff, Active<b>::</b>orthogonal< <b>1</b> > > {}; 1156 1157// Example 3: does not compile because a transition between 1158// different orthogonal regions is not permitted 1159struct CapsLockOn : sc::simple_state< 1160 CapsLockOn, Active<b>::</b>orthogonal< <b>1</b> > > 1161{ 1162 typedef sc::transition< 1163 EvCapsLockPressed, CapsLockOff > reactions; 1164}; 1165 1166struct CapsLockOff : sc::simple_state< 1167 CapsLockOff, Active<b>::</b>orthogonal< <b>2</b> > > 1168{ 1169 typedef sc::transition< 1170 EvCapsLockPressed, CapsLockOn > reactions; 1171}; 1172</pre> 1173 1174 <h3><a name="StateQueries" id="StateQueries">State queries</a></h3> 1175 1176 <p>Often reactions in a state machine depend on the active state in one or 1177 more orthogonal regions. This is because orthogonal regions are not 1178 completely orthogonal or a certain reaction in an outer state can only take 1179 place if the inner orthogonal regions are in particular states. For this 1180 purpose, the <code>state_cast<></code> function introduced under 1181 <a href="#GettingStateInformationOutOfTheMachine">Getting state information 1182 out of the machine</a> is also available within states.</p> 1183 1184 <p>As a somewhat far-fetched example, let's assume that our <a href= 1185 "#OrthogonalStates">keyboard</a> also accepts 1186 <code>EvRequestShutdown</code> events, the reception of which makes the 1187 keyboard terminate only if all lock keys are in the off state. We would 1188 then modify the Keyboard state machine as follows:</p> 1189 <pre> 1190struct EvRequestShutdown : sc::event< EvRequestShutdown > {}; 1191 1192struct NumLockOff; 1193struct CapsLockOff; 1194struct ScrollLockOff; 1195struct Active: sc::simple_state< Active, Keyboard, 1196 mpl::list< NumLockOff, CapsLockOff, ScrollLockOff > > 1197{ 1198 typedef sc::custom_reaction< EvRequestShutdown > reactions; 1199 1200 sc::result react( const EvRequestShutdown & ) 1201 { 1202 if ( ( state_downcast< const NumLockOff * >() != 0 ) && 1203 ( state_downcast< const CapsLockOff * >() != 0 ) && 1204 ( state_downcast< const ScrollLockOff * >() != 0 ) ) 1205 { 1206 return terminate(); 1207 } 1208 else 1209 { 1210 return discard_event(); 1211 } 1212 } 1213}; 1214</pre> 1215 1216 <p>Passing a pointer type instead of reference type results in 0 pointers 1217 being returned instead of <code>std::bad_cast</code> being thrown when the 1218 cast fails. Note also the use of <code>state_downcast<>()</code> 1219 instead of <code>state_cast<>()</code>. Similar to the differences 1220 between <code>boost::polymorphic_downcast<>()</code> and 1221 <code>dynamic_cast</code>, <code>state_downcast<>()</code> is a much 1222 faster variant of <code>state_cast<>()</code> and can only be used 1223 when the passed type is a most-derived type. 1224 <code>state_cast<>()</code> should only be used if you want to query 1225 an additional base.</p> 1226 1227 <h4>Custom state queries</h4> 1228 1229 <p>It is often desirable to find out exactly which state(s) a machine 1230 currently resides in. To some extent this is already possible with 1231 <code>state_cast<>()</code> and <code>state_downcast<>()</code> 1232 but their utility is rather limited because both only return a yes/no 1233 answer to the question "Are you in state X?". It is possible to ask more 1234 sophisticated questions when you pass an additional base class rather than 1235 a state class to <code>state_cast<>()</code> but this involves more 1236 work (all states need to derive from and implement the additional base), is 1237 slow (under the hood <code>state_cast<>()</code> uses 1238 <code>dynamic_cast</code>), forces projects to compile with C++ RTTI turned 1239 on and has a negative impact on state entry/exit speed.</p> 1240 1241 <p>Especially for debugging it would be so much more useful being able to 1242 ask "In which state(s) are you?". For this purpose it is possible to 1243 iterate over all active <b>innermost</b> states with 1244 <code>state_machine<>::state_begin()</code> and 1245 <code>state_machine<>::state_end()</code>. Dereferencing the returned 1246 iterator returns a reference to <code>const 1247 state_machine<>::state_base_type</code>, the common base of all 1248 states. We can thus print the currently active state configuration as 1249 follows (see the Keyboard example for the complete code):</p> 1250 <pre> 1251void DisplayStateConfiguration( const Keyboard & kbd ) 1252{ 1253 char region = 'a'; 1254 1255 for ( 1256 Keyboard::state_iterator pLeafState = kbd.state_begin(); 1257 pLeafState != kbd.state_end(); ++pLeafState ) 1258 { 1259 std::cout << "Orthogonal region " << region << ": "; 1260 // The following use of typeid assumes that 1261 // BOOST_STATECHART_USE_NATIVE_RTTI is defined 1262 std::cout << typeid( *pLeafState ).name() << "\n"; 1263 ++region; 1264 } 1265} 1266</pre> 1267 1268 <p>If necessary, the outer states can be accessed with 1269 <code>state_machine<>::state_base_type::outer_state_ptr()</code>, 1270 which returns a pointer to <code>const 1271 state_machine<>::state_base_type</code>. When called on an outermost 1272 state this function simply returns 0.</p> 1273 1274 <h3><a name="StateTypeInformation" id="StateTypeInformation">State type 1275 information</a></h3> 1276 1277 <p>To cut down on executable size some applications must be compiled with 1278 C++ RTTI turned off. This would render the ability to iterate over all 1279 active states pretty much useless if it weren't for the following two 1280 functions:</p> 1281 1282 <ul> 1283 <li><code>static <i>unspecified_type</i> 1284 simple_state<>::static_type()</code></li> 1285 1286 <li><code><i>unspecified_type<br></i> 1287 state_machine<>::state_base_type::dynamic_type() const</code></li> 1288 </ul> 1289 1290 <p>Both return a value that is comparable via <code>operator==()</code> and 1291 <code>std::less<></code>. This alone would be enough to implement the 1292 <code>DisplayStateConfiguration</code> function above without the help of 1293 <code>typeid</code> but it is still somewhat cumbersome as a map must be 1294 used to associate the type information values with the state names.</p> 1295 1296 <h4><a name="CustomStateTypeInformation" id= 1297 "CustomStateTypeInformation">Custom state type information</a></h4> 1298 1299 <p>That's why the following functions are also provided (only available 1300 when <a href= 1301 "configuration.html#ApplicationDefinedMacros">BOOST_STATECHART_USE_NATIVE_RTTI</a> 1302 is <b>not</b> defined):</p> 1303 1304 <ul> 1305 <li><code>template< class T ><br> 1306 static void simple_state<>::custom_static_type_ptr( const T * 1307 );</code></li> 1308 1309 <li><code>template< class T ><br> 1310 static const T * 1311 simple_state<>::custom_static_type_ptr();</code></li> 1312 1313 <li><code>template< class T ><br> 1314 const T * state_machine<>::<br> 1315 state_base_type::custom_dynamic_type_ptr() const;</code></li> 1316 </ul> 1317 1318 <p>These allow us to directly associate arbitrary state type information 1319 with each state ...</p> 1320 <pre> 1321// ... 1322 1323int main() 1324{ 1325 NumLockOn::custom_static_type_ptr( "NumLockOn" ); 1326 NumLockOff::custom_static_type_ptr( "NumLockOff" ); 1327 CapsLockOn::custom_static_type_ptr( "CapsLockOn" ); 1328 CapsLockOff::custom_static_type_ptr( "CapsLockOff" ); 1329 ScrollLockOn::custom_static_type_ptr( "ScrollLockOn" ); 1330 ScrollLockOff::custom_static_type_ptr( "ScrollLockOff" ); 1331 1332 // ... 1333} 1334</pre> 1335 1336 <p>... and rewrite the display function as follows:</p> 1337 <pre> 1338void DisplayStateConfiguration( const Keyboard & kbd ) 1339{ 1340 char region = 'a'; 1341 1342 for ( 1343 Keyboard::state_iterator pLeafState = kbd.state_begin(); 1344 pLeafState != kbd.state_end(); ++pLeafState ) 1345 { 1346 std::cout << "Orthogonal region " << region << ": "; 1347 std::cout << 1348 pLeafState->custom_dynamic_type_ptr< char >() << "\n"; 1349 ++region; 1350 } 1351} 1352</pre> 1353 1354 <h3><a name="ExceptionHandling" id="ExceptionHandling">Exception 1355 handling</a></h3> 1356 1357 <p>Exceptions can be propagated from all user code except from state 1358 destructors. Out of the box, the state machine framework is configured for 1359 simple exception handling and does not catch any of these exceptions, so 1360 they are immediately propagated to the state machine client. A scope guard 1361 inside the <code>state_machine<></code> ensures that all state 1362 objects are destructed before the exception is caught by the client. The 1363 scope guard does not attempt to call any <code>exit</code> functions (see 1364 <a href="#TwoStageExit">Two stage exit</a> below) that states might define 1365 as these could themselves throw other exceptions which would mask the 1366 original exception. Consequently, if a state machine should do something 1367 more sensible when exceptions are thrown, it has to catch them before they 1368 are propagated into the Boost.Statechart framework. This exception handling 1369 scheme is often appropriate but it can lead to considerable code 1370 duplication in state machines where many actions can trigger exceptions 1371 that need to be handled inside the state machine (see <a href= 1372 "rationale.html#ErrorHandling">Error handling</a> in the Rationale).<br> 1373 That's why exception handling can be customized through the 1374 <code>ExceptionTranslator</code> parameter of the 1375 <code>state_machine</code> class template. Since the out-of-the box 1376 behavior is to <b>not</b> translate any exceptions, the default argument 1377 for this parameter is <code>null_exception_translator</code>. A 1378 <code>state_machine<></code> subtype can be configured for advanced 1379 exception handling by specifying the library-supplied 1380 <code>exception_translator<></code> instead. This way, the following 1381 happens when an exception is propagated from user code:</p> 1382 1383 <ol> 1384 <li>The exception is caught inside the framework</li> 1385 1386 <li>In the catch block, an <code>exception_thrown</code> event is 1387 allocated on the stack</li> 1388 1389 <li>Also in the catch block, an <b>immediate</b> dispatch of the 1390 <code>exception_thrown</code> event is attempted. That is, possibly 1391 remaining events in the queue are dispatched only after the exception has 1392 been handled successfully</li> 1393 1394 <li>If the exception was handled successfully, the state machine returns 1395 to the client normally. If the exception could not be handled 1396 successfully, the original exception is rethrown so that the client of 1397 the state machine can handle the exception</li> 1398 </ol> 1399 1400 <p>On platforms with buggy exception handling implementations users would 1401 probably want to implement their own model of the <a href= 1402 "reference.html#ExceptionTranslator">ExceptionTranslator concept</a> (see 1403 also <a href="#DiscriminatingExceptions">Discriminating 1404 exceptions</a>).</p> 1405 1406 <h4>Successful exception handling</h4> 1407 1408 <p>An exception is considered handled successfully, if:</p> 1409 1410 <ul> 1411 <li>an appropriate reaction for the <code>exception_thrown</code> event 1412 has been found, <b>and</b></li> 1413 1414 <li>the state machine is in a stable state after the reaction has 1415 completed.</li> 1416 </ul> 1417 1418 <p>The second condition is important for scenarios 2 and 3 in the next 1419 section. In these scenarios, the state machine is in the middle of a 1420 transition when the exception is handled. The machine would be left in an 1421 invalid state, should the reaction simply discard the event without doing 1422 anything else. <code>exception_translator<></code> simply rethrows 1423 the original exception if the exception handling was unsuccessful. Just as 1424 with simple exception handling, in this case a scope guard inside the 1425 <code>state_machine<></code> ensures that all state objects are 1426 destructed before the exception is caught by the client.</p> 1427 1428 <h4>Which states can react to an <code>exception_thrown</code> event?</h4> 1429 1430 <p>Short answer: If the state machine is stable when the exception is 1431 thrown, the state that caused the exception is first tried for a reaction. 1432 Otherwise the outermost <a href="definitions.html#UnstableState">unstable 1433 state</a> is first tried for a reaction.</p> 1434 1435 <p>Longer answer: There are three scenarios:</p> 1436 1437 <ol> 1438 <li>A <code>react</code> member function propagates an exception 1439 <b>before</b> calling any of the reaction functions or the action 1440 executed during an in-state reaction propagates an exception. The state 1441 that caused the exception is first tried for a reaction, so the following 1442 machine will transit to Defective after receiving an EvStart event:<br> 1443 <br> 1444 <img alt="ThrowingInStateReaction" src="ThrowingInStateReaction.gif" 1445 border="0" width="362" height="182"><br> 1446 <br></li> 1447 1448 <li>A state entry action (constructor) propagates an exception:<br> 1449 1450 <ul> 1451 <li>If there are no orthogonal regions, the direct outer state of the 1452 state that caused the exception is first tried for a reaction, so the 1453 following machine will transit to Defective after trying to enter 1454 Stopped:<br> 1455 <br> 1456 <img alt="ThrowingEntryAction" src="ThrowingEntryAction.gif" border= 1457 "0" width="438" height="241"><br></li> 1458 1459 <li>If there are orthogonal regions, the outermost <a href= 1460 "definitions.html#UnstableState">unstable state</a> is first tried 1461 for a reaction. The outermost unstable state is found by first 1462 selecting the direct outer state of the state that caused the 1463 exception and then moving outward until a state is found that is 1464 unstable but has no direct or indirect outer states that are 1465 unstable. This more complex rule is necessary because only reactions 1466 associated with the outermost unstable state (or any of its direct or 1467 indirect outer states) are able to bring the machine back into a 1468 stable state. Consider the following statechart:<br> 1469 <br> 1470 <img alt="OutermostUnstableState" src="OutermostUnstableState.gif" 1471 border="0" width="467" height="572"><br> 1472 <br> 1473 Whether this state machine will ultimately transition to E or F after 1474 initiation depends on which of the two orthogonal regions is 1475 initiated first. If the upper orthogonal region is initiated first, 1476 the entry sequence is as follows: A, D, B, (exception is thrown). 1477 Both D and B were successfully entered, so B is the outermost 1478 unstable state when the exception is thrown and the machine will 1479 therefore transition to F. However, if the lower orthogonal region is 1480 initiated first, the sequence is as follows: A, B, (exception is 1481 thrown). D was never entered so A is the outermost unstable state 1482 when the exception is thrown and the machine will therefore 1483 transition to E.<br> 1484 In practice these differences rarely matter as top-level error 1485 recovery is adequate for most state machines. However, since the 1486 sequence of initiation is clearly defined (orthogonal region 0 is 1487 always initiated first, then region 1 and so forth), users <b>can</b> 1488 accurately control when and where they want to handle 1489 exceptions<br></li> 1490 </ul> 1491 </li> 1492 1493 <li>A transition action propagates an exception: The innermost common 1494 outer state of the source and the target state is first tried for a 1495 reaction, so the following machine will transit to Defective after 1496 receiving an EvStartStop event:<br> 1497 <br> 1498 <img alt="ThrowingTransitionAction" src="ThrowingTransitionAction.gif" 1499 border="0" width="422" height="362"></li> 1500 </ol> 1501 1502 <p>As with a normal event, the dispatch algorithm will move outward to find 1503 a reaction if the first tried state does not provide one (or if the 1504 reaction explicitly returned <code>forward_event();</code>). However, <b>in 1505 contrast to normal events, it will give up once it has unsuccessfully tried 1506 an outermost state</b>, so the following machine will <b>not</b> transit to 1507 Defective after receiving an EvNumLockPressed event:</p> 1508 1509 <p><img alt="ExceptionsAndOrthStates" src="ExceptionsAndOrthStates.gif" 1510 border="0" width="571" height="331"></p> 1511 1512 <p>Instead, the machine is terminated and the original exception 1513 rethrown.</p> 1514 1515 <h4><a name="DiscriminatingExceptions" id= 1516 "DiscriminatingExceptions">Discriminating exceptions</a></h4> 1517 1518 <p>Because the <code>exception_thrown</code> event is dispatched from 1519 within the catch block, we can rethrow and catch the exception in a custom 1520 reaction:</p> 1521 <pre> 1522struct Defective : sc::simple_state< 1523 Defective, Purifier > {}; 1524 1525// Pretend this is a state deeply nested in the Purifier 1526// state machine 1527struct Idle : sc::simple_state< Idle, Purifier > 1528{ 1529 typedef mpl::list< 1530 sc::custom_reaction< EvStart >, 1531 sc::custom_reaction< sc::exception_thrown > 1532 > reactions; 1533 1534 sc::result react( const EvStart & ) 1535 { 1536 throw std::runtime_error( "" ); 1537 } 1538 1539 sc::result react( const sc::exception_thrown & ) 1540 { 1541 try 1542 { 1543 <b>throw;</b> 1544 } 1545 catch ( const std::runtime_error & ) 1546 { 1547 // only std::runtime_errors will lead to a transition 1548 // to Defective ... 1549 return transit< Defective >(); 1550 } 1551 catch ( ... ) 1552 { 1553 // ... all other exceptions are forwarded to our outer 1554 // state(s). The state machine is terminated and the 1555 // exception rethrown if the outer state(s) can't 1556 // handle it either... 1557 return forward_event(); 1558 } 1559 1560 // Alternatively, if we want to terminate the machine 1561 // immediately, we can also either rethrow or throw 1562 // a different exception. 1563 } 1564}; 1565</pre> 1566 1567 <p><b>Unfortunately, this idiom (using <code>throw;</code> inside a 1568 <code>try</code> block nested inside a <code>catch</code> block) does not 1569 work on at least one very popular compiler.</b> If you have to use one of 1570 these platforms, you can pass a customized exception translator class to 1571 the <code>state_machine</code> class template. This will allow you to 1572 generate different events depending on the type of the exception.</p> 1573 1574 <h4><a name="TwoStageExit" id="TwoStageExit">Two stage exit</a></h4> 1575 1576 <p>If a <code>simple_state<></code> or <code>state<></code> 1577 subtype declares a public member function with the signature <code>void 1578 exit()</code> then this function is called just before the state object is 1579 destructed. As explained under <a href="rationale.html#ErrorHandling">Error 1580 handling</a> in the Rationale, this is useful for two things that would 1581 otherwise be difficult or cumbersome to achieve with destructors only:</p> 1582 1583 <ol> 1584 <li>To signal a failure in an exit action</li> 1585 1586 <li>To execute certain exit actions <b>only</b> during a transition or a 1587 termination but not when the state machine object is destructed</li> 1588 </ol> 1589 1590 <p>A few points to consider before employing <code>exit()</code>:</p> 1591 1592 <ul> 1593 <li>There is no guarantee that <code>exit()</code> will be called: 1594 1595 <ul> 1596 <li>If the client destructs the state machine object without calling 1597 <code>terminate()</code> beforehand then the currently active states 1598 are destructed without calling <code>exit()</code>. This is necessary 1599 because an exception that is possibly thrown from <code>exit()</code> 1600 could not be propagated on to the state machine client</li> 1601 1602 <li><code>exit()</code> is not called when a previously executed 1603 action propagated an exception and that exception has not (yet) been 1604 handled successfully. This is because a new exception that could 1605 possibly be thrown from <code>exit()</code> would mask the original 1606 exception</li> 1607 </ul> 1608 </li> 1609 1610 <li>A state is considered exited, even if its <code>exit</code> function 1611 propagated an exception. That is, the state object is inevitably 1612 destructed right after calling <code>exit()</code>, regardless of whether 1613 <code>exit()</code> propagated an exception or not. A state machine 1614 configured for advanced exception handling is therefore always unstable 1615 while handling an exception propagated from an <code>exit</code> 1616 function</li> 1617 1618 <li>In a state machine configured for advanced exception handling the 1619 processing rules for an exception event resulting from an exception 1620 propagated from <code>exit()</code> are analogous to the ones defined for 1621 exceptions propagated from state constructors. That is, the outermost 1622 unstable state is first tried for a reaction and the dispatcher then 1623 moves outward until an appropriate reaction is found</li> 1624 </ul> 1625 1626 <h3><a name="SubmachinesAndParameterizedStates" id= 1627 "SubmachinesAndParameterizedStates">Submachines & parameterized 1628 states</a></h3> 1629 1630 <p>Submachines are to event-driven programming what functions are to 1631 procedural programming, reusable building blocks implementing often needed 1632 functionality. The associated UML notation is not entirely clear to me. It 1633 seems to be severely limited (e.g. the same submachine cannot appear in 1634 different orthogonal regions) and does not seem to account for obvious 1635 stuff like e.g. parameters.</p> 1636 1637 <p>Boost.Statechart is completely unaware of submachines but they can be 1638 implemented quite nicely with templates. Here, a submachine is used to 1639 improve the copy-paste implementation of the keyboard machine discussed 1640 under <a href="#OrthogonalStates">Orthogonal states</a>:</p> 1641 <pre> 1642enum LockType 1643{ 1644 NUM_LOCK, 1645 CAPS_LOCK, 1646 SCROLL_LOCK 1647}; 1648 1649template< LockType lockType > 1650struct Off; 1651struct Active : sc::simple_state< 1652 Active, Keyboard, mpl::list< 1653 Off< NUM_LOCK >, Off< CAPS_LOCK >, Off< SCROLL_LOCK > > > {}; 1654 1655template< LockType lockType > 1656struct EvPressed : sc::event< EvPressed< lockType > > {}; 1657 1658template< LockType lockType > 1659struct On : sc::simple_state< 1660 On< lockType >, Active::orthogonal< lockType > > 1661{ 1662 typedef sc::transition< 1663 EvPressed< lockType >, Off< lockType > > reactions; 1664}; 1665 1666template< LockType lockType > 1667struct Off : sc::simple_state< 1668 Off< lockType >, Active::orthogonal< lockType > > 1669{ 1670 typedef sc::transition< 1671 EvPressed< lockType >, On< lockType > > reactions; 1672}; 1673</pre> 1674 1675 <h3><a name="AsynchronousStateMachines" id= 1676 "AsynchronousStateMachines">Asynchronous state machines</a></h3> 1677 1678 <h4>Why asynchronous state machines are necessary</h4> 1679 1680 <p>As the name suggests, a synchronous state machine processes each event 1681 synchronously. This behavior is implemented by the 1682 <code>state_machine</code> class template, whose <code>process_event</code> 1683 function only returns after having executed all reactions (including the 1684 ones provoked by internal events that actions might have posted). This 1685 function is strictly non-reentrant (just like all other member functions, 1686 so <code>state_machine<></code> is not thread-safe). This makes it 1687 difficult for two <code>state_machine<></code> subtype objects to 1688 communicate via events in a bi-directional fashion correctly, <b>even in a 1689 single-threaded program</b>. For example, state machine <code>A</code> is 1690 in the middle of processing an external event. Inside an action, it decides 1691 to send a new event to state machine <code>B</code> (by calling 1692 <code>B::process_event()</code>). It then "waits" for B to send back an 1693 answer via a <code>boost::function<></code>-like call-back, which 1694 references <code>A::process_event()</code> and was passed as a data member 1695 of the event. However, while <code>A</code> is "waiting" for <code>B</code> 1696 to send back an event, <code>A::process_event()</code> has not yet returned 1697 from processing the external event and as soon as <code>B</code> answers 1698 via the call-back, <code>A::process_event()</code> is <b>unavoidably</b> 1699 reentered. This all really happens in a single thread, that's why "wait" is 1700 in quotes.</p> 1701 1702 <h4>How it works</h4> 1703 1704 <p>The <code>asynchronous_state_machine</code> class template has none of 1705 the member functions the <code>state_machine</code> class template has. 1706 Moreover, <code>asynchronous_state_machine<></code> subtype objects 1707 cannot even be created or destroyed directly. Instead, all these operations 1708 must be performed through the <code>Scheduler</code> object each 1709 asynchronous state machine is associated with. All these 1710 <code>Scheduler</code> member functions only push an appropriate item into 1711 the schedulers' queue and then return immediately. A dedicated thread will 1712 later pop the items out of the queue to have them processed.</p> 1713 1714 <p>Applications will usually first create a 1715 <code>fifo_scheduler<></code> object and then call 1716 <code>fifo_scheduler<>::create_processor<>()</code> and 1717 <code>fifo_scheduler<>::initiate_processor()</code> to schedule the 1718 creation and initiation of one or more 1719 <code>asynchronous_state_machine<></code> subtype objects. Finally, 1720 <code>fifo_scheduler<>::operator()()</code> is either called directly 1721 to let the machine(s) run in the current thread, or, a 1722 <code>boost::function<></code> object referencing 1723 <code>operator()()</code> is passed to a new <code>boost::thread</code>. 1724 Alternatively, the latter could also be done right after constructing the 1725 <code>fifo_scheduler<></code> object. In the following code, we are 1726 running one state machine in a new <code>boost::thread</code> and the other 1727 in the main thread (see the PingPong example for the full source code):</p> 1728 <pre> 1729struct Waiting; 1730struct Player : 1731 sc::asynchronous_state_machine< Player, Waiting > 1732{ 1733 // ... 1734}; 1735 1736// ... 1737 1738int main() 1739{ 1740 // Create two schedulers that will wait for new events 1741 // when their event queue runs empty 1742 sc::fifo_scheduler<> scheduler1( true ); 1743 sc::fifo_scheduler<> scheduler2( true ); 1744 1745 // Each player is serviced by its own scheduler 1746 sc::fifo_scheduler<>::processor_handle player1 = 1747 scheduler1.create_processor< Player >( /* ... */ ); 1748 scheduler1.initiate_processor( player1 ); 1749 sc::fifo_scheduler<>::processor_handle player2 = 1750 scheduler2.create_processor< Player >( /* ... */ ); 1751 scheduler2.initiate_processor( player2 ); 1752 1753 // the initial event that will start the game 1754 boost::intrusive_ptr< BallReturned > pInitialBall = 1755 new BallReturned(); 1756 1757 // ... 1758 1759 scheduler2.queue_event( player2, pInitialBall ); 1760 1761 // ... 1762 1763 // Up until here no state machines exist yet. They 1764 // will be created when operator()() is called 1765 1766 // Run first scheduler in a new thread 1767 boost::thread otherThread( boost::bind( 1768 &sc::fifo_scheduler<>::operator(), &scheduler1, 0 ) ); 1769 scheduler2(); // Run second scheduler in this thread 1770 otherThread.join(); 1771 1772 return 0; 1773} 1774</pre> 1775 1776 <p>We could just as well use two boost::threads:</p> 1777 <pre> 1778int main() 1779{ 1780 // ... 1781 1782 boost::thread thread1( boost::bind( 1783 &sc::fifo_scheduler<>::operator(), &scheduler1, 0 ) ); 1784 boost::thread thread2( boost::bind( 1785 &sc::fifo_scheduler<>::operator(), &scheduler2, 0 ) ); 1786 1787 // do something else ... 1788 1789 thread1.join(); 1790 thread2.join(); 1791 1792 return 0; 1793} 1794</pre> 1795 1796 <p>Or, run both machines in the same thread:</p> 1797 <pre> 1798int main() 1799{ 1800 sc::fifo_scheduler<> scheduler1( true ); 1801 1802 sc::fifo_scheduler<>::processor_handle player1 = 1803 scheduler1.create_processor< Player >( /* ... */ ); 1804 sc::fifo_scheduler<>::processor_handle player2 = 1805 scheduler1.create_processor< Player >( /* ... */ ); 1806 1807 // ... 1808 1809 scheduler1(); 1810 1811 return 0; 1812} 1813</pre> 1814 1815 <p>In all the examples above, 1816 <code>fifo_scheduler<>::operator()()</code> waits on an empty event 1817 queue and will only return after a call to 1818 <code>fifo_scheduler<>::terminate()</code>. The <code>Player</code> 1819 state machine calls this function on its scheduler object right before 1820 terminating.</p> 1821 <hr> 1822 1823 <p><a href="http://validator.w3.org/check?uri=referer"><img border="0" src= 1824 "../../../doc/images/valid-html401.png" alt="Valid HTML 4.01 Transitional" 1825 height="31" width="88"></a></p> 1826 1827 <p>Revised 1828 <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B, %Y" startspan -->03 December, 2006<!--webbot bot="Timestamp" endspan i-checksum="38512" --></p> 1829 1830 <p><i>Copyright © 2003-<!--webbot bot="Timestamp" s-type="EDITED" s-format="%Y" startspan -->2006<!--webbot bot="Timestamp" endspan i-checksum="770" --> 1831 <a href="contact.html">Andreas Huber Dönni</a></i></p> 1832 1833 <p><i>Distributed under the Boost Software License, Version 1.0. (See 1834 accompanying file <a href="../../../LICENSE_1_0.txt">LICENSE_1_0.txt</a> or 1835 copy at <a href= 1836 "http://www.boost.org/LICENSE_1_0.txt">http://www.boost.org/LICENSE_1_0.txt</a>)</i></p> 1837</body> 1838</html> 1839