1 | <html> |
---|
2 | <head> |
---|
3 | <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> |
---|
4 | <title>Chapter 15. Boost.Thread</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="libraries.html" title="Part I. The Boost C++ Libraries (BoostBook Subset)"> |
---|
9 | <link rel="prev" href="string_algo/credits.html" title="Credits"> |
---|
10 | <link rel="next" href="thread/design.html" title="Design"> |
---|
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="string_algo/credits.html"><img src="images/prev.png" alt="Prev"></a><a accesskey="u" href="libraries.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="thread/design.html"><img src="images/next.png" alt="Next"></a> |
---|
24 | </div> |
---|
25 | <div class="chapter" lang="en"> |
---|
26 | <div class="titlepage"><div> |
---|
27 | <div><h2 class="title"> |
---|
28 | <a name="thread"></a>Chapter 15. Boost.Thread</h2></div> |
---|
29 | <div><div class="author"><h3 class="author"> |
---|
30 | <span class="firstname">William</span> <span class="othername">E.</span> <span class="surname">Kempf</span> |
---|
31 | </h3></div></div> |
---|
32 | <div><p class="copyright">Copyright © 2001-2003 William E. Kempf</p></div> |
---|
33 | <div><div class="legalnotice"> |
---|
34 | <a name="id1709814"></a><p>Subject to the Boost Software License, Version 1.0. |
---|
35 | (See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)</p> |
---|
36 | </div></div> |
---|
37 | </div></div> |
---|
38 | <div class="toc"> |
---|
39 | <p><b>Table of Contents</b></p> |
---|
40 | <dl> |
---|
41 | <dt><span class="section"><a href="thread.html#thread.overview">Overview</a></span></dt> |
---|
42 | <dd><dl> |
---|
43 | <dt><span class="section"><a href="thread.html#thread.introduction">Introduction</a></span></dt> |
---|
44 | <dt><span class="section"><a href="thread.html#id1709909">Dangers</a></span></dt> |
---|
45 | <dt><span class="section"><a href="thread.html#id1710137">C++ Standard Library usage in multithreaded programs</a></span></dt> |
---|
46 | <dt><span class="section"><a href="thread.html#id1710320">Common guarantees for all <span class="bold"><strong>Boost.Thread</strong></span> components</a></span></dt> |
---|
47 | </dl></dd> |
---|
48 | <dt><span class="section"><a href="thread/design.html">Design</a></span></dt> |
---|
49 | <dd><dl> |
---|
50 | <dt><span class="section"><a href="thread/design.html#thread.design.goals">Goals</a></span></dt> |
---|
51 | <dt><span class="section"><a href="thread/design.html#id1710673">Iterative Phases</a></span></dt> |
---|
52 | <dt><span class="section"><a href="thread/design.html#id1710717">Phase 1, Synchronization Primitives</a></span></dt> |
---|
53 | <dt><span class="section"><a href="thread/design.html#thread.design.phase2">Phase 2, Thread Management and Thread Specific Storage</a></span></dt> |
---|
54 | <dt><span class="section"><a href="thread/design.html#id1710888">The Next Phase</a></span></dt> |
---|
55 | </dl></dd> |
---|
56 | <dt><span class="section"><a href="thread/concepts.html">Concepts</a></span></dt> |
---|
57 | <dd><dl> |
---|
58 | <dt><span class="section"><a href="thread/concepts.html#thread.concepts.mutexes">Mutexes</a></span></dt> |
---|
59 | <dt><span class="section"><a href="thread/concepts.html#thread.concepts.read-write-mutexes">Read/Write Mutexes</a></span></dt> |
---|
60 | </dl></dd> |
---|
61 | <dt><span class="section"><a href="thread/rationale.html">Rationale</a></span></dt> |
---|
62 | <dd><dl> |
---|
63 | <dt><span class="section"><a href="thread/rationale.html#thread.rationale.Boost.Thread">Rationale for the Creation of <span class="bold"><strong>Boost.Thread</strong></span></a></span></dt> |
---|
64 | <dt><span class="section"><a href="thread/rationale.html#thread.rationale.primitives">Rationale for the Low Level Primitives Supported in <span class="bold"><strong>Boost.Thread</strong></span></a></span></dt> |
---|
65 | <dt><span class="section"><a href="thread/rationale.html#thread.rationale.locks">Rationale for the Lock Design</a></span></dt> |
---|
66 | <dt><span class="section"><a href="thread/rationale.html#thread.rationale.non-copyable">Rationale for NonCopyable Thread Type</a></span></dt> |
---|
67 | <dt><span class="section"><a href="thread/rationale.html#thread.rationale.events">Rationale for not providing <span class="emphasis"><em>Event Variables</em></span></a></span></dt> |
---|
68 | </dl></dd> |
---|
69 | <dt><span class="section"><a href="thread/reference.html">Reference</a></span></dt> |
---|
70 | <dd><dl> |
---|
71 | <dt><span class="section"><a href="thread/reference.html#header.boost.thread.barrier.hpp">Header <boost/thread/barrier.hpp></a></span></dt> |
---|
72 | <dt><span class="section"><a href="thread/reference.html#header.boost.thread.condition.hpp">Header <boost/thread/condition.hpp></a></span></dt> |
---|
73 | <dt><span class="section"><a href="thread/reference.html#header.boost.thread.exceptions.hpp">Header <boost/thread/exceptions.hpp></a></span></dt> |
---|
74 | <dt><span class="section"><a href="thread/reference.html#header.boost.thread.mutex.hpp">Header <boost/thread/mutex.hpp></a></span></dt> |
---|
75 | <dt><span class="section"><a href="thread/reference.html#header.boost.thread.once.hpp">Header <boost/thread/once.hpp></a></span></dt> |
---|
76 | <dt><span class="section"><a href="thread/reference.html#header.boost.thread.recursive_mutex.hpp">Header <boost/thread/recursive_mutex.hpp></a></span></dt> |
---|
77 | <dt><span class="section"><a href="thread/reference.html#header.boost.thread.read_write_mutex.hpp">Header <boost/thread/read_write_mutex.hpp></a></span></dt> |
---|
78 | <dt><span class="section"><a href="thread/reference.html#header.boost.thread.thread.hpp">Header <boost/thread/thread.hpp></a></span></dt> |
---|
79 | <dt><span class="section"><a href="thread/reference.html#header.boost.thread.tss.hpp">Header <boost/thread/tss.hpp></a></span></dt> |
---|
80 | <dt><span class="section"><a href="thread/reference.html#header.boost.thread.xtime.hpp">Header <boost/thread/xtime.hpp></a></span></dt> |
---|
81 | </dl></dd> |
---|
82 | <dt><span class="section"><a href="thread/faq.html">Frequently Asked Questions</a></span></dt> |
---|
83 | <dt><span class="section"><a href="thread/configuration.html">Configuration</a></span></dt> |
---|
84 | <dd><dl> |
---|
85 | <dt><span class="section"><a href="thread/configuration.html#thread.configuration.public">Library Defined Public Macros</a></span></dt> |
---|
86 | <dt><span class="section"><a href="thread/configuration.html#thread.configuration.implementation">Library Defined Implementation Macros</a></span></dt> |
---|
87 | </dl></dd> |
---|
88 | <dt><span class="section"><a href="thread/build.html">Build</a></span></dt> |
---|
89 | <dd><dl> |
---|
90 | <dt><span class="section"><a href="thread/build.html#thread.build.building">Building the <span class="bold"><strong>Boost.Thread</strong></span> Libraries</a></span></dt> |
---|
91 | <dt><span class="section"><a href="thread/build.html#thread.build.testing">Testing the <span class="bold"><strong>Boost.Thread</strong></span> Libraries</a></span></dt> |
---|
92 | </dl></dd> |
---|
93 | <dt><span class="section"><a href="thread/implementation_notes.html">Implementation Notes</a></span></dt> |
---|
94 | <dd><dl><dt><span class="section"><a href="thread/implementation_notes.html#thread.implementation_notes.win32">Win32</a></span></dt></dl></dd> |
---|
95 | <dt><span class="section"><a href="thread/release_notes.html">Release Notes</a></span></dt> |
---|
96 | <dd><dl> |
---|
97 | <dt><span class="section"><a href="thread/release_notes.html#thread.release_notes.boost_1_34_0">Boost 1.34.0</a></span></dt> |
---|
98 | <dt><span class="section"><a href="thread/release_notes.html#thread.release_notes.boost_1_32_0">Boost 1.32.0</a></span></dt> |
---|
99 | </dl></dd> |
---|
100 | <dt><span class="glossary"><a href="thread.html#thread.glossary">Glossary</a></span></dt> |
---|
101 | <dt><span class="section"><a href="thread/acknowledgements.html">Acknowledgements</a></span></dt> |
---|
102 | <dt><span class="bibliography"><a href="thread.html#thread.bibliography">Bibliography</a></span></dt> |
---|
103 | </dl> |
---|
104 | </div> |
---|
105 | <div class="section" lang="en"> |
---|
106 | <div class="titlepage"><div><div><h2 class="title" style="clear: both"> |
---|
107 | <a name="thread.overview"></a>Overview</h2></div></div></div> |
---|
108 | <div class="toc"><dl> |
---|
109 | <dt><span class="section"><a href="thread.html#thread.introduction">Introduction</a></span></dt> |
---|
110 | <dt><span class="section"><a href="thread.html#id1709909">Dangers</a></span></dt> |
---|
111 | <dt><span class="section"><a href="thread.html#id1710137">C++ Standard Library usage in multithreaded programs</a></span></dt> |
---|
112 | <dt><span class="section"><a href="thread.html#id1710320">Common guarantees for all <span class="bold"><strong>Boost.Thread</strong></span> components</a></span></dt> |
---|
113 | </dl></div> |
---|
114 | <div class="section" lang="en"> |
---|
115 | <div class="titlepage"><div><div><h3 class="title"> |
---|
116 | <a name="thread.introduction"></a>Introduction</h3></div></div></div> |
---|
117 | <p><span class="bold"><strong>Boost.Thread</strong></span> allows C++ programs to execute as multiple, |
---|
118 | asynchronous, independent threads-of-execution. Each thread has its own |
---|
119 | machine state including program instruction counter and registers. Programs |
---|
120 | which execute as multiple threads are called multithreaded programs to |
---|
121 | distinguish them from traditional single-threaded programs. The <a href="thread.html#thread.glossary" title="Glossary">glossary</a> gives a more complete description |
---|
122 | of the multithreading execution environment.</p> |
---|
123 | <p>Multithreading provides several advantages: |
---|
124 | </p> |
---|
125 | <div class="itemizedlist"><ul type="disc"> |
---|
126 | <li><p>Programs which would otherwise block waiting for some external |
---|
127 | event can continue to respond if the blocking operation is placed in a |
---|
128 | separate thread. Multithreading is usually an absolute requirement for |
---|
129 | these programs.</p></li> |
---|
130 | <li><p>Well-designed multithreaded programs may execute faster than |
---|
131 | single-threaded programs, particularly on multiprocessor hardware. |
---|
132 | Note, however, that poorly-designed multithreaded programs are often |
---|
133 | slower than single-threaded programs.</p></li> |
---|
134 | <li><p>Some program designs may be easier to formulate using a |
---|
135 | multithreaded approach. After all, the real world is |
---|
136 | asynchronous!</p></li> |
---|
137 | </ul></div> |
---|
138 | </div> |
---|
139 | <div class="section" lang="en"> |
---|
140 | <div class="titlepage"><div><div><h3 class="title"> |
---|
141 | <a name="id1709909"></a>Dangers</h3></div></div></div> |
---|
142 | <div class="toc"><dl> |
---|
143 | <dt><span class="section"><a href="thread.html#id1709914">General considerations</a></span></dt> |
---|
144 | <dt><span class="section"><a href="thread.html#id1710011">Testing and debugging considerations</a></span></dt> |
---|
145 | <dt><span class="section"><a href="thread.html#id1710070">Getting a head start</a></span></dt> |
---|
146 | </dl></div> |
---|
147 | <div class="section" lang="en"> |
---|
148 | <div class="titlepage"><div><div><h4 class="title"> |
---|
149 | <a name="id1709914"></a>General considerations</h4></div></div></div> |
---|
150 | <p>Beyond the errors which can occur in single-threaded programs, |
---|
151 | multithreaded programs are subject to additional errors: |
---|
152 | </p> |
---|
153 | <div class="itemizedlist"><ul type="disc"> |
---|
154 | <li><p><a href="thread.html#thread.glossary.race-condition">Race |
---|
155 | conditions</a></p></li> |
---|
156 | <li><p><a href="thread.html#thread.glossary.deadlock">Deadlock</a> |
---|
157 | (sometimes called "deadly embrace")</p></li> |
---|
158 | <li><p><a href="thread.html#thread.glossary.priority-failure">Priority |
---|
159 | failures</a> (priority inversion, infinite overtaking, starvation, |
---|
160 | etc.)</p></li> |
---|
161 | </ul></div> |
---|
162 | <p>Every multithreaded program must be designed carefully to avoid these |
---|
163 | errors. These aren't rare or exotic failures - they are virtually guaranteed |
---|
164 | to occur unless multithreaded code is designed to avoid them. Priority |
---|
165 | failures are somewhat less common, but are nonetheless serious.</p> |
---|
166 | <p>The <a href="thread/design.html" title="Design"><span class="bold"><strong>Boost.Thread</strong></span> design</a> |
---|
167 | attempts to minimize these errors, but they will still occur unless the |
---|
168 | programmer proactively designs to avoid them.</p> |
---|
169 | <div class="note"><table border="0" summary="Note"> |
---|
170 | <tr> |
---|
171 | <td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td> |
---|
172 | <th align="left">Note</th> |
---|
173 | </tr> |
---|
174 | <tr><td align="left" valign="top">Please also see <a href="thread/implementation_notes.html" title="Implementation Notes">the section called “Implementation Notes”</a> |
---|
175 | for additional, implementation-specific considerations.</td></tr> |
---|
176 | </table></div> |
---|
177 | </div> |
---|
178 | <div class="section" lang="en"> |
---|
179 | <div class="titlepage"><div><div><h4 class="title"> |
---|
180 | <a name="id1710011"></a>Testing and debugging considerations</h4></div></div></div> |
---|
181 | <p>Multithreaded programs are non-deterministic. In other words, the |
---|
182 | same program with the same input data may follow different execution |
---|
183 | paths each time it is invoked. That can make testing and debugging a |
---|
184 | nightmare: |
---|
185 | </p> |
---|
186 | <div class="itemizedlist"><ul type="disc"> |
---|
187 | <li><p>Failures are often not repeatable.</p></li> |
---|
188 | <li><p>Probe effect causes debuggers to produce very different results |
---|
189 | from non-debug uses.</p></li> |
---|
190 | <li><p>Debuggers require special support to show thread state.</p></li> |
---|
191 | <li><p>Tests on a single processor system may give no indication of |
---|
192 | serious errors which would appear on multiprocessor systems, and visa |
---|
193 | versa. Thus test cases should include a varying number of |
---|
194 | processors.</p></li> |
---|
195 | <li><p>For programs which create a varying number of threads according |
---|
196 | to workload, tests which don't span the full range of possibilities |
---|
197 | may miss serious errors.</p></li> |
---|
198 | </ul></div> |
---|
199 | </div> |
---|
200 | <div class="section" lang="en"> |
---|
201 | <div class="titlepage"><div><div><h4 class="title"> |
---|
202 | <a name="id1710070"></a>Getting a head start</h4></div></div></div> |
---|
203 | <p>Although it might appear that multithreaded programs are inherently |
---|
204 | unreliable, many reliable multithreaded programs do exist. Multithreading |
---|
205 | techniques are known which lead to reliable programs.</p> |
---|
206 | <p>Design patterns for reliable multithreaded programs, including the |
---|
207 | important <span class="emphasis"><em>monitor</em></span> pattern, are presented in |
---|
208 | <span class="emphasis"><em>Pattern-Oriented Software Architecture Volume 2 - Patterns for |
---|
209 | Concurrent and Networked Objects</em></span> |
---|
210 | [<span class="citation"><a href="thread.html#thread.bib.SchmidtStalRohnertBuschmann">SchmidtStalRohnertBuschmann</a></span>]. Many important multithreading programming |
---|
211 | considerations (independent of threading library) are discussed in |
---|
212 | <span class="emphasis"><em>Programming with POSIX Threads</em></span> [<span class="citation"><a href="thread.html#thread.bib.Butenhof97">Butenhof97</a></span>].</p> |
---|
213 | <p>Doing some reading before attempting multithreaded designs will |
---|
214 | give you a head start toward reliable multithreaded programs.</p> |
---|
215 | </div> |
---|
216 | </div> |
---|
217 | <div class="section" lang="en"> |
---|
218 | <div class="titlepage"><div><div><h3 class="title"> |
---|
219 | <a name="id1710137"></a>C++ Standard Library usage in multithreaded programs</h3></div></div></div> |
---|
220 | <div class="toc"><dl> |
---|
221 | <dt><span class="section"><a href="thread.html#id1710143">Runtime libraries</a></span></dt> |
---|
222 | <dt><span class="section"><a href="thread.html#id1710197">Potentially non-thread-safe functions</a></span></dt> |
---|
223 | </dl></div> |
---|
224 | <div class="section" lang="en"> |
---|
225 | <div class="titlepage"><div><div><h4 class="title"> |
---|
226 | <a name="id1710143"></a>Runtime libraries</h4></div></div></div> |
---|
227 | <p> |
---|
228 | <span class="bold"><strong>Warning:</strong></span> Multithreaded programs such as |
---|
229 | those using <span class="bold"><strong>Boost.Thread</strong></span> must link to <a href="thread.html#thread.glossary.thread-safe">thread-safe</a> versions of |
---|
230 | all runtime libraries used by the program, including the runtime library |
---|
231 | for the C++ Standard Library. Failure to do so will cause <a href="thread.html#thread.glossary.race-condition">race conditions</a> to occur |
---|
232 | when multiple threads simultaneously execute runtime library functions for |
---|
233 | <code class="computeroutput">new</code>, <code class="computeroutput">delete</code>, or other language features which |
---|
234 | imply shared state.</p> |
---|
235 | </div> |
---|
236 | <div class="section" lang="en"> |
---|
237 | <div class="titlepage"><div><div><h4 class="title"> |
---|
238 | <a name="id1710197"></a>Potentially non-thread-safe functions</h4></div></div></div> |
---|
239 | <p>Certain C++ Standard Library functions inherited from C are |
---|
240 | particular problems because they hold internal state between |
---|
241 | calls: |
---|
242 | </p> |
---|
243 | <div class="itemizedlist"><ul type="disc"> |
---|
244 | <li><p><code class="computeroutput">rand</code></p></li> |
---|
245 | <li><p><code class="computeroutput">strtok</code></p></li> |
---|
246 | <li><p><code class="computeroutput">asctime</code></p></li> |
---|
247 | <li><p><code class="computeroutput">ctime</code></p></li> |
---|
248 | <li><p><code class="computeroutput">gmtime</code></p></li> |
---|
249 | <li><p><code class="computeroutput">localtime</code></p></li> |
---|
250 | </ul></div> |
---|
251 | <p>It is possible to write thread-safe implementations of these by |
---|
252 | using thread specific storage (see |
---|
253 | <code class="computeroutput"><a href="boost/thread_specific_ptr.html" title="Class thread_specific_ptr">boost::thread_specific_ptr</a></code>), and several C++ |
---|
254 | compiler vendors do just that. The technique is well-know and is explained |
---|
255 | in [<span class="citation"><a href="thread.html#thread.bib.Butenhof97">Butenhof97</a></span>].</p> |
---|
256 | <p>But at least one vendor (HP-UX) does not provide thread-safe |
---|
257 | implementations of the above functions in their otherwise thread-safe |
---|
258 | runtime library. Instead they provide replacement functions with |
---|
259 | different names and arguments.</p> |
---|
260 | <p><span class="bold"><strong>Recommendation:</strong></span> For the most |
---|
261 | portable, yet thread-safe code, use Boost replacements for the problem |
---|
262 | functions. See the Boost Random Number Library |
---|
263 | and Boost Tokenizer Library.</p> |
---|
264 | </div> |
---|
265 | </div> |
---|
266 | <div class="section" lang="en"> |
---|
267 | <div class="titlepage"><div><div><h3 class="title"> |
---|
268 | <a name="id1710320"></a>Common guarantees for all <span class="bold"><strong>Boost.Thread</strong></span> components</h3></div></div></div> |
---|
269 | <div class="toc"><dl> |
---|
270 | <dt><span class="section"><a href="thread.html#id1710331">Exceptions</a></span></dt> |
---|
271 | <dt><span class="section"><a href="thread.html#id1710414">NonCopyable requirement</a></span></dt> |
---|
272 | </dl></div> |
---|
273 | <div class="section" lang="en"> |
---|
274 | <div class="titlepage"><div><div><h4 class="title"> |
---|
275 | <a name="id1710331"></a>Exceptions</h4></div></div></div> |
---|
276 | <p><span class="bold"><strong>Boost.Thread</strong></span> destructors never |
---|
277 | throw exceptions. Unless otherwise specified, other |
---|
278 | <span class="bold"><strong>Boost.Thread</strong></span> functions that do not have |
---|
279 | an exception-specification may throw implementation-defined |
---|
280 | exceptions.</p> |
---|
281 | <p>In particular, <span class="bold"><strong>Boost.Thread</strong></span> |
---|
282 | reports failure to allocate storage by throwing an exception of type |
---|
283 | <code class="computeroutput">std::bad_alloc</code> or a class derived from |
---|
284 | <code class="computeroutput">std::bad_alloc</code>, failure to obtain thread resources other than |
---|
285 | memory by throwing an exception of type |
---|
286 | <code class="computeroutput"><a href="boost/thread_resource_error.html" title="Class thread_resource_error">boost::thread_resource_error</a></code>, and certain lock |
---|
287 | related failures by throwing an exception of type |
---|
288 | <code class="computeroutput"><a href="boost/lock_error.html" title="Class lock_error">boost::lock_error</a></code>.</p> |
---|
289 | <p><span class="bold"><strong>Rationale:</strong></span> Follows the C++ Standard |
---|
290 | Library practice of allowing all functions except destructors or other |
---|
291 | specified functions to throw exceptions on errors.</p> |
---|
292 | </div> |
---|
293 | <div class="section" lang="en"> |
---|
294 | <div class="titlepage"><div><div><h4 class="title"> |
---|
295 | <a name="id1710414"></a>NonCopyable requirement</h4></div></div></div> |
---|
296 | <p><span class="bold"><strong>Boost.Thread</strong></span> classes documented as |
---|
297 | meeting the NonCopyable requirement disallow copy construction and copy |
---|
298 | assignment. For the sake of exposition, the synopsis of such classes show |
---|
299 | private derivation from <code class="computeroutput">boost::noncopyable</code>. Users |
---|
300 | should not depend on this derivation, however, as implementations are free |
---|
301 | to meet the NonCopyable requirement in other ways.</p> |
---|
302 | </div> |
---|
303 | </div> |
---|
304 | </div> |
---|
305 | <div class="glossary"> |
---|
306 | <div class="titlepage"><div><div><h2 class="title"> |
---|
307 | <a name="thread.glossary"></a>Glossary</h2></div></div></div> |
---|
308 | <p>Definitions are given in terms of the C++ Standard |
---|
309 | [<span class="citation"><a href="thread.html#thread.bib.ISO98">ISO98</a></span>]. References to the standard are in the form [1.2.3/4], which |
---|
310 | represents the section number, with the paragraph number following the |
---|
311 | "/".</p> |
---|
312 | <p>Because the definitions are written in something akin to "standardese", |
---|
313 | they can be difficult to understand. The intent isn't to confuse, but rather |
---|
314 | to clarify the additional requirements <span class="bold"><strong>Boost.Thread</strong></span> places on a C++ |
---|
315 | implementation as defined by the C++ Standard.</p> |
---|
316 | <dl> |
---|
317 | <dt> |
---|
318 | <a name="thread.glossary.thread"></a>Thread</dt> |
---|
319 | <dd> |
---|
320 | <p>Thread is short for "thread of execution". A thread of execution is |
---|
321 | an execution environment [1.9/7] within the execution environment of a C++ |
---|
322 | program [1.9]. The main() function [3.6.1] of the program is the initial |
---|
323 | function of the initial thread. A program in a multithreading environment |
---|
324 | always has an initial thread even if the program explicitly creates no |
---|
325 | additional threads.</p> |
---|
326 | <p>Unless otherwise specified, each thread shares all aspects of its |
---|
327 | execution environment with other threads in the program. Shared aspects of |
---|
328 | the execution environment include, but are not limited to, the |
---|
329 | following:</p> |
---|
330 | <div class="itemizedlist"><ul type="disc"> |
---|
331 | <li><p>Static storage duration (static, extern) objects |
---|
332 | [3.7.1].</p></li> |
---|
333 | <li><p>Dynamic storage duration (heap) objects [3.7.3]. Thus |
---|
334 | each memory allocation will return a unique addresses, regardless of the |
---|
335 | thread making the allocation request.</p></li> |
---|
336 | <li><p>Automatic storage duration (stack) objects [3.7.2] |
---|
337 | accessed via pointer or reference from another thread.</p></li> |
---|
338 | <li><p>Resources provided by the operating system. For example, |
---|
339 | files.</p></li> |
---|
340 | <li><p>The program itself. In other words, each thread is |
---|
341 | executing some function of the same program, not a totally different |
---|
342 | program.</p></li> |
---|
343 | </ul></div> |
---|
344 | <p>Each thread has its own:</p> |
---|
345 | <div class="itemizedlist"><ul type="disc"> |
---|
346 | <li><p>Registers and current execution sequence (program |
---|
347 | counter) [1.9/5].</p></li> |
---|
348 | <li><p>Automatic storage duration (stack) objects |
---|
349 | [3.7.2].</p></li> |
---|
350 | </ul></div> |
---|
351 | </dd> |
---|
352 | <dt> |
---|
353 | <a name="thread.glossary.thread-safe"></a>Thread-safe</dt> |
---|
354 | <dd> |
---|
355 | <p>A program is thread-safe if it has no <a href="thread.html#thread.glossary.race-condition">race conditions</a>, does |
---|
356 | not <a href="thread.html#thread.glossary.deadlock">deadlock</a>, and has |
---|
357 | no <a href="thread.html#thread.glossary.priority-failure">priority |
---|
358 | failures</a>.</p> |
---|
359 | <p>Note that thread-safety does not necessarily imply efficiency, and |
---|
360 | than while some thread-safety violations can be determined statically at |
---|
361 | compile time, many thread-safety errors can only only be detected at |
---|
362 | runtime.</p> |
---|
363 | </dd> |
---|
364 | <dt> |
---|
365 | <a name="thread.glossary.thread-state"></a>Thread State</dt> |
---|
366 | <dd> |
---|
367 | <p>During the lifetime of a thread, it shall be in one of the following |
---|
368 | states:</p> |
---|
369 | <div class="table"> |
---|
370 | <a name="id1766146"></a><p class="title"><b>Table 15.26. Thread States</b></p> |
---|
371 | <table class="table" summary="Thread States"> |
---|
372 | <colgroup> |
---|
373 | <col> |
---|
374 | <col> |
---|
375 | </colgroup> |
---|
376 | <thead><tr> |
---|
377 | <th align="left">State</th> |
---|
378 | <th align="left">Description</th> |
---|
379 | </tr></thead> |
---|
380 | <tbody> |
---|
381 | <tr> |
---|
382 | <td align="left">Ready</td> |
---|
383 | <td align="left">Ready to run, but waiting for a processor.</td> |
---|
384 | </tr> |
---|
385 | <tr> |
---|
386 | <td align="left">Running</td> |
---|
387 | <td align="left">Currently executing on a processor. Zero or more threads |
---|
388 | may be running at any time, with a maximum equal to the number of |
---|
389 | processors.</td> |
---|
390 | </tr> |
---|
391 | <tr> |
---|
392 | <td align="left">Blocked</td> |
---|
393 | <td align="left">Waiting for some resource other than a processor which is |
---|
394 | not currently available, or for the completion of calls to library |
---|
395 | functions [1.9/6]. The term "waiting" is synonymous with |
---|
396 | "blocked"</td> |
---|
397 | </tr> |
---|
398 | <tr> |
---|
399 | <td align="left">Terminated</td> |
---|
400 | <td align="left">Finished execution but not yet detached or joined.</td> |
---|
401 | </tr> |
---|
402 | </tbody> |
---|
403 | </table> |
---|
404 | </div> |
---|
405 | <p>Thread state transitions shall occur only as specified:</p> |
---|
406 | <div class="table"> |
---|
407 | <a name="id1766228"></a><p class="title"><b>Table 15.27. Thread States Transitions</b></p> |
---|
408 | <table class="table" summary="Thread States Transitions"> |
---|
409 | <colgroup> |
---|
410 | <col> |
---|
411 | <col> |
---|
412 | <col> |
---|
413 | </colgroup> |
---|
414 | <thead><tr> |
---|
415 | <th align="left">From</th> |
---|
416 | <th align="left">To</th> |
---|
417 | <th align="left">Cause</th> |
---|
418 | </tr></thead> |
---|
419 | <tbody> |
---|
420 | <tr> |
---|
421 | <td align="left">[none]</td> |
---|
422 | <td align="left">Ready</td> |
---|
423 | <td align="left"><p>Thread is created by a call to a library function. |
---|
424 | In the case of the initial thread, creation is implicit and |
---|
425 | occurs during the startup of the main() function [3.6.1].</p></td> |
---|
426 | </tr> |
---|
427 | <tr> |
---|
428 | <td align="left">Ready</td> |
---|
429 | <td align="left">Running</td> |
---|
430 | <td align="left"><p>Processor becomes available.</p></td> |
---|
431 | </tr> |
---|
432 | <tr> |
---|
433 | <td align="left">Running</td> |
---|
434 | <td align="left">Ready</td> |
---|
435 | <td align="left">Thread preempted.</td> |
---|
436 | </tr> |
---|
437 | <tr> |
---|
438 | <td align="left">Running</td> |
---|
439 | <td align="left">Blocked</td> |
---|
440 | <td align="left">Thread calls a library function which waits for a resource or |
---|
441 | for the completion of I/O.</td> |
---|
442 | </tr> |
---|
443 | <tr> |
---|
444 | <td align="left">Running</td> |
---|
445 | <td align="left">Terminated</td> |
---|
446 | <td align="left">Thread returns from its initial function, calls a thread |
---|
447 | termination library function, or is canceled by some other thread |
---|
448 | calling a thread termination library function.</td> |
---|
449 | </tr> |
---|
450 | <tr> |
---|
451 | <td align="left">Blocked</td> |
---|
452 | <td align="left">Ready</td> |
---|
453 | <td align="left">The resource being waited for becomes available, or the |
---|
454 | blocking library function completes.</td> |
---|
455 | </tr> |
---|
456 | <tr> |
---|
457 | <td align="left">Terminated</td> |
---|
458 | <td align="left">[none]</td> |
---|
459 | <td align="left">Thread is detached or joined by some other thread calling the |
---|
460 | appropriate library function, or by program termination |
---|
461 | [3.6.3].</td> |
---|
462 | </tr> |
---|
463 | </tbody> |
---|
464 | </table> |
---|
465 | </div> |
---|
466 | <p>[Note: if a suspend() function is added to the threading library, |
---|
467 | additional transitions to the blocked state will have to be added to the |
---|
468 | above table.]</p> |
---|
469 | </dd> |
---|
470 | <dt> |
---|
471 | <a name="thread.glossary.race-condition"></a>Race Condition</dt> |
---|
472 | <dd> |
---|
473 | <p>A race condition is what occurs when multiple threads read from and write |
---|
474 | to the same memory without proper synchronization, resulting in an incorrect |
---|
475 | value being read or written. The result of a race condition may be a bit |
---|
476 | pattern which isn't even a valid value for the data type. A race condition |
---|
477 | results in undefined behavior [1.3.12].</p> |
---|
478 | <p>Race conditions can be prevented by serializing memory access using |
---|
479 | the tools provided by <span class="bold"><strong>Boost.Thread</strong></span>.</p> |
---|
480 | </dd> |
---|
481 | <dt> |
---|
482 | <a name="thread.glossary.deadlock"></a>Deadlock</dt> |
---|
483 | <dd><p>Deadlock is an execution state where for some set of threads, each |
---|
484 | thread in the set is blocked waiting for some action by one of the other |
---|
485 | threads in the set. Since each is waiting on the others, none will ever |
---|
486 | become ready again.</p></dd> |
---|
487 | <dt> |
---|
488 | <a name="thread.glossary.starvation"></a>Starvation</dt> |
---|
489 | <dd><p>The condition in which a thread is not making sufficient progress in |
---|
490 | its work during a given time interval.</p></dd> |
---|
491 | <dt> |
---|
492 | <a name="thread.glossary.priority-failure"></a>Priority Failure</dt> |
---|
493 | <dd><p>A priority failure (such as priority inversion or infinite overtaking) |
---|
494 | occurs when threads are executed in such a sequence that required work is not |
---|
495 | performed in time to be useful.</p></dd> |
---|
496 | <dt> |
---|
497 | <a name="thread.glossary.undefined-behavior"></a>Undefined Behavior</dt> |
---|
498 | <dd> |
---|
499 | <p>The result of certain operations in <span class="bold"><strong>Boost.Thread</strong></span> is undefined; |
---|
500 | this means that those operations can invoke almost any behavior when |
---|
501 | they are executed.</p> |
---|
502 | <p>An operation whose behavior is undefined can work "correctly" |
---|
503 | in some implementations (i.e., do what the programmer thought it |
---|
504 | would do), while in other implementations it may exhibit almost |
---|
505 | any "incorrect" behavior--such as returning an invalid value, |
---|
506 | throwing an exception, generating an access violation, or terminating |
---|
507 | the process.</p> |
---|
508 | <p>Executing a statement whose behavior is undefined is a |
---|
509 | programming error.</p> |
---|
510 | </dd> |
---|
511 | <dt> |
---|
512 | <a name="thread.glossary.memory-visibility"></a>Memory Visibility</dt> |
---|
513 | <dd> |
---|
514 | <p>An address [1.7] shall always point to the same memory byte, |
---|
515 | regardless of the thread or processor dereferencing the address.</p> |
---|
516 | <p>An object [1.8, 1.9] is accessible from multiple threads if it is of |
---|
517 | static storage duration (static, extern) [3.7.1], or if a pointer or |
---|
518 | reference to it is explicitly or implicitly dereferenced in multiple |
---|
519 | threads.</p> |
---|
520 | <p>For an object accessible from multiple threads, the value of the |
---|
521 | object accessed from one thread may be indeterminate or different from the |
---|
522 | value accessed from another thread, except under the conditions specified in |
---|
523 | the following table. For the same row of the table, the value of an object |
---|
524 | accessible at the indicated sequence point in thread A will be determinate |
---|
525 | and the same if accessed at or after the indicated sequence point in thread |
---|
526 | B, provided the object is not otherwise modified. In the table, the |
---|
527 | "sequence point at a call" is the sequence point after the evaluation of all |
---|
528 | function arguments [1.9/17], while the "sequence point after a call" is the |
---|
529 | sequence point after the copying of the returned value... [1.9/17].</p> |
---|
530 | <div class="table"> |
---|
531 | <a name="id1766542"></a><p class="title"><b>Table 15.28. Memory Visibility</b></p> |
---|
532 | <table class="table" summary="Memory Visibility"> |
---|
533 | <colgroup> |
---|
534 | <col> |
---|
535 | <col> |
---|
536 | </colgroup> |
---|
537 | <thead><tr> |
---|
538 | <th>Thread A</th> |
---|
539 | <th>Thread B</th> |
---|
540 | </tr></thead> |
---|
541 | <tbody> |
---|
542 | <tr> |
---|
543 | <td>The sequence point at a call to a library thread-creation |
---|
544 | function.</td> |
---|
545 | <td>The first sequence point of the initial function in the new |
---|
546 | thread created by the Thread A call.</td> |
---|
547 | </tr> |
---|
548 | <tr> |
---|
549 | <td>The sequence point at a call to a library function which |
---|
550 | locks a mutex, directly or by waiting for a condition |
---|
551 | variable.</td> |
---|
552 | <td>The sequence point after a call to a library function which |
---|
553 | unlocks the same mutex.</td> |
---|
554 | </tr> |
---|
555 | <tr> |
---|
556 | <td>The last sequence point before thread termination.</td> |
---|
557 | <td>The sequence point after a call to a library function which |
---|
558 | joins the terminated thread.</td> |
---|
559 | </tr> |
---|
560 | <tr> |
---|
561 | <td>The sequence point at a call to a library function which |
---|
562 | signals or broadcasts a condition variable.</td> |
---|
563 | <td>The sequence point after the call to the library function |
---|
564 | which was waiting on that same condition variable or signal.</td> |
---|
565 | </tr> |
---|
566 | </tbody> |
---|
567 | </table> |
---|
568 | </div> |
---|
569 | <p>The architecture of the execution environment and the observable |
---|
570 | behavior of the abstract machine [1.9] shall be the same on all |
---|
571 | processors.</p> |
---|
572 | <p>The latitude granted by the C++ standard for an implementation to |
---|
573 | alter the definition of observable behavior of the abstract machine to |
---|
574 | include additional library I/O functions [1.9/6] is extended to include |
---|
575 | threading library functions.</p> |
---|
576 | <p>When an exception is thrown and there is no matching exception handler |
---|
577 | in the same thread, behavior is undefined. The preferred behavior is the |
---|
578 | same as when there is no matching exception handler in a program |
---|
579 | [15.3/9]. That is, terminate() is called, and it is implementation-defined |
---|
580 | whether or not the stack is unwound.</p> |
---|
581 | </dd> |
---|
582 | </dl> |
---|
583 | </div> |
---|
584 | <div class="bibliography"> |
---|
585 | <div class="titlepage"><div><div><h2 class="title"> |
---|
586 | <a name="thread.bibliography"></a>Bibliography</h2></div></div></div> |
---|
587 | <div class="biblioentry"> |
---|
588 | <a name="thread.bib.AndrewsSchneider83"></a><p>[<span class="abbrev"><a name="thread.bib.AndrewsSchneider83.abbrev"></a>AndrewsSchnieder83</span>] <span class="biblioset"><i>ACM Computing Surveys</i>. <span class="volumenum">Vol. 15. </span><span class="issuenum">No. 1. </span><span class="date">March, 1983. </span></span><span class="biblioset"><span class="authorgroup"><span class="firstname">Gregory</span> <span class="othername">R.</span> <span class="surname">Andrews</span> and <span class="firstname">Fred</span> <span class="othername">B.</span> <span class="surname">Schneider</span>. </span>“ |
---|
589 | <a href="http://www.acm.org/pubs/citations/journals/surveys/1983-15-1/p3-andrews/" target="_top">Concepts and Notations for Concurrent Programming</a> |
---|
590 | ”. </span><p>Good general background reading. Includes descriptions of Path |
---|
591 | Expressions, Message Passing, and Remote Procedure Call in addition to the |
---|
592 | basics</p></p> |
---|
593 | </div> |
---|
594 | <div class="biblioentry"> |
---|
595 | <a name="thread.bib.Boost"></a><p>[<span class="abbrev"><a name="thread.bib.Boost.abbrev"></a>Boost</span>] <span class="bibliomisc">The <span class="emphasis"><em>Boost</em></span> world wide web site. |
---|
596 | <a href="http:/www.boost.org" target="_top">http://www.boost.org</a>. </span><p><span class="bold"><strong>Boost.Thread</strong></span> is one of many Boost libraries. The Boost web |
---|
597 | site includes a great deal of documentation and general information which |
---|
598 | applies to all Boost libraries. Current copies of the libraries including |
---|
599 | documentation and test programs may be downloaded from the web |
---|
600 | site.</p></p> |
---|
601 | </div> |
---|
602 | <div class="biblioentry"> |
---|
603 | <a name="thread.bib.Hansen73"></a><p>[<span class="abbrev"><a name="thread.bib.Hansen73.abbrev"></a>Hansen73</span>] <span class="biblioset"><i>ACM Computing Surveys</i>. <span class="volumenum">Vol. 5. </span><span class="issuenum">No. 4. </span><span class="date">December, 1973. </span></span><span class="biblioset"><span class="author"><span class="firstname">Per Brinch</span>. </span>“ |
---|
604 | <a href="http://www.acm.org/pubs/articles/journals/surveys/1973-5-4/p223-hansen/" target="_top">Concurrent Programming Concepts</a> |
---|
605 | ”. </span><p>"This paper describes the evolution of language features for |
---|
606 | multiprogramming from event queues and semaphores to critical regions and |
---|
607 | monitors." Includes analysis of why events are considered error-prone. Also |
---|
608 | noteworthy because of an introductory quotation from Christopher Alexander; |
---|
609 | Brinch Hansen was years ahead of others in recognizing pattern concepts |
---|
610 | applied to software, too.</p></p> |
---|
611 | </div> |
---|
612 | <div class="biblioentry"> |
---|
613 | <a name="thread.bib.Butenhof97"></a><p>[<span class="abbrev"><a name="thread.bib.Butenhof97.abbrev"></a>Butenhof97</span>] <span class="title"><i> |
---|
614 | <a href="http://cseng.aw.com/book/0,3828,0201633922,00.html" target="_top">Programming with POSIX Threads </a> |
---|
615 | </i>. </span><span class="author"><span class="firstname">David</span> <span class="othername">R.</span> <span class="surname">Butenhof</span>. </span><span class="publisher">Addison-Wesley</span><span class="copyright">Copyright © 1997. </span><span class="isbn">ISNB: 0-201-63392-2. </span><p>This is a very readable explanation of threads and how to use |
---|
616 | them. Many of the insights given apply to all multithreaded programming, not |
---|
617 | just POSIX Threads</p></p> |
---|
618 | </div> |
---|
619 | <div class="biblioentry"> |
---|
620 | <a name="thread.bib.Hoare74"></a><p>[<span class="abbrev"><a name="thread.bib.Hoare74.abbrev"></a>Hoare74</span>] <span class="biblioset"><i>Communications of the ACM</i>. <span class="volumenum">Vol. 17. </span><span class="issuenum">No. 10. </span><span class="date">October, 1974. </span></span><span class="biblioset">“ |
---|
621 | <a href="http://www.acm.org/classics/feb96/" target="_top">Monitors: An Operating System Structuring Concept</a> |
---|
622 | ”. <span class="author"><span class="firstname">C.A.R.</span> <span class="surname">Hoare</span>. </span><span class="pagenums">549-557. </span></span><p>Hoare and Brinch Hansen's work on Monitors is the basis for reliable |
---|
623 | multithreading patterns. This is one of the most often referenced papers in |
---|
624 | all of computer science, and with good reason.</p></p> |
---|
625 | </div> |
---|
626 | <div class="biblioentry"> |
---|
627 | <a name="thread.bib.ISO98"></a><p>[<span class="abbrev"><a name="thread.bib.ISO98.abbrev"></a>ISO98</span>] <span class="title"><i> |
---|
628 | <a href="http://www.ansi.org" target="_top">Programming Language C++</a> |
---|
629 | </i>. </span><span class="orgname">ISO/IEC. </span><span class="releaseinfo">14882:1998(E). </span><p>This is the official C++ Standards document. Available from the ANSI |
---|
630 | (American National Standards Institute) Electronic Standards Store.</p></p> |
---|
631 | </div> |
---|
632 | <div class="biblioentry"> |
---|
633 | <a name="thread.bib.McDowellHelmbold89"></a><p>[<span class="abbrev"><a name="thread.bib.McDowellHelmbold89.abbrev"></a>McDowellHelmbold89</span>] <span class="biblioset"><i>Communications of the ACM</i>. <span class="volumenum">Vol. 21. </span><span class="issuenum">No. 2. </span><span class="date">December, 1989. </span></span><span class="biblioset"><span class="author"><span class="firstname">Charles</span> <span class="othername">E.</span> <span class="surname">McDowell</span>. </span><span class="author"><span class="firstname">David</span> <span class="othername">P.</span> <span class="surname">Helmbold</span>. </span><i> |
---|
634 | <a href="http://www.acm.org/pubs/citations/journals/surveys/1989-21-4/p593-mcdowell/" target="_top">Debugging Concurrent Programs</a> |
---|
635 | </i>. </span><p>Identifies many of the unique failure modes and debugging difficulties |
---|
636 | associated with concurrent programs.</p></p> |
---|
637 | </div> |
---|
638 | <div class="biblioentry"> |
---|
639 | <a name="thread.bib.SchmidtPyarali"></a><p>[<span class="abbrev"><a name="thread.bib.SchmidtPyarali.abbrev"></a>SchmidtPyarali</span>] <span class="title"><i> |
---|
640 | <a href="http://www.cs.wustl.edu/~schmidt/win32-cv-1.html8" target="_top">Strategies for Implementing POSIX Condition Variables on Win32</a> |
---|
641 | </i>. </span><span class="authorgroup"><span class="firstname">Douglas</span> <span class="othername">C.</span> <span class="surname">Schmidt</span> and <span class="firstname">Irfan</span> <span class="surname">Pyarali</span>. </span><span class="orgname">Department of Computer Science, Washington University, St. Louis, |
---|
642 | Missouri. </span><p>Rationale for understanding <span class="bold"><strong>Boost.Thread</strong></span> condition |
---|
643 | variables. Note that Alexander Terekhov found some bugs in the |
---|
644 | implementation given in this article, so pthreads-win32 and <span class="bold"><strong>Boost.Thread</strong></span> |
---|
645 | are even more complicated yet.</p></p> |
---|
646 | </div> |
---|
647 | <div class="biblioentry"> |
---|
648 | <a name="thread.bib.SchmidtStalRohnertBuschmann"></a><p>[<span class="abbrev"><a name="thread.bib.SchmidtStalRohnertBuschmann.abbrev"></a>SchmidtStalRohnertBuschmann</span>] <span class="title"><i> |
---|
649 | <a href="http://www.wiley.com/Corporate/Website/Objects/Products/0,9049,104671,00.html" target="_top">Pattern-Oriented Architecture Volume 2</a> |
---|
650 | </i>. </span><span class="subtitle">Patterns for Concurrent and Networked Objects. </span><span class="titleabbrev">POSA2. </span><span class="authorgroup"><span class="firstname">Douglas</span> <span class="othername">C.</span> <span class="surname">Schmidt</span>, <span class="firstname">Michael</span>, <span class="firstname">Hans</span> <span class="surname">Rohnert</span>, and <span class="firstname">Frank</span> <span class="surname">Buschmann</span>. </span><span class="publisher">Wiley</span><span class="copyright">Copyright © 2000. </span><p>This is a very good explanation of how to apply several patterns |
---|
651 | useful for concurrent programming. Among the patterns documented is the |
---|
652 | Monitor Pattern mentioned frequently in the <span class="bold"><strong>Boost.Thread</strong></span> |
---|
653 | documentation.</p></p> |
---|
654 | </div> |
---|
655 | <div class="biblioentry"> |
---|
656 | <a name="thread.bib.Stroustrup"></a><p>[<span class="abbrev"><a name="thread.bib.Stroustrup.abbrev"></a>Stroustrup</span>] <span class="title"><i> |
---|
657 | <a href="http://cseng.aw.com/book/0,3828,0201700735,00.html" target="_top">The C++ Programming Language</a> |
---|
658 | </i>. </span><span class="edition">Special Edition. </span><span class="publisher">Addison-Wesley</span><span class="copyright">Copyright © 2000. </span><span class="isbn">ISBN: 0-201-70073-5. </span><p>The first book a C++ programmer should own. Note that the 3rd edition |
---|
659 | (and subsequent editions like the Special Edition) has been rewritten to |
---|
660 | cover the ISO standard language and library.</p></p> |
---|
661 | </div> |
---|
662 | </div> |
---|
663 | </div> |
---|
664 | <table width="100%"><tr> |
---|
665 | <td align="left"><small><p>Last revised: October 15, 2006 at 14:52:54 GMT</p></small></td> |
---|
666 | <td align="right"><small></small></td> |
---|
667 | </tr></table> |
---|
668 | <hr> |
---|
669 | <div class="spirit-nav"> |
---|
670 | <a accesskey="p" href="string_algo/credits.html"><img src="images/prev.png" alt="Prev"></a><a accesskey="u" href="libraries.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="thread/design.html"><img src="images/next.png" alt="Next"></a> |
---|
671 | </div> |
---|
672 | </body> |
---|
673 | </html> |
---|