tutorial.html 68 KB

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