|
Boost-Commit : |
From: fmhess_at_[hidden]
Date: 2007-09-25 14:09:52
Author: fmhess
Date: 2007-09-25 14:09:10 EDT (Tue, 25 Sep 2007)
New Revision: 39527
URL: http://svn.boost.org/trac/boost/changeset/39527
Log:
More documentation updates. All the obvious problems I'm aware of should
be fixed now.
Text files modified:
sandbox/thread_safe_signals/libs/thread_safe_signals/doc/design.xml | 72 ----------------
sandbox/thread_safe_signals/libs/thread_safe_signals/doc/faq.xml | 14 +-
sandbox/thread_safe_signals/libs/thread_safe_signals/doc/rationale.xml | 170 ++++++++++-----------------------------
sandbox/thread_safe_signals/libs/thread_safe_signals/doc/signals.xml | 2
sandbox/thread_safe_signals/libs/thread_safe_signals/doc/tests.xml | 13 --
sandbox/thread_safe_signals/libs/thread_safe_signals/doc/tutorial.xml | 37 ++++++--
6 files changed, 84 insertions(+), 224 deletions(-)
Modified: sandbox/thread_safe_signals/libs/thread_safe_signals/doc/design.xml
==============================================================================
--- sandbox/thread_safe_signals/libs/thread_safe_signals/doc/design.xml (original)
+++ sandbox/thread_safe_signals/libs/thread_safe_signals/doc/design.xml 2007-09-25 14:09:10 EDT (Tue, 25 Sep 2007)
@@ -8,34 +8,6 @@
<using-namespace name="boost::signals"/>
<section>
- <title>Type Erasure</title>
-
- <para>"Type erasure", where static type information is eliminated
- by the use of dynamically dispatched interfaces, is used
- extensively within the Boost.Signals library to reduce the amount
- of code generated by template instantiation. Each signal must
- manage a list of slots and their associated connections, along
- with a <code>std::map</code> to map from group identifiers to
- their associated connections. However, instantiating this map for
- every token type, and perhaps within each translation unit (for
- some popular template instantiation strategies) increase compile
- time overhead and space overhead.</para>
-
- <para> To combat this so-called "template bloat", we use
- Boost.Function and Boost.Any to store unknown types and
- operations. Then, all of the code for handling the list of slots
- and the mapping from slot identifiers to connections is factored
- into the class <code><classname>signal_base</classname></code>
- that deals exclusively with the <code>any</code> and
- <code><classname>function</classname></code> objects, hiding the
- actual implementations using the well-known pimpl idiom. The
- actual <code><classname>signalN</classname></code> class templates
- deal only with code that will change depending on the number of
- arguments or which is inherently template-dependent (such as
- connection).</para>
- </section>
-
- <section>
<title><code>connection</code> class</title>
<para> The <code><classname>connection</classname></code> class is
@@ -121,7 +93,7 @@
iterator with the set of arguments given to the signal
itself, and returns the result of that slot
call.</para></entry>
- </row>
+ </row>
<row>
<entry><para>Input Caching Iterator Adaptor</para></entry>
<entry><para>This iterator adaptor caches the result of
@@ -139,46 +111,4 @@
</tgroup>
</informaltable>
</section>
-
- <section>
- <title><code>visit_each</code> function template</title>
-
- <para> The <code><functionname>visit_each</functionname></code>
- function template is a mechanism for discovering objects that are
- stored within another object. Function template
- <code><functionname>visit_each</functionname></code> takes three
- arguments: an object to explore, a visitor function object that is
- invoked with each subobject, and the <code>int</code> 0. </para>
-
- <para> The third parameter is merely a temporary solution to the
- widespread lack of proper function template partial ordering. The
- primary <code><functionname>visit_each</functionname></code>
- function template specifies this third parameter type to be
- <code>long</code>, whereas any user specializations must specify
- their third parameter to be of type <code>int</code>. Thus, even
- though a broken compiler cannot tell the ordering between, e.g., a
- match against a parameter <code>T</code> and a parameter
- <code>A<T></code>, it can determine that the conversion from
- the integer 0 to <code>int</code> is better than the conversion to
- <code>long</code>. The ordering determined by this conversion thus
- achieves partial ordering of the function templates in a limited,
- but successful, way. The following example illustrates the use of
- this technique:</para>
-
- <programlisting>
-template<typename> class A {};
-template<typename T> void foo(T, long);
-template<typename T> void foo(A<T>, int);
-A<T> at;
-foo(at, 0);
-</programlisting>
-
- <para> In this example, we assume that our compiler can not tell
- that <code>A<T></code> is a better match than
- <code>T</code>, and therefore assume that the function templates
- cannot be ordered based on that parameter. Then the conversion
- from 0 to <code>int</code> is better than the conversion from 0 to
- <code>long</code>, and the second function template is
- chosen. </para>
- </section>
</section>
Modified: sandbox/thread_safe_signals/libs/thread_safe_signals/doc/faq.xml
==============================================================================
--- sandbox/thread_safe_signals/libs/thread_safe_signals/doc/faq.xml (original)
+++ sandbox/thread_safe_signals/libs/thread_safe_signals/doc/faq.xml 2007-09-25 14:09:10 EDT (Tue, 25 Sep 2007)
@@ -24,9 +24,9 @@
</question>
<answer>
<para>Yes, if the ThreadingModel template parameter of the signal is set to
- <code>boost::signals::multi_threaded</code>, or if it is set to
- <code>boost::signals::auto_threaded</code> and boost has detected thread support
- in the compiler's current translation mode. If you use <code>boost::signals::multi_threaded</code>,
+ <code>boost::signalslib::multi_threaded</code>, or if it is set to
+ <code>boost::signalslib::auto_threaded</code> and boost has detected thread support
+ in the compiler's current translation mode. If you use <code>boost::signalslib::multi_threaded</code>,
you will also have to link to libboost_thread.</para>
</answer>
</qandaentry>
@@ -39,7 +39,7 @@
<code>signals</code> and <code>slots</code> are defined using
preprocessor macros, causing a conflict with the <code>boost::signals</code>
namespace. For thread_safe_signals, <code>boost::signals</code> is actually
- just an alias to <code>boost::signalslib</code>. So by always using the
+ just a namespace alias to <code>boost::signalslib</code>. So by always using the
namespace <code>boost::signalslib</code> instead of
<code>boost::signals</code> in your
code, you can avoid any conflict with the Qt <code>signals</code> macro.
@@ -55,10 +55,8 @@
Signals and Slots, the relevant part of your .pro file might
look like this:</para>
- <programlisting>
-CONFIG += no_keywords # so Qt won't #define any non-all-caps `keywords'
-INCLUDEPATH += . /usr/local/include/boost-1_33_1/
-macx:LIBS += /usr/local/lib/libboost_signals-1_33_1.a # ...your exact paths may vary
+ <programlisting>CONFIG += no_keywords # so Qt won't #define any non-all-caps `keywords'
+INCLUDEPATH += . /usr/local/include/thread_safe_signals /usr/local/include/boost-1_33_1/ # ...your exact paths may vary
</programlisting>
<para>Now you can mix Boost.Signals and Qt Signals and Slots
Modified: sandbox/thread_safe_signals/libs/thread_safe_signals/doc/rationale.xml
==============================================================================
--- sandbox/thread_safe_signals/libs/thread_safe_signals/doc/rationale.xml (original)
+++ sandbox/thread_safe_signals/libs/thread_safe_signals/doc/rationale.xml 2007-09-25 14:09:10 EDT (Tue, 25 Sep 2007)
@@ -5,67 +5,10 @@
<title>Design Rationale</title>
<using-namespace name="boost"/>
- <using-namespace name="boost::signals"/>
+ <using-namespace name="boost::signalslib"/>
<using-class name="boost::signalN"/>
<section>
- <title>Choice of Slot Definitions</title>
-
- <para> The definition of a slot differs amongst signals and slots
- libraries. Within Boost.Signals, a slot is defined in a very loose
- manner: it can be any function object that is callable given
- parameters of the types specified by the signal, and whose return
- value is convertible to the result type expected by the
- signal. However, alternative definitions have associated pros and
- cons that were considered prior to the construction of
- Boost.Signals.</para>
-
- <itemizedlist>
- <listitem>
- <para><emphasis role="bold">Slots derive from a specific base
- class</emphasis>: generally a scheme such as this will require
- all user-defined slots to derive from some library-specified
- <code>Slot</code> abstract class that defines a virtual
- function calling the slot. Adaptors can be used to convert a
- definition such as this to a definition similar to that used
- by Boost.Signals, but the use of a large number of small
- adaptor classes containing virtual functions has been found to
- cause an unacceptable increase in the size of executables
- (polymorphic class types require more code than
- non-polymorphic types).</para>
-
- <para> This approach does have the benefit of simplicity of
- implementation and user interface, from an object-oriented
- perspective.</para>
- </listitem>
-
- <listitem>
- <para><emphasis role="bold">Slots constructed from a set of
- primitives</emphasis>: in this scheme the slot can have a
- limited set of types (often derived from a common abstract
- base class) that are constructed from some library-defined set
- of primitives that often include conversions from free
- function pointers and member function pointers, and a limited
- set of binding capabilities. Such an approach is reasonably
- simple and cover most common cases, but it does not allow a
- large degree of flexibility in slot construction. Libraries
- for function object composition have become quite advanced and
- it is out of the scope of a signals and slots library to
- encorporate such enhancements. Thus Boost.Signals does not
- include argument binding or function object composition
- primitives, but instead provides a hook (via the
- <code><functionname>visit_each</functionname></code>
- mechanism) that allows existing binder/composition libraries
- to provide the necessary information to Signals.</para>
- </listitem>
- </itemizedlist>
-
- <para> Users not satisfied with the slot definition choice may opt
- to replace the default slot function type with an alternative that
- meets their specific needs.</para>
- </section>
-
- <section>
<title>User-level Connection Management</title>
<para> Users need to have fine control over the connection of
@@ -96,7 +39,7 @@
existing slot we would need to be able to compare arbitrary
function objects, which is not feasible.</para>
</listitem>
-
+
<listitem>
<para><emphasis role="bold">Pass a token to
disconnect</emphasis>: this approach identifies slots with a
@@ -115,7 +58,7 @@
implementation, their detection is generally
nontrivial.</para>
</listitem>
-
+
<listitem>
<para>Tokens must be unique, otherwise two slots will have
the same name and will be indistinguishable. In
@@ -143,6 +86,41 @@
</section>
<section>
+ <title>Automatic Connection Management</title>
+
+ <para>Automatic connection management in thread_safe_signals
+ depends on the use of <classname>boost::shared_ptr</classname> to
+ manage the lifetimes of tracked objects. This is differs from
+ the original Boost.Signals library, which instead relied on derivation
+ from the <code><classname>boost::trackable</classname></code> class.
+ The Boost.Signals library would be
+ notified of an object's destruction by the
+ <code><classname>trackable</classname></code> destructor.
+ </para>
+ <para>Unfortunately, the <code><classname>trackable</classname></code>
+ scheme cannot be made thread safe due
+ to destructor ordering. The destructor of an class derived from
+ <code><classname>trackable</classname></code> will always be
+ called before the destructor of the base <code><classname>trackable</classname></code>
+ class. However, for thread-safety the connection between the signal and object
+ needs to be disconnected before the object runs its destructors.
+ Otherwise, if an object being destroyed
+ in one thread is connected to a signal concurrently
+ invoking in another thread, the signal may call into
+ a partially destroyed object.
+ </para>
+ <para>We solve this problem by requiring that tracked objects be
+ managed by <classname>shared_ptr</classname>. Slots keep a
+ <classname>weak_ptr</classname> to every object the slot depends
+ on. Connections to a slot are disconnected when any of its tracked
+ <classname>weak_ptr</classname>s expire. Additionally, signals
+ create their own temporary <classname>shared_ptr</classname>s to
+ all of a slot's tracked objects prior to invoking the slot. This
+ insures none of the tracked objects from destruct in mid-invocation.
+ </para>
+ </section>
+
+ <section>
<title>Combiner Interface</title>
<para> The Combiner interface was chosen to mimic a call to an
@@ -231,15 +209,15 @@
return true;
}
- int get_value() const
- {
+ int get_value() const
+ {
if (!got_first)
throw std::runtime_error("Empty!");
- return max_value;
+ return max_value;
}
private:
- int max_value;
+ int max_value;
bool got_first;
};
</programlisting>
@@ -326,69 +304,13 @@
</listitem>
</itemizedlist>
</section>
-
- <section>
- <title><code>trackable</code> rationale</title>
-
- <para> The <code><classname>trackable</classname></code>
- class is the primary user interface to automatic connection
- lifetime management, and its design affects users directly. Two
- issues stick out most: the odd copying behavior of
- <code>trackable</code>, and the limitation requiring users to
- derive from <code>trackable</code> to create types that can
- participate in automatic connection management.</para>
-
- <section>
- <title><code>trackable</code> copying behavior</title>
-
- <para> The copying behavior of
- <code><classname>trackable</classname></code> is essentially
- that <code><classname>trackable</classname></code> subobjects
- are never copied; instead, the copy operation is merely a
- no-op. To understand this, we look at the nature of a
- signal-slot connection and note that the connection is based on
- the entities that are being connected; when one of the entities
- is destroyed, the connection is destroyed. Therefore, when a
- <code><classname>trackable</classname></code> subobject is
- copied, we cannot copy the connections because the connections
- don't refer to the target entity - they refer to the source
- entity. This reason is dual to the reason signals are
- noncopyable: the slots connected to them are connected to that
- particular signal, not the data contained in the signal.</para>
- </section>
-
- <section>
- <title>Why derivation from <code>trackable</code>?</title>
-
- <para> For <code><classname>trackable</classname></code> to work
- properly, there are two constraints:</para>
-
- <itemizedlist>
- <listitem>
- <para><code><classname>trackable</classname></code> must
- have storage space to keep track of all connections made to
- this object.</para>
- </listitem>
-
- <listitem>
- <para><code><classname>trackable</classname></code> must be
- notified when the object is being destructed so that it can
- disconnect its connections.</para>
- </listitem>
- </itemizedlist>
-
- <para>Clearly, deriving from
- <code><classname>trackable</classname></code> meets these two
- guidelines. We have not yet found a superior solution.</para>
- </section>
- </section>
<section>
<title>Comparison with other Signal/Slot implementations</title>
<section>
<title>libsigc++</title>
-
+
<para> <ulink
url="http://libsigc.sourceforge.net">libsigc++</ulink> is a C++
signals & slots library that originally started as part of
@@ -399,7 +321,7 @@
indeed Boost.Signals was strongly influenced by Karl Nelson and
libsigc++. A cursory inspection of each library will find a
similar syntax for the construction of signals and in the use of
- connections and automatic connection lifetime management. There
+ connections. There
are some major differences in design that separate these
libraries:</para>
@@ -411,9 +333,7 @@
objects (as part of the library), explicit adaptation from
the argument and return types of the signal to the argument
and return types of the slot (libsigc++ is, by default, more
- strict about types than Boost.Signals). A discussion of this
- approach with a comparison against the approach taken by
- Boost.Signals is given in Choice of Slot Definitions.</para>
+ strict about types than Boost.Signals).</para>
</listitem>
<listitem>
Modified: sandbox/thread_safe_signals/libs/thread_safe_signals/doc/signals.xml
==============================================================================
--- sandbox/thread_safe_signals/libs/thread_safe_signals/doc/signals.xml (original)
+++ sandbox/thread_safe_signals/libs/thread_safe_signals/doc/signals.xml 2007-09-25 14:09:10 EDT (Tue, 25 Sep 2007)
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
-<library name="Signals" dirname="signals"
+<library name="Signals" dirname="thread_safe_signals"
xmlns:xi="http://www.w3.org/2001/XInclude" id="signals"
last-revision="$Date: 2007-06-12 14:01:23 -0400 (Tue, 12 Jun 2007) $">
<libraryinfo>
Modified: sandbox/thread_safe_signals/libs/thread_safe_signals/doc/tests.xml
==============================================================================
--- sandbox/thread_safe_signals/libs/thread_safe_signals/doc/tests.xml (original)
+++ sandbox/thread_safe_signals/libs/thread_safe_signals/doc/tests.xml 2007-09-25 14:09:10 EDT (Tue, 25 Sep 2007)
@@ -7,14 +7,13 @@
<lib>../build/boost_signals</lib>
<purpose>
<para>Ensure that calling <methodname>connect</methodname> with a slot
-that has already been disconnected via deletion does not actually
+that has already expired does not actually
connect to the slot.</para>
</purpose>
</run-test>
<run-test filename="deletion_test.cpp">
<lib>../../../libs/test/build/boost_test_exec_monitor</lib>
- <lib>../build/boost_signals</lib>
<purpose>
<para>Test deletion of slots.</para>
</purpose>
@@ -22,13 +21,11 @@
<run-test filename="ordering_test.cpp">
<lib>../../../libs/test/build/boost_test_exec_monitor</lib>
- <lib>../build/boost_signals</lib>
<purpose><para>Test slot group ordering.</para></purpose>
</run-test>
<run-test filename="signal_n_test.cpp">
<lib>../../../libs/test/build/boost_test_exec_monitor</lib>
- <lib>../build/boost_signals</lib>
<purpose>
<para>Basic test of signal/slot connections and invocation using the
<classname>boost::signalN</classname> class templates.</para>
@@ -37,7 +34,6 @@
<run-test filename="signal_test.cpp">
<lib>../../../libs/test/build/boost_test_exec_monitor</lib>
- <lib>../build/boost_signals</lib>
<purpose>
<para>Basic test of signal/slot connections and invocation using the
<classname>boost::signal</classname> class template.</para>
@@ -50,12 +46,11 @@
</if-fails>
</run-test>
- <run-test filename="trackable_test.cpp">
+ <run-test filename="track_test.cpp">
<lib>../../../libs/test/build/boost_test_exec_monitor</lib>
- <lib>../build/boost_signals</lib>
<purpose>
- <para>Test automatic lifetime management using
- <classname>boost::trackable</classname> objects.</para>
+ <para>Test automatic connection management of signals
+ and slots.</para>
</purpose>
</run-test>
</testsuite>
Modified: sandbox/thread_safe_signals/libs/thread_safe_signals/doc/tutorial.xml
==============================================================================
--- sandbox/thread_safe_signals/libs/thread_safe_signals/doc/tutorial.xml (original)
+++ sandbox/thread_safe_signals/libs/thread_safe_signals/doc/tutorial.xml 2007-09-25 14:09:10 EDT (Tue, 25 Sep 2007)
@@ -474,13 +474,15 @@
{
// If there are no slots to call, just return the
// default-constructed value
- if (first == last)
- return T();
-
- T max_value = *first++;
+ T max_value = T();
while (first != last) {
- if (max_value < *first)
- max_value = *first;
+ try {
+ if (max_value < *first)
+ max_value = *first;
+ }
+ // Iterator dereference may throw boost::expired_slot if the
+ // slot has expired due to automatic connection management.
+ catch(const boost::expired_slot &) {}
++first;
}
@@ -554,7 +556,16 @@
template<typename InputIterator>
Container operator()(InputIterator first, InputIterator last) const
{
- return Container(first, last);
+ Container values;
+
+ while(first != last) {
+ try {
+ values.push_back(*first);
+ }
+ catch(const boost::expired_slot &) {}
+ ++first;
+ }
+ return values;
}
};
</programlisting>
@@ -636,8 +647,11 @@
result_type operator()(InputIterator first, InputIterator last) const
{
while (first != last) {
- if (result_type fulfilled = *first)
- return fulfilled;
+ try {
+ if (result_type fulfilled = *first)
+ return fulfilled;
+ }
+ catch(const boost::expired_slot &) {}
++first;
}
return 0;
@@ -1130,7 +1144,10 @@
<section>
<title>Linking against the Signals library</title>
<para>The thread_safe_signals version of Boost.Signals is currently a header-only library.
- No linking is to a compiled binary library is required.
+ However, if you use the <classname>boost::signalslib::multithreaded</classname> class as
+ the ThreadingModel template parameter for your signals, you will have to link to the
+ Boost.threads library, libboost_thread.
+ .
</para>
</section>
Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk