rationale.html 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616
  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 - Rationale</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">Rationale</h2>
  22. </td>
  23. </tr>
  24. </table>
  25. <hr>
  26. <dl class="index">
  27. <dt><a href="#Introduction">Introduction</a></dt>
  28. <dt><a href="#WhyYetAnotherStateMachineFramework">Why yet another state
  29. machine framework</a></dt>
  30. <dt><a href="#StateLocalStorage">State-local storage</a></dt>
  31. <dt><a href="#DynamicConfigurability">Dynamic configurability</a></dt>
  32. <dt><a href="#ErrorHandling">Error handling</a></dt>
  33. <dt><a href="#AsynchronousStateMachines">Asynchronous state
  34. machines</a></dt>
  35. <dt><a href="#MemberFunctionsVsFunctionObjects">User actions: Member
  36. functions vs. function objects</a></dt>
  37. <dt><a href="#Limitations">Limitations</a></dt>
  38. </dl>
  39. <h2><a name="Introduction" id="Introduction">Introduction</a></h2>
  40. <p>Most of the design decisions made during the development of this library
  41. are the result of the following requirements.</p>
  42. <p>Boost.Statechart should ...</p>
  43. <ol>
  44. <li>be fully type-safe. Whenever possible, type mismatches should be
  45. flagged with an error at compile-time</li>
  46. <li>not require the use of a code generator. A lot of the existing FSM
  47. solutions force the developer to design the state machine either
  48. graphically or in a specialized language. All or part of the code is then
  49. generated</li>
  50. <li>allow for easy transformation of a UML statechart (defined in
  51. <a href="http://www.omg.org/cgi-bin/doc?formal/03-03-01">http://www.omg.org/cgi-bin/doc?formal/03-03-01</a>)
  52. into a working state machine. Vice versa, an existing C++
  53. implementation of a state machine should be fairly trivial to transform
  54. into a UML statechart. Specifically, the following state machine
  55. features should be supported:
  56. <ul>
  57. <li>Hierarchical (composite, nested) states</li>
  58. <li>Orthogonal (concurrent) states</li>
  59. <li>Entry-, exit- and transition-actions</li>
  60. <li>Guards</li>
  61. <li>Shallow/deep history</li>
  62. </ul>
  63. </li>
  64. <li>produce a customizable reaction when a C++ exception is propagated
  65. from user code</li>
  66. <li>support synchronous and asynchronous state machines and leave it to
  67. the user which thread an asynchronous state machine will run in. Users
  68. should also be able to use the threading library of their choice</li>
  69. <li>support the development of arbitrarily large and complex state
  70. machines. Multiple developers should be able to work on the same state
  71. machine simultaneously</li>
  72. <li>allow the user to customize all resource management so that the
  73. library could be used for applications with hard real-time
  74. requirements</li>
  75. <li>enforce as much as possible at compile time. Specifically, invalid
  76. state machines should not compile</li>
  77. <li>offer reasonable performance for a wide range of applications</li>
  78. </ol>
  79. <h2><a name="WhyYetAnotherStateMachineFramework" id=
  80. "WhyYetAnotherStateMachineFramework">Why yet another state machine
  81. framework?</a></h2>
  82. <p>Before I started to develop this library I had a look at the following
  83. frameworks:</p>
  84. <ul>
  85. <li>The framework accompanying the book "Practical Statecharts in C/C++"
  86. by Miro Samek, CMP Books, ISBN: 1-57820-110-1<br>
  87. <a href=
  88. "http://www.quantum-leaps.com">http://www.quantum-leaps.com<br></a> Fails
  89. to satisfy at least the requirements 1, 3, 4, 6, 8.</li>
  90. <li>The framework accompanying "Rhapsody in C++" by ILogix (a code
  91. generator solution)<br>
  92. <a href=
  93. "http://www.ilogix.com/sublevel.aspx?id=53">http://www.ilogix.com/sublevel.aspx?id=53<br>
  94. </a> This might look like comparing apples with oranges. However, there
  95. is no inherent reason why a code generator couldn't produce code that can
  96. easily be understood and modified by humans. Fails to satisfy at least
  97. the requirements 2, 4, 5, 6, 8 (there is quite a bit of error checking
  98. before code generation, though).</li>
  99. <li>The framework accompanying the article "State Machine Design in
  100. C++"<br>
  101. <a href=
  102. "http://www.ddj.com/184401236?pgno=1">http://www.ddj.com/184401236?pgno=1<br>
  103. </a> Fails to satisfy at least the requirements 1, 3, 4, 5 (there is no
  104. direct threading support), 6, 8.</li>
  105. </ul>
  106. <p>I believe Boost.Statechart satisfies all requirements.</p>
  107. <h2><a name="StateLocalStorage" id="StateLocalStorage">State-local
  108. storage</a></h2>
  109. <p>This not yet widely known state machine feature is enabled by the fact
  110. that every state is represented by a class. Upon state-entry, an object of
  111. the class is constructed and the object is later destructed when the state
  112. machine exits the state. Any data that is useful only as long as the
  113. machine resides in the state can (and should) thus be a member of the
  114. state. This feature paired with the ability to spread a state machine over
  115. several translation units makes possible virtually unlimited
  116. scalability.&nbsp;</p>
  117. <p>In most existing FSM frameworks the whole state machine runs in one
  118. environment (context). That is, all resource handles and variables local to
  119. the state machine are stored in one place (normally as members of the class
  120. that also derives from some state machine base class). For large state
  121. machines this often leads to the class having a huge number of data members
  122. most of which are needed only briefly in a tiny part of the machine. The
  123. state machine class therefore often becomes a change hotspot what leads to
  124. frequent recompilations of the whole state machine.</p>
  125. <p>The FAQ item "<a href="faq.html#StateLocalStorage">What's so cool about
  126. state-local storage?</a>" further explains this by comparing the tutorial
  127. StopWatch to a behaviorally equivalent version that does not use
  128. state-local storage.</p>
  129. <h2><a name="DynamicConfigurability" id="DynamicConfigurability">Dynamic
  130. configurability</a></h2>
  131. <h3>Two types of state machine frameworks</h3>
  132. <ul>
  133. <li>A state machine framework supports dynamic configurability if the
  134. whole layout of a state machine can be defined at runtime ("layout"
  135. refers to states and transitions, actions are still specified with normal
  136. C++ code). That is, data only available at runtime can be used to build
  137. arbitrarily large machines. See "<a href=
  138. "https://www.researchgate.net/publication/293741100_A_multiple_substring_search_algorithm">A
  139. Multiple Substring Search Algorithm</a>" by Moishe Halibard and Moshe Rubin
  140. in June 2002 issue of CUJ for a good example.
  141. <li>On the other side are state machine frameworks which require the
  142. layout to be specified at compile time</li>
  143. </ul>
  144. <p>State machines that are built at runtime almost always get away with a
  145. simple state model (no hierarchical states, no orthogonal states, no entry
  146. and exit actions, no history) because the layout is very often <b>computed
  147. by an algorithm</b>. On the other hand, machine layouts that are fixed at
  148. compile time are almost always designed by humans, who frequently need/want
  149. a sophisticated state model in order to keep the complexity at acceptable
  150. levels. Dynamically configurable FSM frameworks are therefore often
  151. optimized for simple flat machines while incarnations of the static variant
  152. tend to offer more features for abstraction.</p>
  153. <p>However, fully-featured dynamic FSM libraries do exist. So, the question
  154. is:</p>
  155. <h3>Why not use a dynamically configurable FSM library for all state
  156. machines?</h3>
  157. <p>One might argue that a dynamically configurable FSM framework is all one
  158. ever needs because <b>any</b> state machine can be implemented with it.
  159. However, due to its nature such a framework has a number of disadvantages
  160. when used to implement static machines:</p>
  161. <ul>
  162. <li>No compile-time optimizations and validations can be made. For
  163. example, Boost.Statechart determines the <a href=
  164. "definitions.html#InnermostCommonContext">innermost common context</a> of
  165. the transition-source and destination state at compile time. Moreover,
  166. compile time checks ensure that the state machine is valid (e.g. that
  167. there are no transitions between orthogonal states).</li>
  168. <li>Double dispatch must inevitably be implemented with some kind of a
  169. table. As argued under <a href="performance.html#DoubleDispatch">Double
  170. dispatch</a>, this scales badly.</li>
  171. <li>To warrant fast table lookup, states and events must be represented
  172. with an integer. To keep the table as small as possible, the numbering
  173. should be continuous, e.g. if there are ten states, it's best to use the
  174. ids 0-9. To ensure continuity of ids, all states are best defined in the
  175. same header file. The same applies to events. Again, this does not
  176. scale.</li>
  177. <li>Because events carrying parameters are not represented by a type,
  178. some sort of a generic event with a property map must be used and
  179. type-safety is enforced at runtime rather than at compile time.</li>
  180. </ul>
  181. <p>It is for these reasons, that Boost.Statechart was built from ground up
  182. to <b>not</b> support dynamic configurability. However, this does not mean
  183. that it's impossible to dynamically shape a machine implemented with this
  184. library. For example, guards can be used to make different transitions
  185. depending on input only available at runtime. However, such layout changes
  186. will always be limited to what can be foreseen before compilation. A
  187. somewhat related library, the boost::spirit parser framework, allows for
  188. roughly the same runtime configurability.</p>
  189. <h2><a name="ErrorHandling" id="ErrorHandling">Error handling</a></h2>
  190. <p>There is not a single word about error handling in the UML state machine
  191. semantics specifications. Moreover, most existing FSM solutions also seem
  192. to ignore the issue.&nbsp;</p>
  193. <h3>Why an FSM library should support error handling</h3>
  194. <p>Consider the following state configuration:</p>
  195. <p><img alt="A" src="A.gif" border="0" width="230" height="170"></p>
  196. <p>Both states define entry actions (x() and y()). Whenever state A becomes
  197. active, a call to x() will immediately be followed by a call to y(). y()
  198. could depend on the side-effects of x(). Therefore, executing y() does not
  199. make sense if x() fails. This is not an esoteric corner case but happens in
  200. every-day state machines all the time. For example, x() could acquire
  201. memory the contents of which is later modified by y(). There is a different
  202. but in terms of error handling equally critical situation in the Tutorial
  203. under <a href=
  204. "tutorial.html#GettingStateInformationOutOfTheMachine">Getting state
  205. information out of the machine</a> when <code>Running::~Running()</code>
  206. accesses its outer state <code>Active</code>. Had the entry action of
  207. <code>Active</code> failed and had <code>Running</code> been entered anyway
  208. then <code>Running</code>'s exit action would have invoked undefined
  209. behavior. The error handling situation with outer and inner states
  210. resembles the one with base and derived classes: If a base class
  211. constructor fails (by throwing an exception) the construction is aborted,
  212. the derived class constructor is not called and the object never comes to
  213. life.<br>
  214. In most traditional FSM frameworks such an error situation is relatively
  215. easy to tackle <b>as long as the error can be propagated to the state
  216. machine client</b>. In this case a failed action simply propagates a C++
  217. exception into the framework. The framework usually does not catch the
  218. exception so that the state machine client can handle it. Note that, after
  219. doing so, the client can no longer use the state machine object because it
  220. is either in an unknown state or the framework has already reset the state
  221. because of the exception (e.g. with a scope guard). That is, by their
  222. nature, state machines typically only offer basic exception safety.<br>
  223. However, error handling with traditional FSM frameworks becomes
  224. surprisingly cumbersome as soon as a lot of actions can fail and the state
  225. machine <b>itself</b> needs to gracefully handle these errors. Usually, a
  226. failing action (e.g. x()) then posts an appropriate error event and sets a
  227. global error variable to true. Every following action (e.g. y()) first has
  228. to check the error variable before doing anything. After all actions have
  229. completed (by doing nothing!), the previously posted error event has to be
  230. processed what leads to the execution of the remedy action. Please note
  231. that it is not sufficient to simply queue the error event as other events
  232. could still be pending. Instead, the error event has absolute priority and
  233. has to be dealt with immediately. There are slightly less cumbersome
  234. approaches to FSM error handling but these usually necessitate a change of
  235. the statechart layout and thus obscure the normal behavior. No matter what
  236. approach is used, programmers are normally forced to write a lot of code
  237. that deals with errors and most of that code is <b>not</b> devoted to error
  238. handling but to error propagation.</p>
  239. <h3>Error handling support in Boost.Statechart</h3>
  240. <p>C++ exceptions may be propagated from any action to signal a failure.
  241. Depending on how the state machine is configured, such an exception is
  242. either immediately propagated to the state machine client or caught and
  243. converted into a special event that is dispatched immediately. For more
  244. information see the <a href="tutorial.html#ExceptionHandling">Exception
  245. handling</a> chapter in the Tutorial.</p>
  246. <h3>Two stage exit</h3>
  247. <p>An exit action can be implemented by adding a destructor to a state. Due
  248. to the nature of destructors, there are two disadvantages to this
  249. approach:</p>
  250. <ul>
  251. <li>Since C++ destructors should virtually never throw, one cannot simply
  252. propagate an exception from an exit action as one does when any of the
  253. other actions fails</li>
  254. <li>When a <code>state_machine&lt;&gt;</code> object is destructed then
  255. all currently active states are inevitably also destructed. That is,
  256. state machine termination is tied to the destruction of the state machine
  257. object</li>
  258. </ul>
  259. <p>In my experience, neither of the above points is usually problem in
  260. practice since ...</p>
  261. <ul>
  262. <li>exit actions cannot often fail. If they can, such a failure is
  263. usually either
  264. <ul>
  265. <li>not of interest to the outside world, i.e. the failure can simply
  266. be ignored</li>
  267. <li>so severe, that the application needs to be terminated anyway. In
  268. such a situation stack unwind is almost never desirable and the
  269. failure is better signaled through other mechanisms (e.g.
  270. abort())</li>
  271. </ul>
  272. </li>
  273. <li>to clean up properly, often exit actions <b>must</b> be executed when
  274. a state machine object is destructed, even if it is destructed as a
  275. result of a stack unwind</li>
  276. </ul>
  277. <p>However, several people have put forward theoretical arguments and
  278. real-world scenarios, which show that the exit action to destructor mapping
  279. <b>can</b> be a problem and that workarounds are overly cumbersome. That's
  280. why <a href="tutorial.html#TwoStageExit">two stage exit</a> is now
  281. supported.</p>
  282. <h2><a name="AsynchronousStateMachines" id=
  283. "AsynchronousStateMachines">Asynchronous state machines</a></h2>
  284. <h3>Requirements</h3>
  285. <p>For asynchronous state machines different applications have rather
  286. varied requirements:</p>
  287. <ol>
  288. <li>In some applications each state machine needs to run in its own
  289. thread, other applications are single-threaded and run all machines in
  290. the same thread</li>
  291. <li>For some applications a FIFO scheduler is perfect, others need
  292. priority- or EDF-schedulers</li>
  293. <li>For some applications the boost::thread library is just fine, others
  294. might want to use another threading library, yet other applications run
  295. on OS-less platforms where ISRs are the only mode of (apparently)
  296. concurrent execution</li>
  297. </ol>
  298. <h3>Out of the box behavior</h3>
  299. <p>By default, <code>asynchronous_state_machine&lt;&gt;</code> subtype
  300. objects are serviced by a <code>fifo_scheduler&lt;&gt;</code> object.
  301. <code>fifo_scheduler&lt;&gt;</code> does not lock or wait in
  302. single-threaded applications and uses boost::thread primitives to do so in
  303. multi-threaded programs. Moreover, a <code>fifo_scheduler&lt;&gt;</code>
  304. object can service an arbitrary number of
  305. <code>asynchronous_state_machine&lt;&gt;</code> subtype objects. Under the
  306. hood, <code>fifo_scheduler&lt;&gt;</code> is just a thin wrapper around an
  307. object of its <code>FifoWorker</code> template parameter (which manages the
  308. queue and ensures thread safety) and a
  309. <code>processor_container&lt;&gt;</code> (which manages the lifetime of the
  310. state machines).</p>
  311. <p>The UML standard mandates that an event not triggering a reaction in a
  312. state machine should be silently discarded. Since a
  313. <code>fifo_scheduler&lt;&gt;</code> object is itself also a state machine,
  314. events destined to no longer existing
  315. <code>asynchronous_state_machine&lt;&gt;</code> subtype objects are also
  316. silently discarded. This is enabled by the fact that
  317. <code>asynchronous_state_machine&lt;&gt;</code> subtype objects cannot be
  318. constructed or destructed directly. Instead, this must be done through
  319. <code>fifo_scheduler&lt;&gt;::create_processor&lt;&gt;()</code> and
  320. <code>fifo_scheduler&lt;&gt;::destroy_processor()</code>
  321. (<code>processor</code> refers to the fact that
  322. <code>fifo_scheduler&lt;&gt;</code> can only host
  323. <code>event_processor&lt;&gt;</code> subtype objects;
  324. <code>asynchronous_state_machine&lt;&gt;</code> is just one way to
  325. implement such a processor). Moreover,
  326. <code>create_processor&lt;&gt;()</code> only returns a
  327. <code>processor_handle</code> object. This must henceforth be used to
  328. initiate, queue events for, terminate and destroy the state machine through
  329. the scheduler.</p>
  330. <h3>Customization</h3>
  331. <p>If a user needs to customize the scheduler behavior she can do so by
  332. instantiating <code>fifo_scheduler&lt;&gt;</code> with her own class
  333. modeling the <code>FifoWorker</code> concept. I considered a much more
  334. generic design where locking and waiting is implemented in a policy but I
  335. have so far failed to come up with a clean and simple interface for it.
  336. Especially the waiting is a bit difficult to model as some platforms have
  337. condition variables, others have events and yet others don't have any
  338. notion of waiting whatsoever (they instead loop until a new event arrives,
  339. presumably via an ISR). Given the relatively few lines of code required to
  340. implement a custom <code>FifoWorker</code> type and the fact that almost
  341. all applications will implement at most one such class, it does not seem to
  342. be worthwhile anyway. Applications requiring a less or more sophisticated
  343. event processor lifetime management can customize the behavior at a more
  344. coarse level, by using a custom <code>Scheduler</code> type. This is
  345. currently also true for applications requiring non-FIFO queuing schemes.
  346. However, Boost.Statechart will probably provide a
  347. <code>priority_scheduler</code> in the future so that custom schedulers
  348. need to be implemented only in rare cases.</p>
  349. <h2><a name="MemberFunctionsVsFunctionObjects" id=
  350. "MemberFunctionsVsFunctionObjects">User actions: Member functions vs.
  351. function objects</a></h2>
  352. <p>All user-supplied functions (<code>react</code> member functions,
  353. entry-, exit- and transition-actions) must be class members. The reasons
  354. for this are as follows:</p>
  355. <ul>
  356. <li>The concept of state-local storage mandates that state-entry and
  357. state-exit actions are implemented as members</li>
  358. <li><code>react</code> member functions and transition actions often
  359. access state-local data. So, it is most natural to implement these
  360. functions as members of the class the data of which the functions will
  361. operate on anyway</li>
  362. </ul>
  363. <h2><a name="Limitations" id="Limitations">Limitations</a></h2>
  364. <h4>Junction points</h4>
  365. <p>UML junction points are not supported because arbitrarily complex guard
  366. expressions can easily be implemented with
  367. <code>custom_reaction&lt;&gt;</code>s.</p>
  368. <h4>Dynamic choice points</h4>
  369. <p>Currently there is no direct support for this UML element because its
  370. behavior can often be implemented with
  371. <code>custom_reaction&lt;&gt;</code>s. In rare cases this is not possible,
  372. namely when a choice point happens to be the initial state. Then, the
  373. behavior can easily be implemented as follows:</p>
  374. <pre>
  375. struct make_choice : sc::event&lt; make_choice &gt; {};
  376. // universal choice point base class template
  377. template&lt; class MostDerived, class Context &gt;
  378. struct choice_point : sc::state&lt; MostDerived, Context &gt;
  379. {
  380. typedef sc::state&lt; MostDerived, Context &gt; base_type;
  381. typedef typename base_type::my_context my_context;
  382. typedef choice_point my_base;
  383. choice_point( my_context ctx ) : base_type( ctx )
  384. {
  385. this-&gt;post_event( boost::intrusive_ptr&lt; make_choice &gt;(
  386. new make_choice() ) );
  387. }
  388. };
  389. // ...
  390. struct MyChoicePoint;
  391. struct Machine : sc::state_machine&lt; Machine, MyChoicePoint &gt; {};
  392. struct Dest1 : sc::simple_state&lt; Dest1, Machine &gt; {};
  393. struct Dest2 : sc::simple_state&lt; Dest2, Machine &gt; {};
  394. struct Dest3 : sc::simple_state&lt; Dest3, Machine &gt; {};
  395. struct MyChoicePoint : choice_point&lt; MyChoicePoint, Machine &gt;
  396. {
  397. MyChoicePoint( my_context ctx ) : my_base( ctx ) {}
  398. sc::result react( const make_choice &amp; )
  399. {
  400. if ( /* ... */ )
  401. {
  402. return transit&lt; Dest1 &gt;();
  403. }
  404. else if ( /* ... */ )
  405. {
  406. return transit&lt; Dest2 &gt;();
  407. }
  408. else
  409. {
  410. return transit&lt; Dest3 &gt;();
  411. }
  412. }
  413. };
  414. </pre>
  415. <p><code>choice_point&lt;&gt;</code> is not currently part of
  416. Boost.Statechart, mainly because I fear that beginners could use it in
  417. places where they would be better off with
  418. <code>custom_reaction&lt;&gt;</code>. If the demand is high enough I will
  419. add it to the library.</p>
  420. <h4>Deep history of orthogonal regions</h4>
  421. <p>Deep history of states with orthogonal regions is currently not
  422. supported:</p>
  423. <p><img alt="DeepHistoryLimitation1" src="DeepHistoryLimitation1.gif"
  424. border="0" width="331" height="346"></p>
  425. <p>Attempts to implement this statechart will lead to a compile-time error
  426. because B has orthogonal regions and its direct or indirect outer state
  427. contains a deep history pseudo state. In other words, a state containing a
  428. deep history pseudo state must not have any direct or indirect inner states
  429. which themselves have orthogonal regions. This limitation stems from the
  430. fact that full deep history support would be more complicated to implement
  431. and would consume more resources than the currently implemented limited
  432. deep history support. Moreover, full deep history behavior can easily be
  433. implemented with shallow history:</p>
  434. <p><img alt="DeepHistoryLimitation2" src="DeepHistoryLimitation2.gif"
  435. border="0" width="332" height="347"></p>
  436. <p>Of course, this only works if C, D, E or any of their direct or indirect
  437. inner states do not have orthogonal regions. If not so then this pattern
  438. has to be applied recursively.</p>
  439. <h4>Synchronization (join and fork) bars</h4>
  440. <p><img alt="JoinAndFork" src="JoinAndFork.gif" border="0" width="541"
  441. height="301"></p>
  442. <p>Synchronization bars are not supported, that is, a transition always
  443. originates at exactly one state and always ends at exactly one state. Join
  444. bars are sometimes useful but their behavior can easily be emulated with
  445. guards. The support of fork bars would make the implementation <b>much</b>
  446. more complex and they are only needed rarely.</p>
  447. <h4>Event dispatch to orthogonal regions</h4>
  448. <p>The Boost.Statechart event dispatch algorithm is different to the one
  449. specified in <a href=
  450. "http://www.wisdom.weizmann.ac.il/~dharel/SCANNED.PAPERS/Statecharts.pdf">David
  451. Harel's original paper</a> and in the <a href=
  452. "http://www.omg.org/cgi-bin/doc?formal/03-03-01">UML standard</a>. Both
  453. mandate that each event is dispatched to all orthogonal regions of a state
  454. machine. Example:</p>
  455. <p><img alt="EventDispatch" src="EventDispatch.gif" border="0" width="436"
  456. height="211"></p>
  457. <p>Here the Harel/UML dispatch algorithm specifies that the machine must
  458. transition from (B,D) to (C,E) when an EvX event is processed. Because of
  459. the subtleties that Harel describes in chapter 7 of <a href=
  460. "http://www.wisdom.weizmann.ac.il/~dharel/SCANNED.PAPERS/Statecharts.pdf">his
  461. paper</a>, an implementation of this algorithm is not only quite complex
  462. but also much slower than the simplified version employed by
  463. Boost.Statechart, which stops searching for <a href=
  464. "definitions.html#Reaction">reactions</a> as soon as it has found one
  465. suitable for the current event. That is, had the example been implemented
  466. with this library, the machine would have transitioned
  467. non-deterministically from (B,D) to either (C,D) or (B,E). This version was
  468. chosen because, in my experience, in real-world machines different
  469. orthogonal regions often do not specify transitions for the same events.
  470. For the rare cases when they do, the UML behavior can easily be emulated as
  471. follows:</p>
  472. <p><img alt="SimpleEventDispatch" src="SimpleEventDispatch.gif" border="0"
  473. width="466" height="226"></p>
  474. <h4>Transitions across orthogonal regions</h4>
  475. <p><img alt="TransAcrossOrthRegions" src="TransAcrossOrthRegions.gif"
  476. border="0" width="226" height="271"></p>
  477. <p>Transitions across orthogonal regions are currently flagged with an
  478. error at compile time (the UML specifications explicitly allow them while
  479. Harel does not mention them at all). I decided to not support them because
  480. I have erroneously tried to implement such a transition several times but
  481. have never come across a situation where it would make any sense. If you
  482. need to make such transitions, please do let me know!</p>
  483. <hr>
  484. <p><a href="http://validator.w3.org/check?uri=referer"><img border="0" src=
  485. "../../../doc/images/valid-html401.png" alt="Valid HTML 4.01 Transitional"
  486. height="31" width="88"></a></p>
  487. <p>Revised
  488. <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B, %Y" startspan -->03 December, 2006<!--webbot bot="Timestamp" endspan i-checksum="38512" --></p>
  489. <p><i>Copyright &copy; 2003-<!--webbot bot="Timestamp" s-type="EDITED" s-format="%Y" startspan -->2006<!--webbot bot="Timestamp" endspan i-checksum="770" -->
  490. <a href="contact.html">Andreas Huber D&ouml;nni</a></i></p>
  491. <p><i>Distributed under the Boost Software License, Version 1.0. (See
  492. accompanying file <a href="../../../LICENSE_1_0.txt">LICENSE_1_0.txt</a> or
  493. copy at <a href=
  494. "http://www.boost.org/LICENSE_1_0.txt">http://www.boost.org/LICENSE_1_0.txt</a>)</i></p>
  495. </body>
  496. </html>