Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/doc/html/thread/rationale.html @ 46

Last change on this file since 46 was 29, checked in by landauf, 17 years ago

updated boost from 1_33_1 to 1_34_1

File size: 30.4 KB
RevLine 
[29]1<html>
2<head>
3<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
4<title>Rationale</title>
5<link rel="stylesheet" href="../boostbook.css" type="text/css">
6<meta name="generator" content="DocBook XSL Stylesheets V1.68.1">
7<link rel="start" href="../index.html" title="The Boost C++ Libraries BoostBook Documentation Subset">
8<link rel="up" href="../thread.html" title="Chapter 15. Boost.Thread">
9<link rel="prev" href="concepts.html" title="Concepts">
10<link rel="next" href="reference.html" title="Reference">
11</head>
12<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
13<table cellpadding="2" width="100%">
14<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../boost.png"></td>
15<td align="center"><a href="../../../index.htm">Home</a></td>
16<td align="center"><a href="../../../libs/libraries.htm">Libraries</a></td>
17<td align="center"><a href="../../../people/people.htm">People</a></td>
18<td align="center"><a href="../../../more/faq.htm">FAQ</a></td>
19<td align="center"><a href="../../../more/index.htm">More</a></td>
20</table>
21<hr>
22<div class="spirit-nav">
23<a accesskey="p" href="concepts.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../thread.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="reference.html"><img src="../images/next.png" alt="Next"></a>
24</div>
25<div class="section" lang="en">
26<div class="titlepage"><div><div><h2 class="title" style="clear: both">
27<a name="thread.rationale"></a>Rationale</h2></div></div></div>
28<div class="toc"><dl>
29<dt><span class="section"><a href="rationale.html#thread.rationale.Boost.Thread">Rationale for the Creation of <span class="bold"><strong>Boost.Thread</strong></span></a></span></dt>
30<dt><span class="section"><a href="rationale.html#thread.rationale.primitives">Rationale for the Low Level Primitives Supported in <span class="bold"><strong>Boost.Thread</strong></span></a></span></dt>
31<dt><span class="section"><a href="rationale.html#thread.rationale.locks">Rationale for the Lock Design</a></span></dt>
32<dt><span class="section"><a href="rationale.html#thread.rationale.non-copyable">Rationale for NonCopyable Thread Type</a></span></dt>
33<dt><span class="section"><a href="rationale.html#thread.rationale.events">Rationale for not providing <span class="emphasis"><em>Event Variables</em></span></a></span></dt>
34</dl></div>
35<p>This page explains the rationale behind various design decisions in the
36  <span class="bold"><strong>Boost.Thread</strong></span> library. Having the rationale documented here should explain
37  how we arrived at the current design as well as prevent future rehashing of
38  discussions and thought processes that have already occurred. It can also give
39  users a lot of insight into the design process required for this
40  library.</p>
41<div class="section" lang="en">
42<div class="titlepage"><div><div><h3 class="title">
43<a name="thread.rationale.Boost.Thread"></a>Rationale for the Creation of <span class="bold"><strong>Boost.Thread</strong></span></h3></div></div></div>
44<p>Processes often have a degree of "potential parallelism" and it can
45        often be more intuitive to design systems with this in mind. Further, these
46        parallel processes can result in more responsive programs. The benefits for
47        multithreaded programming are quite well known to most modern programmers,
48        yet the C++ language doesn't directly support this concept.</p>
49<p>Many platforms support multithreaded programming despite the fact that
50        the language doesn't support it. They do this through external libraries,
51        which are, unfortunately, platform specific. POSIX has tried to address this
52        problem through the standardization of a "pthread" library. However, this is
53        a standard only on POSIX platforms, so its portability is limited.</p>
54<p>Another problem with POSIX and other platform specific thread
55        libraries is that they are almost universally C based libraries. This leaves
56        several C++ specific issues unresolved, such as what happens when an
57        exception is thrown in a thread. Further, there are some C++ concepts, such
58        as destructors, that can make usage much easier than what's available in a C
59        library.</p>
60<p>What's truly needed is C++ language support for threads. However, the
61        C++ standards committee needs existing practice or a good proposal as a
62        starting point for adding this to the standard.</p>
63<p>The <span class="bold"><strong>Boost.Thread</strong></span> library was developed to provide a C++ developer
64        with a portable interface for writing multithreaded programs on numerous
65        platforms. There's a hope that the library can be the basis for a more
66        detailed proposal for the C++ standards committee to consider for inclusion
67        in the next C++ standard.</p>
68</div>
69<div class="section" lang="en">
70<div class="titlepage"><div><div><h3 class="title">
71<a name="thread.rationale.primitives"></a>Rationale for the Low Level Primitives Supported in <span class="bold"><strong>Boost.Thread</strong></span></h3></div></div></div>
72<p>The <span class="bold"><strong>Boost.Thread</strong></span> library supplies a set of low level primitives for
73        writing multithreaded programs, such as mutexes and condition variables. In
74        fact, the first release of <span class="bold"><strong>Boost.Thread</strong></span> supports only these low level
75        primitives. However, computer science research has shown that use of these
76        primitives is difficult since it's difficult to mathematically prove that a
77        usage pattern is correct, meaning it doesn't result in race conditions or
78        deadlocks. There are several algebras (such as CSP, CCS and Join calculus)
79        that have been developed to help write provably correct parallel
80        processes. In order to prove the correctness these processes must be coded
81        using higher level abstractions. So why does <span class="bold"><strong>Boost.Thread</strong></span> support the
82        lower level concepts?</p>
83<p>The reason is simple: the higher level concepts need to be implemented
84        using at least some of the lower level concepts. So having portable lower
85        level concepts makes it easier to develop the higher level concepts and will
86        allow researchers to experiment with various techniques.</p>
87<p>Beyond this theoretical application of higher level concepts, however,
88        the fact remains that many multithreaded programs are written using only the
89        lower level concepts, so they are useful in and of themselves, even if it's
90        hard to prove that their usage is correct. Since many users will be familiar
91        with these lower level concepts but unfamiliar with any of the higher
92        level concepts, supporting the lower level concepts provides
93        greater accessibility.</p>
94</div>
95<div class="section" lang="en">
96<div class="titlepage"><div><div><h3 class="title">
97<a name="thread.rationale.locks"></a>Rationale for the Lock Design</h3></div></div></div>
98<p>Programmers who are used to multithreaded programming issues will
99        quickly note that the <span class="bold"><strong>Boost.Thread</strong></span> design for mutex lock concepts is not
100        <a href="../thread.html#thread.glossary.thread-safe">thread-safe</a> (this is
101        clearly documented as well). At first this may seem like a serious design
102        flaw. Why have a multithreading primitive that's not thread-safe
103        itself?</p>
104<p>A lock object is not a synchronization primitive. A lock object's sole
105        responsibility is to ensure that a mutex is both locked and unlocked in a
106        manner that won't result in the common error of locking a mutex and then
107        forgetting to unlock it. This means that instances of a lock object are only
108        going to be created, at least in theory, within block scope and won't be
109        shared between threads. Only the mutex objects will be created outside of
110        block scope and/or shared between threads. Though it's possible to create a
111        lock object outside of block scope and to share it between threads, to do so
112        would not be a typical usage (in fact, to do so would likely be an
113        error). Nor are there any cases when such usage would be required.</p>
114<p>Lock objects must maintain some state information. In order to allow a
115        program to determine if a try_lock or timed_lock was successful the lock
116        object must retain state indicating the success or failure of the call made
117        in its constructor. If a lock object were to have such state and remain
118        thread-safe it would need to synchronize access to the state information
119        which would result in roughly doubling the time of most operations. Worse,
120        since checking the state can occur only by a call after construction, we'd
121        have a race condition if the lock object were shared between threads.</p>
122<p>So, to avoid the overhead of synchronizing access to the state
123        information and to avoid the race condition, the <span class="bold"><strong>Boost.Thread</strong></span> library
124        simply does nothing to make lock objects thread-safe. Instead, sharing a
125        lock object between threads results in undefined behavior. Since the only
126        proper usage of lock objects is within block scope this isn't a problem, and
127        so long as the lock object is properly used there's no danger of any
128        multithreading issues.</p>
129</div>
130<div class="section" lang="en">
131<div class="titlepage"><div><div><h3 class="title">
132<a name="thread.rationale.non-copyable"></a>Rationale for NonCopyable Thread Type</h3></div></div></div>
133<div class="toc"><dl>
134<dt><span class="section"><a href="rationale.html#thread.rationale.non-copyable.simple">1. Use case: Simple creation of a thread.</a></span></dt>
135<dt><span class="section"><a href="rationale.html#thread.rationale.non-copyable.joined">2. Use case: Creation of a thread that's later joined.</a></span></dt>
136<dt><span class="section"><a href="rationale.html#thread.rationale.non-copyable.loop">3. Use case: Simple creation of several threads in a loop.</a></span></dt>
137<dt><span class="section"><a href="rationale.html#thread.rationale.non-copyable.loop-join">4. Use case: Creation of several threads in a loop which are later joined.</a></span></dt>
138<dt><span class="section"><a href="rationale.html#thread.rationale.non-copyable.pass">5. Use case: Creation of a thread whose ownership is passed to another object/method.</a></span></dt>
139<dt><span class="section"><a href="rationale.html#thread.rationale.non-copyable.shared">6. Use case: Creation of a thread whose ownership is shared between multiple
140          objects.</a></span></dt>
141<dt><span class="section"><a href="rationale.html#thread.rationale_comparison.non-copyable.simple">1. Comparison: simple creation of a thread.</a></span></dt>
142<dt><span class="section"><a href="rationale.html#thread.rationale_comparison.non-copyable.joined">2. Comparison: creation of a thread that's later joined.</a></span></dt>
143<dt><span class="section"><a href="rationale.html#thread.rationale_comparison.non-copyable.loop">3. Comparison: simple creation of several threads in a loop.</a></span></dt>
144<dt><span class="section"><a href="rationale.html#thread.rationale_comparison.non-copyable.loop-join">4. Comparison: creation of several threads in a loop which are later joined.</a></span></dt>
145<dt><span class="section"><a href="rationale.html#thread.rationale_comparison.non-copyable.pass">5. Comparison: creation of a thread whose ownership is passed to another object/method.</a></span></dt>
146<dt><span class="section"><a href="rationale.html#thread.rationale_comparison.non-copyable.shared">6. Comparison: creation of a thread whose ownership is shared
147          between multiple objects.</a></span></dt>
148</dl></div>
149<p>Programmers who are used to C libraries for multithreaded programming
150        are likely to wonder why <span class="bold"><strong>Boost.Thread</strong></span> uses a noncopyable design for
151        <code class="computeroutput"><a href="../boost/thread.html" title="Class thread">boost::thread</a></code>. After all, the C thread types are
152        copyable, and you often have a need for copying them within user
153        code. However, careful comparison of C designs to C++ designs shows a flaw
154        in this logic.</p>
155<p>All C types are copyable. It is, in fact, not possible to make a
156        noncopyable type in C. For this reason types that represent system resources
157        in C are often designed to behave very similarly to a pointer to dynamic
158        memory. There's an API for acquiring the resource and an API for releasing
159        the resource. For memory we have pointers as the type and alloc/free for
160        the acquisition and release APIs. For files we have FILE* as the type and
161        fopen/fclose for the acquisition and release APIs. You can freely copy
162        instances of the types but must manually manage the lifetime of the actual
163        resource through the acquisition and release APIs.</p>
164<p>C++ designs recognize that the acquisition and release APIs are error
165        prone and try to eliminate possible errors by acquiring the resource in the
166        constructor and releasing it in the destructor. The best example of such a
167        design is the std::iostream set of classes which can represent the same
168        resource as the FILE* type in C. A file is opened in the std::fstream's
169        constructor and closed in its destructor. However, if an iostream were
170        copyable it could lead to a file being closed twice, an obvious error, so
171        the std::iostream types are noncopyable by design. This is the same design
172        used by boost::thread, which is a simple and easy to understand design
173        that's consistent with other C++ standard types.</p>
174<p>During the design of boost::thread it was pointed out that it would be
175        possible to allow it to be a copyable type if some form of "reference
176        management" were used, such as ref-counting or ref-lists, and many argued
177        for a boost::thread_ref design instead. The reasoning was that copying
178        "thread" objects was a typical need in the C libraries, and so presumably
179        would be in the C++ libraries as well. It was also thought that
180        implementations could provide more efficient reference management than
181        wrappers (such as boost::shared_ptr) around a noncopyable thread
182        concept. Analysis of whether or not these arguments would hold true doesn't
183        appear to bear them out. To illustrate the analysis we'll first provide
184        pseudo-code illustrating the six typical usage patterns of a thread
185        object.</p>
186<div class="section" lang="en">
187<div class="titlepage"><div><div><h4 class="title">
188<a name="thread.rationale.non-copyable.simple"></a>1. Use case: Simple creation of a thread.</h4></div></div></div>
189<pre class="programlisting">
190      void foo()
191      {
192         create_thread(&amp;bar);
193      }
194      </pre>
195</div>
196<div class="section" lang="en">
197<div class="titlepage"><div><div><h4 class="title">
198<a name="thread.rationale.non-copyable.joined"></a>2. Use case: Creation of a thread that's later joined.</h4></div></div></div>
199<pre class="programlisting">
200      void foo()
201      {
202         thread = create_thread(&amp;bar);
203         join(thread);
204      }
205      </pre>
206</div>
207<div class="section" lang="en">
208<div class="titlepage"><div><div><h4 class="title">
209<a name="thread.rationale.non-copyable.loop"></a>3. Use case: Simple creation of several threads in a loop.</h4></div></div></div>
210<pre class="programlisting">
211      void foo()
212      {
213         for (int i=0; i&lt;NUM_THREADS; ++i)
214            create_thread(&amp;bar);
215      }
216      </pre>
217</div>
218<div class="section" lang="en">
219<div class="titlepage"><div><div><h4 class="title">
220<a name="thread.rationale.non-copyable.loop-join"></a>4. Use case: Creation of several threads in a loop which are later joined.</h4></div></div></div>
221<pre class="programlisting">
222      void foo()
223      {
224         for (int i=0; i&lt;NUM_THREADS; ++i)
225            threads[i] = create_thread(&amp;bar);
226         for (int i=0; i&lt;NUM_THREADS; ++i)
227            threads[i].join();
228      }
229      </pre>
230</div>
231<div class="section" lang="en">
232<div class="titlepage"><div><div><h4 class="title">
233<a name="thread.rationale.non-copyable.pass"></a>5. Use case: Creation of a thread whose ownership is passed to another object/method.</h4></div></div></div>
234<pre class="programlisting">
235      void foo()
236      {
237         thread = create_thread(&amp;bar);
238         manager.owns(thread);
239      }
240      </pre>
241</div>
242<div class="section" lang="en">
243<div class="titlepage"><div><div><h4 class="title">
244<a name="thread.rationale.non-copyable.shared"></a>6. Use case: Creation of a thread whose ownership is shared between multiple
245          objects.</h4></div></div></div>
246<pre class="programlisting">
247      void foo()
248      {
249         thread = create_thread(&amp;bar);
250         manager1.add(thread);
251         manager2.add(thread);
252      }
253      </pre>
254</div>
255<p>Of these usage patterns there's only one that requires reference
256        management (number 6). Hopefully it's fairly obvious that this usage pattern
257        simply won't occur as often as the other usage patterns. So there really
258        isn't a "typical need" for a thread concept, though there is some
259        need.</p>
260<p>Since the need isn't typical we must use different criteria for
261        deciding on either a thread_ref or thread design. Possible criteria include
262        ease of use and performance. So let's analyze both of these
263        carefully.</p>
264<p>With ease of use we can look at existing experience. The standard C++
265        objects that represent a system resource, such as std::iostream, are
266        noncopyable, so we know that C++ programmers must at least be experienced
267        with this design. Most C++ developers are also used to smart pointers such
268        as boost::shared_ptr, so we know they can at least adapt to a thread_ref
269        concept with little effort. So existing experience isn't going to lead us to
270        a choice.</p>
271<p>The other thing we can look at is how difficult it is to use both
272        types for the six usage patterns above. If we find it overly difficult to
273        use a concept for any of the usage patterns there would be a good argument
274        for choosing the other design. So we'll code all six usage patterns using
275        both designs.</p>
276<div class="section" lang="en">
277<div class="titlepage"><div><div><h4 class="title">
278<a name="thread.rationale_comparison.non-copyable.simple"></a>1. Comparison: simple creation of a thread.</h4></div></div></div>
279<pre class="programlisting">
280      void foo()
281      {
282         thread thrd(&amp;bar);
283      }
284      void foo()
285      {
286         thread_ref thrd = create_thread(&amp;bar);
287      }
288      </pre>
289</div>
290<div class="section" lang="en">
291<div class="titlepage"><div><div><h4 class="title">
292<a name="thread.rationale_comparison.non-copyable.joined"></a>2. Comparison: creation of a thread that's later joined.</h4></div></div></div>
293<pre class="programlisting">
294      void foo()
295      {
296         thread thrd(&amp;bar);
297         thrd.join();
298      }
299      void foo()
300      {
301         thread_ref thrd =
302         create_thread(&amp;bar);thrd-&gt;join();
303      }
304      </pre>
305</div>
306<div class="section" lang="en">
307<div class="titlepage"><div><div><h4 class="title">
308<a name="thread.rationale_comparison.non-copyable.loop"></a>3. Comparison: simple creation of several threads in a loop.</h4></div></div></div>
309<pre class="programlisting">
310      void foo()
311      {
312         for (int i=0; i&lt;NUM_THREADS; ++i)
313            thread thrd(&amp;bar);
314      }
315      void foo()
316      {
317         for (int i=0; i&lt;NUM_THREADS; ++i)
318            thread_ref thrd = create_thread(&amp;bar);
319      }
320      </pre>
321</div>
322<div class="section" lang="en">
323<div class="titlepage"><div><div><h4 class="title">
324<a name="thread.rationale_comparison.non-copyable.loop-join"></a>4. Comparison: creation of several threads in a loop which are later joined.</h4></div></div></div>
325<pre class="programlisting">
326      void foo()
327      {
328         std::auto_ptr&lt;thread&gt; threads[NUM_THREADS];
329         for (int i=0; i&lt;NUM_THREADS; ++i)
330            threads[i] = std::auto_ptr&lt;thread&gt;(new thread(&amp;bar));
331         for (int i= 0; i&lt;NUM_THREADS;
332             ++i)threads[i]-&gt;join();
333      }
334      void foo()
335      {
336         thread_ref threads[NUM_THREADS];
337         for (int i=0; i&lt;NUM_THREADS; ++i)
338            threads[i] = create_thread(&amp;bar);
339         for (int i= 0; i&lt;NUM_THREADS;
340            ++i)threads[i]-&gt;join();
341      }
342      </pre>
343</div>
344<div class="section" lang="en">
345<div class="titlepage"><div><div><h4 class="title">
346<a name="thread.rationale_comparison.non-copyable.pass"></a>5. Comparison: creation of a thread whose ownership is passed to another object/method.</h4></div></div></div>
347<pre class="programlisting">
348      void foo()
349      {
350         thread thrd* = new thread(&amp;bar);
351         manager.owns(thread);
352      }
353      void foo()
354      {
355         thread_ref thrd = create_thread(&amp;bar);
356         manager.owns(thrd);
357      }
358      </pre>
359</div>
360<div class="section" lang="en">
361<div class="titlepage"><div><div><h4 class="title">
362<a name="thread.rationale_comparison.non-copyable.shared"></a>6. Comparison: creation of a thread whose ownership is shared
363          between multiple objects.</h4></div></div></div>
364<pre class="programlisting">
365      void foo()
366      {
367         boost::shared_ptr&lt;thread&gt; thrd(new thread(&amp;bar));
368         manager1.add(thrd);
369         manager2.add(thrd);
370      }
371      void foo()
372      {
373         thread_ref thrd = create_thread(&amp;bar);
374         manager1.add(thrd);
375         manager2.add(thrd);
376      }
377      </pre>
378</div>
379<p>This shows the usage patterns being nearly identical in complexity for
380        both designs. The only actual added complexity occurs because of the use of
381        operator new in
382        <a href="rationale.html#thread.rationale_comparison.non-copyable.loop-join" title="4. Comparison: creation of several threads in a loop which are later joined.">(4)</a>,
383        <a href="rationale.html#thread.rationale_comparison.non-copyable.pass" title="5. Comparison: creation of a thread whose ownership is passed to another object/method.">(5)</a>, and
384        <a href="rationale.html#thread.rationale_comparison.non-copyable.shared" title="6. Comparison: creation of a thread whose ownership is shared
385          between multiple objects.">(6)</a>;
386        and the use of std::auto_ptr and boost::shared_ptr in
387        <a href="rationale.html#thread.rationale_comparison.non-copyable.loop-join" title="4. Comparison: creation of several threads in a loop which are later joined.">(4)</a> and
388        <a href="rationale.html#thread.rationale_comparison.non-copyable.shared" title="6. Comparison: creation of a thread whose ownership is shared
389          between multiple objects.">(6)</a>
390        respectively. However, that's not really
391        much added complexity, and C++ programmers are used to using these idioms
392        anyway. Some may dislike the presence of operator new in user code, but
393        this can be eliminated by proper design of higher level concepts, such as
394        the boost::thread_group class that simplifies example
395        <a href="rationale.html#thread.rationale_comparison.non-copyable.loop-join" title="4. Comparison: creation of several threads in a loop which are later joined.">(4)</a>
396        down to:</p>
397<pre class="programlisting">
398    void foo()
399    {
400       thread_group threads;
401       for (int i=0; i&lt;NUM_THREADS; ++i)
402          threads.create_thread(&amp;bar);
403       threads.join_all();
404    }
405    </pre>
406<p>So ease of use is really a wash and not much help in picking a
407        design.</p>
408<p>So what about performance? Looking at the above code examples,
409    we can analyze the theoretical impact to performance that both designs
410        have. For <a href="rationale.html#thread.rationale_comparison.non-copyable.simple" title="1. Comparison: simple creation of a thread.">(1)</a>
411        we can see that platforms that don't have a ref-counted native
412        thread type (POSIX, for instance) will be impacted by a thread_ref
413        design. Even if the native thread type is ref-counted there may be an impact
414        if more state information has to be maintained for concepts foreign to the
415        native API, such as clean up stacks for Win32 implementations.
416        For <a href="rationale.html#thread.rationale_comparison.non-copyable.joined" title="2. Comparison: creation of a thread that's later joined.">(2)</a>
417        and <a href="rationale.html#thread.rationale_comparison.non-copyable.loop" title="3. Comparison: simple creation of several threads in a loop.">(3)</a>
418        the performance impact will be identical to
419        <a href="rationale.html#thread.rationale_comparison.non-copyable.simple" title="1. Comparison: simple creation of a thread.">(1)</a>.
420        For <a href="rationale.html#thread.rationale_comparison.non-copyable.loop-join" title="4. Comparison: creation of several threads in a loop which are later joined.">(4)</a>
421        things get a little more interesting and we find that theoretically at least
422        the thread_ref may perform faster since the thread design requires dynamic
423        memory allocation/deallocation. However, in practice there may be dynamic
424        allocation for the thread_ref design as well, it will just be hidden from
425        the user. As long as the implementation has to do dynamic allocations the
426        thread_ref loses again because of the reference management. For
427        <a href="rationale.html#thread.rationale_comparison.non-copyable.pass" title="5. Comparison: creation of a thread whose ownership is passed to another object/method.">(5)</a> we see
428        the same impact as we do for
429        <a href="rationale.html#thread.rationale_comparison.non-copyable.loop-join" title="4. Comparison: creation of several threads in a loop which are later joined.">(4)</a>.
430        For <a href="rationale.html#thread.rationale_comparison.non-copyable.shared" title="6. Comparison: creation of a thread whose ownership is shared
431          between multiple objects.">(6)</a>
432        we still have a possible impact to
433        the thread design because of dynamic allocation but thread_ref no longer
434        suffers because of its reference management, and in fact, theoretically at
435        least, the thread_ref may do a better job of managing the references. All of
436        this indicates that thread wins for
437        <a href="rationale.html#thread.rationale_comparison.non-copyable.simple" title="1. Comparison: simple creation of a thread.">(1)</a>,
438        <a href="rationale.html#thread.rationale_comparison.non-copyable.joined" title="2. Comparison: creation of a thread that's later joined.">(2)</a> and
439        <a href="rationale.html#thread.rationale_comparison.non-copyable.loop" title="3. Comparison: simple creation of several threads in a loop.">(3)</a>; with
440        <a href="rationale.html#thread.rationale_comparison.non-copyable.loop-join" title="4. Comparison: creation of several threads in a loop which are later joined.">(4)</a>
441        and <a href="rationale.html#thread.rationale_comparison.non-copyable.pass" title="5. Comparison: creation of a thread whose ownership is passed to another object/method.">(5)</a> the
442        winner depending on the implementation and the platform but with the thread design
443        probably having a better chance; and with
444        <a href="rationale.html#thread.rationale_comparison.non-copyable.shared" title="6. Comparison: creation of a thread whose ownership is shared
445          between multiple objects.">(6)</a> 
446        it will again depend on the
447        implementation and platform but this time we favor thread_ref
448        slightly. Given all of this it's a narrow margin, but the thread design
449        prevails.</p>
450<p>Given this analysis, and the fact that noncopyable objects for system
451        resources are the normal designs that C++ programmers are used to dealing
452        with, the <span class="bold"><strong>Boost.Thread</strong></span> library has gone with a noncopyable design.</p>
453</div>
454<div class="section" lang="en">
455<div class="titlepage"><div><div><h3 class="title">
456<a name="thread.rationale.events"></a>Rationale for not providing <span class="emphasis"><em>Event Variables</em></span></h3></div></div></div>
457<p><span class="emphasis"><em>Event variables</em></span> are simply far too
458        error-prone. <code class="computeroutput"><a href="../boost/condition.html" title="Class condition">boost::condition</a></code> variables are a much safer
459        alternative. [Note that Graphical User Interface <span class="emphasis"><em>events</em></span> are
460        a different concept, and are not what is being discussed here.]</p>
461<p>Event variables were one of the first synchronization primitives. They
462        are still used today, for example, in the native Windows multithreading
463        API. Yet both respected computer science researchers and experienced
464        multithreading practitioners believe event variables are so inherently
465        error-prone that they should never be used, and thus should not be part of a
466        multithreading library.</p>
467<p>Per Brinch Hansen [<span class="citation"><a href="../thread.html#thread.bib.Hansen73">Hansen73</a></span>] analyzed event variables in some
468        detail, pointing out [emphasis his] that "<span class="emphasis"><em>event operations force
469        the programmer to be aware of the relative speeds of the sending and
470        receiving processes</em></span>". His summary:</p>
471<div class="blockquote"><blockquote class="blockquote"><p>We must therefore conclude that event variables of the previous type
472          are impractical for system design. <span class="emphasis"><em>The effect of an interaction
473          between two processes must be independent of the speed at which it is
474          carried out.</em></span></p></blockquote></div>
475<p>Experienced programmers using the Windows platform today report that
476        event variables are a continuing source of errors, even after previous bad
477        experiences caused them to be very careful in their use of event
478        variables. Overt problems can be avoided, for example, by teaming the event
479        variable with a mutex, but that may just convert a <a href="../thread.html#thread.glossary.race-condition">race condition</a> into another
480        problem, such as excessive resource use. One of the most distressing aspects
481        of the experience reports is the claim that many defects are latent. That
482        is, the programs appear to work correctly, but contain hidden timing
483        dependencies which will cause them to fail when environmental factors or
484        usage patterns change, altering relative thread timings.</p>
485<p>The decision to exclude event variables from <span class="bold"><strong>Boost.Thread</strong></span> has been
486        surprising to some Windows programmers. They have written programs which
487        work using event variables, and wonder what the problem is. It seems similar
488        to the "goto considered harmful" controversy of 30 years ago. It isn't that
489        events, like gotos, can't be made to work, but rather that virtually all
490        programs using alternatives will be easier to write, debug, read, maintain,
491        and will be less likely to contain latent defects.</p>
492<p>[Rationale provided by Beman Dawes]</p>
493</div>
494</div>
495<table width="100%"><tr>
496<td align="left"><small><p>Last revised: October 15, 2006 at 14:52:53 GMT</p></small></td>
497<td align="right"><small>Copyright © 2001-2003 William E. Kempf</small></td>
498</tr></table>
499<hr>
500<div class="spirit-nav">
501<a accesskey="p" href="concepts.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../thread.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="reference.html"><img src="../images/next.png" alt="Next"></a>
502</div>
503</body>
504</html>
Note: See TracBrowser for help on using the repository browser.