• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
2<html>
3<head>
4<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
5<title>Design Rationale</title>
6<link rel="stylesheet" href="../../../doc/src/boostbook.css" type="text/css">
7<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
8<link rel="home" href="../index.html" title="The Boost C++ Libraries BoostBook Documentation Subset">
9<link rel="up" href="../signals2.html" title="Chapter 35. Boost.Signals2">
10<link rel="prev" href="faq.html" title="Frequently Asked Questions">
11<link rel="next" href="api_changes.html" title="Signals2 API Changes">
12</head>
13<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
14<table cellpadding="2" width="100%"><tr>
15<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../boost.png"></td>
16<td align="center"><a href="../../../index.html">Home</a></td>
17<td align="center"><a href="../../../libs/libraries.htm">Libraries</a></td>
18<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td>
19<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td>
20<td align="center"><a href="../../../more/index.htm">More</a></td>
21</tr></table>
22<hr>
23<div class="spirit-nav">
24<a accesskey="p" href="faq.html"><img src="../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../signals2.html"><img src="../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="api_changes.html"><img src="../../../doc/src/images/next.png" alt="Next"></a>
25</div>
26<div class="section">
27<div class="titlepage"><div><div><h2 class="title" style="clear: both">
28<a name="signals2.rationale"></a>Design Rationale</h2></div></div></div>
29<div class="toc"><dl class="toc">
30<dt><span class="section"><a href="rationale.html#id-1.3.36.9.2">User-level Connection Management</a></span></dt>
31<dt><span class="section"><a href="rationale.html#id-1.3.36.9.3">Automatic Connection Management</a></span></dt>
32<dt><span class="section"><a href="rationale.html#id-1.3.36.9.4"><code class="computeroutput">optional_last_value</code> as the Default Combiner</a></span></dt>
33<dt><span class="section"><a href="rationale.html#id-1.3.36.9.5">Combiner Interface</a></span></dt>
34<dt><span class="section"><a href="rationale.html#id-1.3.36.9.6">Connection Interfaces: +=  operator</a></span></dt>
35<dt><span class="section"><a href="rationale.html#id-1.3.36.9.7">Signals2 Mutex Classes</a></span></dt>
36<dt><span class="section"><a href="rationale.html#id-1.3.36.9.8">Comparison with other Signal/Slot implementations</a></span></dt>
37</dl></div>
38<div class="section">
39<div class="titlepage"><div><div><h3 class="title">
40<a name="id-1.3.36.9.2"></a>User-level Connection Management</h3></div></div></div>
41<p> Users need to have fine control over the connection of
42    signals to slots and their eventual disconnection. The primary approach
43    taken by Boost.Signals2 is to return a
44    <code class="computeroutput"><a class="link" href="../boost/signals2/connection.html" title="Class connection">signals2::connection</a></code> object that enables
45    connected/disconnected query, manual disconnection, and an
46    automatic disconnection on destruction mode (<code class="computeroutput"><a class="link" href="../boost/signals2/scoped_connection.html" title="Class scoped_connection">signals2::scoped_connection</a></code>).
47    In addition, two other interfaces are supported by the
48    <code class="computeroutput"><a class="link" href="../boost/signals2/signal.html#id-1_3_36_6_9_3_1_2_24_3-bb">signal::disconnect</a></code> overloaded method:</p>
49<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
50<li class="listitem"><p><span class="bold"><strong>Pass slot to
51        disconnect</strong></span>: in this interface model, the
52        disconnection of a slot connected with
53        <code class="computeroutput">sig.<a class="link" href="../boost/signals2/signal.html#id-1_3_36_6_9_3_1_2_24_1-bb">connect</a>(typeof(sig)::slot_type(slot_func))</code> is
54        performed via
55        <code class="computeroutput">sig.<a class="link" href="../boost/signals2/signal.html#id-1_3_36_6_9_3_1_2_24_3-bb">disconnect</a>(slot_func)</code>. Internally,
56        a linear search using slot comparison is performed and the
57        slot, if found, is removed from the list. Unfortunately,
58        querying connectedness ends up as a
59        linear-time operation.</p></li>
60<li class="listitem">
61<p><span class="bold"><strong>Pass a token to
62        disconnect</strong></span>: this approach identifies slots with a
63        token that is easily comparable (e.g., a string), enabling
64        slots to be arbitrary function objects. While this approach is
65        essentially equivalent to the connection approach taken by Boost.Signals2,
66        it is possibly more error-prone for several reasons:</p>
67<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: circle; ">
68<li class="listitem"><p>Connections and disconnections must be paired, so
69            the problem becomes similar to the problems incurred when
70            pairing <code class="computeroutput">new</code> and <code class="computeroutput">delete</code> for
71            dynamic memory allocation. While errors of this sort would
72            not be catastrophic for a signals and slots
73            implementation, their detection is generally
74            nontrivial.</p></li>
75<li class="listitem"><p>If tokens are not unique, two slots may have
76            the same name and be indistinguishable. In
77            environments where many connections will be made
78            dynamically, name generation becomes an additional task
79            for the user.</p></li>
80</ul></div>
81<p> This type of interface is supported in Boost.Signals2
82        via the slot grouping mechanism, and the overload of
83        <code class="computeroutput"><a class="link" href="../boost/signals2/signal.html#id-1_3_36_6_9_3_1_2_24_3-bb">signal::disconnect</a></code>
84        which takes an argument of the signal's <code class="computeroutput">Group</code> type.</p>
85</li>
86</ul></div>
87</div>
88<div class="section">
89<div class="titlepage"><div><div><h3 class="title">
90<a name="id-1.3.36.9.3"></a>Automatic Connection Management</h3></div></div></div>
91<p>Automatic connection management in Signals2
92      depends on the use of <code class="computeroutput">boost::shared_ptr</code> to
93      manage the lifetimes of tracked objects.  This is differs from
94      the original Boost.Signals library, which instead relied on derivation
95      from the <code class="computeroutput">boost::signals::trackable</code> class.
96      The library would be
97      notified of an object's destruction by the
98      <code class="computeroutput">boost::signals::trackable</code> destructor.
99    </p>
100<p>Unfortunately, the <code class="computeroutput">boost::signals::trackable</code>
101      scheme cannot be made thread safe due
102      to destructor ordering.  The destructor of an class derived from
103      <code class="computeroutput">boost::signals::trackable</code> will always be
104      called before the destructor of the base <code class="computeroutput">boost::signals::trackable</code>
105      class.  However, for thread-safety the connection between the signal and object
106      needs to be disconnected before the object runs its destructors.
107      Otherwise, if an object being destroyed
108      in one thread is connected to a signal concurrently
109      invoking in another thread, the signal may call into
110      a partially destroyed object.
111    </p>
112<p>We solve this problem by requiring that tracked objects be
113      managed by <code class="computeroutput">shared_ptr</code>.  Slots keep a
114      <code class="computeroutput">weak_ptr</code> to every object the slot depends
115      on.  Connections to a slot are disconnected when any of its tracked
116      <code class="computeroutput">weak_ptr</code>s expire.  Additionally, signals
117      create their own temporary <code class="computeroutput">shared_ptr</code>s to
118      all of a slot's tracked objects prior to invoking the slot.  This
119      insures none of the tracked objects destruct in mid-invocation.
120    </p>
121<p>The new connection management scheme has the advantage of being
122      non-intrusive.  Objects of any type may be tracked using the
123      <code class="computeroutput">shared_ptr</code>/<code class="computeroutput">weak_ptr</code> scheme.  The old
124      <code class="computeroutput">boost::signals::trackable</code>
125      scheme requires the tracked objects to be derived from the <code class="computeroutput">trackable</code>
126      base class, which is not always practical when interacting
127      with classes from 3rd party libraries.
128    </p>
129</div>
130<div class="section">
131<div class="titlepage"><div><div><h3 class="title">
132<a name="id-1.3.36.9.4"></a><code class="computeroutput">optional_last_value</code> as the Default Combiner</h3></div></div></div>
133<p>
134      The default combiner for Boost.Signals2 has changed from the <code class="computeroutput">last_value</code>
135      combiner used by default in the original Boost.Signals library.
136      This is because <code class="computeroutput">last_value</code> requires that at least 1 slot be
137      connected to the signal when it is invoked (except for the <code class="computeroutput">last_value&lt;void&gt;</code> specialization).
138      In a multi-threaded environment where signal invocations and slot connections
139      and disconnections may be happening concurrently, it is difficult
140      to fulfill this requirement.  When using <code class="computeroutput"><a class="link" href="../boost/signals2/optional_last_value.html" title="Class template optional_last_value">optional_last_value</a></code>,
141      there is no requirement for slots to be connected when a signal
142      is invoked, since in that case the combiner may simply return an empty
143      <code class="computeroutput">boost::optional</code>.
144    </p>
145</div>
146<div class="section">
147<div class="titlepage"><div><div><h3 class="title">
148<a name="id-1.3.36.9.5"></a>Combiner Interface</h3></div></div></div>
149<p> The Combiner interface was chosen to mimic a call to an
150    algorithm in the C++ standard library. It is felt that by viewing
151    slot call results as merely a sequence of values accessed by input
152    iterators, the combiner interface would be most natural to a
153    proficient C++ programmer. Competing interface design generally
154    required the combiners to be constructed to conform to an
155    interface that would be customized for (and limited to) the
156    Signals2 library. While these interfaces are generally enable more
157    straighforward implementation of the signals &amp; slots
158    libraries, the combiners are unfortunately not reusable (either in
159    other signals &amp; slots libraries or within other generic
160    algorithms), and the learning curve is steepened slightly to learn
161    the specific combiner interface.</p>
162<p> The Signals2 formulation of combiners is based on the
163    combiner using the "pull" mode of communication, instead of the
164    more complex "push" mechanism. With a "pull" mechanism, the
165    combiner's state can be kept on the stack and in the program
166    counter, because whenever new data is required (i.e., calling the
167    next slot to retrieve its return value), there is a simple
168    interface to retrieve that data immediately and without returning
169    from the combiner's code. Contrast this with the "push" mechanism,
170    where the combiner must keep all state in class members because
171    the combiner's routines will be invoked for each signal
172    called. Compare, for example, a combiner that returns the maximum
173    element from calling the slots. If the maximum element ever
174    exceeds 100, no more slots are to be called.</p>
175<div class="informaltable"><table class="table">
176<colgroup>
177<col>
178<col>
179</colgroup>
180<thead><tr>
181<th align="left"><p>Pull</p></th>
182<th align="left"><p>Push</p></th>
183</tr></thead>
184<tbody><tr>
185<td align="left">
186<pre xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" class="table-programlisting">
187struct pull_max {
188  typedef int result_type;
189
190  template&lt;typename InputIterator&gt;
191  result_type operator()(InputIterator first,
192                         InputIterator last)
193  {
194    if (first == last)
195      throw std::runtime_error("Empty!");
196
197    int max_value = *first++;
198    while(first != last &amp;&amp; *first &lt;= 100) {
199      if (*first &gt; max_value)
200        max_value = *first;
201      ++first;
202    }
203
204    return max_value;
205  }
206};
207</pre>
208</td>
209<td align="left">
210<pre xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" class="table-programlisting">
211struct push_max {
212  typedef int result_type;
213
214  push_max() : max_value(), got_first(false) {}
215
216  // returns false when we want to stop
217  bool operator()(int result) {
218    if (result &gt; 100)
219      return false;
220
221    if (!got_first) {
222      got_first = true;
223      max_value = result;
224      return true;
225    }
226
227    if (result &gt; max_value)
228      max_value = result;
229
230    return true;
231  }
232
233  int get_value() const
234  {
235    if (!got_first)
236      throw std::runtime_error("Empty!");
237    return max_value;
238  }
239
240private:
241  int  max_value;
242  bool got_first;
243};
244</pre>
245</td>
246</tr></tbody>
247</table></div>
248<p>There are several points to note in these examples. The
249    "pull" version is a reusable function object that is based on an
250    input iterator sequence with an integer <code class="computeroutput">value_type</code>,
251    and is very straightforward in design. The "push" model, on the
252    other hand, relies on an interface specific to the caller and is
253    not generally reusable. It also requires extra state values to
254    determine, for instance, if any elements have been
255    received. Though code quality and ease-of-use is generally
256    subjective, the "pull" model is clearly shorter and more reusable
257    and will often be construed as easier to write and understand,
258    even outside the context of a signals &amp; slots library.</p>
259<p> The cost of the "pull" combiner interface is paid in the
260    implementation of the Signals2 library itself. To correctly handle
261    slot disconnections during calls (e.g., when the dereference
262    operator is invoked), one must construct the iterator to skip over
263    disconnected slots. Additionally, the iterator must carry with it
264    the set of arguments to pass to each slot (although a reference to
265    a structure containing those arguments suffices), and must cache
266    the result of calling the slot so that multiple dereferences don't
267    result in multiple calls. This apparently requires a large degree
268    of overhead, though if one considers the entire process of
269    invoking slots one sees that the overhead is nearly equivalent to
270    that in the "push" model, but we have inverted the control
271    structures to make iteration and dereference complex (instead of
272    making combiner state-finding complex).</p>
273</div>
274<div class="section">
275<div class="titlepage"><div><div><h3 class="title">
276<a name="id-1.3.36.9.6"></a>Connection Interfaces: +=  operator</h3></div></div></div>
277<p> Boost.Signals2 supports a connection syntax with the form
278    <code class="computeroutput">sig.<a class="link" href="../boost/signals2/signal.html#id-1_3_36_6_9_3_1_2_24_1-bb">connect</a>(slot)</code>, but a
279    more terse syntax <code class="computeroutput">sig += slot</code> has been suggested (and
280    has been used by other signals &amp; slots implementations). There
281    are several reasons as to why this syntax has been
282    rejected:</p>
283<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
284<li class="listitem"><p><span class="bold"><strong>It's unnecessary</strong></span>: the
285        connection syntax supplied by Boost.Signals2 is no less
286        powerful that that supplied by the <code class="computeroutput">+=</code>
287        operator. The savings in typing (<code class="computeroutput">connect()</code>
288        vs. <code class="computeroutput">+=</code>) is essentially negligible. Furthermore,
289        one could argue that calling <code class="computeroutput">connect()</code> is more
290        readable than an overload of <code class="computeroutput">+=</code>.</p></li>
291<li class="listitem"><p><span class="bold"><strong>Ambiguous return type</strong></span>:
292        there is an ambiguity concerning the return value of the
293        <code class="computeroutput">+=</code> operation: should it be a reference to the
294        signal itself, to enable <code class="computeroutput">sig += slot1 += slot2</code>,
295        or should it return a
296        <code class="computeroutput"><a class="link" href="../boost/signals2/connection.html" title="Class connection">signals2::connection</a></code> for the
297        newly-created signal/slot connection?</p></li>
298<li class="listitem">
299<p><span class="bold"><strong>Gateway to operators -=,
300        +</strong></span>: when one has added a connection operator
301        <code class="computeroutput">+=</code>, it seems natural to have a disconnection
302        operator <code class="computeroutput">-=</code>. However, this presents problems when
303        the library allows arbitrary function objects to implicitly
304        become slots, because slots are no longer comparable.  </p>
305<p> The second obvious addition when one has
306        <code class="computeroutput">operator+=</code> would be to add a <code class="computeroutput">+</code>
307        operator that supports addition of multiple slots, followed by
308        assignment to a signal. However, this would require
309        implementing <code class="computeroutput">+</code> such that it can accept any two
310        function objects, which is technically infeasible.</p>
311</li>
312</ul></div>
313</div>
314<div class="section">
315<div class="titlepage"><div><div><h3 class="title">
316<a name="id-1.3.36.9.7"></a>Signals2 Mutex Classes</h3></div></div></div>
317<p>
318      The Boost.Signals2 library provides 2 mutex classes: <code class="computeroutput"><a class="link" href="../boost/signals2/mutex.html" title="Class mutex">boost::signals2::mutex</a></code>,
319      and <code class="computeroutput"><a class="link" href="../boost/signals2/dummy_mutex.html" title="Class dummy_mutex">boost::signals2::dummy_mutex</a></code>.  The motivation for providing
320      <code class="computeroutput"><a class="link" href="../boost/signals2/mutex.html" title="Class mutex">boost::signals2::mutex</a></code> is simply that the <code class="computeroutput">boost::mutex</code>
321      class provided by the Boost.Thread library currently requires linking to libboost_thread.
322      The <code class="computeroutput"><a class="link" href="../boost/signals2/mutex.html" title="Class mutex">boost::signals2::mutex</a></code> class allows Signals2 to remain
323      a header-only library.  You may still choose to use <code class="computeroutput">boost::mutex</code>
324      if you wish, by specifying it as the <code class="computeroutput">Mutex</code> template type for your signals.
325    </p>
326<p>
327      The <code class="computeroutput"><a class="link" href="../boost/signals2/dummy_mutex.html" title="Class dummy_mutex">boost::signals2::dummy_mutex</a></code> class is provided to allow
328      performance sensitive single-threaded applications to minimize overhead by avoiding unneeded
329      mutex locking.
330    </p>
331</div>
332<div class="section">
333<div class="titlepage"><div><div><h3 class="title">
334<a name="id-1.3.36.9.8"></a>Comparison with other Signal/Slot implementations</h3></div></div></div>
335<div class="toc"><dl class="toc">
336<dt><span class="section"><a href="rationale.html#id-1.3.36.9.8.2">libsigc++</a></span></dt>
337<dt><span class="section"><a href="rationale.html#id-1.3.36.9.8.3">.NET delegates</a></span></dt>
338</dl></div>
339<div class="section">
340<div class="titlepage"><div><div><h4 class="title">
341<a name="id-1.3.36.9.8.2"></a>libsigc++</h4></div></div></div>
342<p> <a href="http://libsigc.sourceforge.net" target="_top">libsigc++</a> is a C++
343      signals &amp; slots library that originally started as part of
344      an initiative to wrap the C interfaces to <a href="http://www.gtk.org" target="_top">GTK</a> libraries in C++, and has
345      grown to be a separate library maintained by Karl Nelson. There
346      are many similarities between libsigc++ and Boost.Signals2, and
347      indeed the original Boost.Signals was strongly influenced by
348      Karl Nelson and libsigc++. A cursory inspection of each library will find a
349      similar syntax for the construction of signals and in the use of
350      connections. There
351      are some major differences in design that separate these
352      libraries:</p>
353<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
354<li class="listitem"><p><span class="bold"><strong>Slot definitions</strong></span>:
355          slots in libsigc++ are created using a set of primitives
356          defined by the library. These primitives allow binding of
357          objects (as part of the library), explicit adaptation from
358          the argument and return types of the signal to the argument
359          and return types of the slot (libsigc++ is, by default, more
360          strict about types than Boost.Signals2).</p></li>
361<li class="listitem"><p><span class="bold"><strong>Combiner/Marshaller
362          interface</strong></span>: the equivalent to Boost.Signals2
363          combiners in libsigc++ are the marshallers. Marshallers are
364          similar to the "push" interface described in Combiner
365          Interface, and a proper treatment of the topic is given
366          there.</p></li>
367</ul></div>
368</div>
369<div class="section">
370<div class="titlepage"><div><div><h4 class="title">
371<a name="id-1.3.36.9.8.3"></a>.NET delegates</h4></div></div></div>
372<p> <a href="http://www.microsoft.com" target="_top">Microsoft</a>
373      has introduced the .NET Framework and an associated set of
374      languages and language extensions, one of which is the
375      delegate. Delegates are similar to signals and slots, but they
376      are more limited than most C++ signals and slots implementations
377      in that they:</p>
378<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
379<li class="listitem"><p>Require exact type matches between a delegate and what
380          it is calling.</p></li>
381<li class="listitem"><p>Only return the result of the last target called, with no option for customization.</p></li>
382<li class="listitem"><p>Must call a method with <code class="computeroutput">this</code> already
383          bound.</p></li>
384</ul></div>
385</div>
386</div>
387</div>
388<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
389<td align="left"><p><small>Last revised: June 12, 2007 at 14:01:23 -0400</small></p></td>
390<td align="right"><div class="copyright-footer">Copyright © 2001-2004 Douglas Gregor<br>Copyright © 2007-2009 Frank Mori Hess<p>Distributed under the Boost
391    Software License, Version 1.0. (See accompanying file
392    <code class="filename">LICENSE_1_0.txt</code> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)</p>
393</div></td>
394</tr></table>
395<hr>
396<div class="spirit-nav">
397<a accesskey="p" href="faq.html"><img src="../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../signals2.html"><img src="../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="api_changes.html"><img src="../../../doc/src/images/next.png" alt="Next"></a>
398</div>
399</body>
400</html>
401