[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(&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(&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<NUM_THREADS; ++i) |
---|
| 214 | create_thread(&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<NUM_THREADS; ++i) |
---|
| 225 | threads[i] = create_thread(&bar); |
---|
| 226 | for (int i=0; i<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(&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(&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(&bar); |
---|
| 283 | } |
---|
| 284 | void foo() |
---|
| 285 | { |
---|
| 286 | thread_ref thrd = create_thread(&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(&bar); |
---|
| 297 | thrd.join(); |
---|
| 298 | } |
---|
| 299 | void foo() |
---|
| 300 | { |
---|
| 301 | thread_ref thrd = |
---|
| 302 | create_thread(&bar);thrd->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<NUM_THREADS; ++i) |
---|
| 313 | thread thrd(&bar); |
---|
| 314 | } |
---|
| 315 | void foo() |
---|
| 316 | { |
---|
| 317 | for (int i=0; i<NUM_THREADS; ++i) |
---|
| 318 | thread_ref thrd = create_thread(&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<thread> threads[NUM_THREADS]; |
---|
| 329 | for (int i=0; i<NUM_THREADS; ++i) |
---|
| 330 | threads[i] = std::auto_ptr<thread>(new thread(&bar)); |
---|
| 331 | for (int i= 0; i<NUM_THREADS; |
---|
| 332 | ++i)threads[i]->join(); |
---|
| 333 | } |
---|
| 334 | void foo() |
---|
| 335 | { |
---|
| 336 | thread_ref threads[NUM_THREADS]; |
---|
| 337 | for (int i=0; i<NUM_THREADS; ++i) |
---|
| 338 | threads[i] = create_thread(&bar); |
---|
| 339 | for (int i= 0; i<NUM_THREADS; |
---|
| 340 | ++i)threads[i]->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(&bar); |
---|
| 351 | manager.owns(thread); |
---|
| 352 | } |
---|
| 353 | void foo() |
---|
| 354 | { |
---|
| 355 | thread_ref thrd = create_thread(&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<thread> thrd(new thread(&bar)); |
---|
| 368 | manager1.add(thrd); |
---|
| 369 | manager2.add(thrd); |
---|
| 370 | } |
---|
| 371 | void foo() |
---|
| 372 | { |
---|
| 373 | thread_ref thrd = create_thread(&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<NUM_THREADS; ++i) |
---|
| 402 | threads.create_thread(&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> |
---|