Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/libs/statechart/doc/rationale.html @ 33

Last change on this file since 33 was 29, checked in by landauf, 16 years ago

updated boost from 1_33_1 to 1_34_1

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