mirror of
https://github.com/boostorg/thread.git
synced 2026-02-03 09:42:16 +00:00
Compare commits
337 Commits
svn-branch
...
boost-1.34
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4599d4a869 | ||
|
|
19846ff356 | ||
|
|
db2aaa04fd | ||
|
|
b48f9aa609 | ||
|
|
7915ab1ec6 | ||
|
|
f0faf88d66 | ||
|
|
7dd7537f5f | ||
|
|
f51680e8d9 | ||
|
|
a6bc072c6d | ||
|
|
85f2508157 | ||
|
|
ebb6c8d637 | ||
|
|
ddc83e270c | ||
|
|
0173148a2e | ||
|
|
69a4ec6c00 | ||
|
|
2d52219af2 | ||
|
|
1f87a9e4c0 | ||
|
|
ba8afde42b | ||
|
|
93f677cba6 | ||
|
|
dfd865d67d | ||
|
|
96a04402db | ||
|
|
78e644c7c1 | ||
|
|
89cc7fc34e | ||
|
|
974754598e | ||
|
|
87acbb406d | ||
|
|
597517157c | ||
|
|
a0b816be8c | ||
|
|
4a056924d2 | ||
|
|
d5a81f990c | ||
|
|
da8c92f057 | ||
|
|
866b33c808 | ||
|
|
182daf0b17 | ||
|
|
2552febc2a | ||
|
|
eb9db9b683 | ||
|
|
11dbdfca4d | ||
|
|
f49de9ec10 | ||
|
|
3a7e569a65 | ||
|
|
c376c1a62a | ||
|
|
fbbc52063a | ||
|
|
78b4fe3d07 | ||
|
|
b8c8b250b1 | ||
|
|
b26d01c8d7 | ||
|
|
4dbd8a66af | ||
|
|
cb4d739fd1 | ||
|
|
11f913e8fb | ||
|
|
0b6054a919 | ||
|
|
e7620a1050 | ||
|
|
811a03f281 | ||
|
|
2528bd0b8f | ||
|
|
ed587be470 | ||
|
|
55b48874a4 | ||
|
|
720ccdb474 | ||
|
|
a556ff6560 | ||
|
|
33c0af8253 | ||
|
|
86072f95ac | ||
|
|
c7b96bcd7d | ||
|
|
572c18302f | ||
|
|
efd1bdec23 | ||
|
|
ba86f9ff13 | ||
|
|
56b07cb5c0 | ||
|
|
358e32e98f | ||
|
|
01297016bd | ||
|
|
64b5b67661 | ||
|
|
b6f0ec7fd9 | ||
|
|
e9c0b5e0c5 | ||
|
|
4a005ea288 | ||
|
|
9658b69af4 | ||
|
|
e3c9446e29 | ||
|
|
aa240e61d9 | ||
|
|
2954e932ce | ||
|
|
5be79cc858 | ||
|
|
4a9d97d22d | ||
|
|
f4f3433854 | ||
|
|
26bffa3740 | ||
|
|
69e52a9882 | ||
|
|
cc8de48849 | ||
|
|
9d7c119f94 | ||
|
|
6ba9fd1b60 | ||
|
|
fb6250eb94 | ||
|
|
bc73368c96 | ||
|
|
3068f0c62c | ||
|
|
8e00803c83 | ||
|
|
087b69b629 | ||
|
|
3b237267fb | ||
|
|
b9dbb1ed45 | ||
|
|
41d3b29ec0 | ||
|
|
05ceb8b1e2 | ||
|
|
80d3925b8d | ||
|
|
2cd6cbeacc | ||
|
|
6382846f6c | ||
|
|
349d0fd74b | ||
|
|
9c88855bf4 | ||
|
|
f0e6cdfcb5 | ||
|
|
af9864a1b5 | ||
|
|
8ac145e667 | ||
|
|
39f7afc7d0 | ||
|
|
113b974bb7 | ||
|
|
c747a6ff4e | ||
|
|
107d11cfd5 | ||
|
|
a4d2cd94b9 | ||
|
|
3d9fb84fc9 | ||
|
|
e500bc075e | ||
|
|
25e8fa0e11 | ||
|
|
5f27fb2607 | ||
|
|
d977cedb78 | ||
|
|
454b58cdf0 | ||
|
|
82a632b0f9 | ||
|
|
43cbe3f1f8 | ||
|
|
d027cec8a6 | ||
|
|
e53c2c52ee | ||
|
|
5ff0ecc12d | ||
|
|
9c1f421ccb | ||
|
|
66850bc057 | ||
|
|
33da34b4bf | ||
|
|
792cd49310 | ||
|
|
37fdb5e2b0 | ||
|
|
88cd251db7 | ||
|
|
4038d18fc8 | ||
|
|
59bf92a183 | ||
|
|
57879155d2 | ||
|
|
96d43cebc0 | ||
|
|
8e13857b29 | ||
|
|
8c6e454697 | ||
|
|
4c7c7df89b | ||
|
|
515e6d8635 | ||
|
|
bbd941e2df | ||
|
|
3edba1bf19 | ||
|
|
4ad99d8242 | ||
|
|
c0aeaecc14 | ||
|
|
792be9e687 | ||
|
|
fd65337f43 | ||
|
|
9de9726e6f | ||
|
|
522037ca4a | ||
|
|
8fc3d1f718 | ||
|
|
cebaf27ee8 | ||
|
|
b62503f274 | ||
|
|
af50c640ab | ||
|
|
b5c5fbe0f5 | ||
|
|
b88ae8105e | ||
|
|
9ad04bb65e | ||
|
|
13bbaab1c4 | ||
|
|
09ca8d1728 | ||
|
|
9797a93d86 | ||
|
|
d29dae72de | ||
|
|
59fba2bff6 | ||
|
|
0350d4c501 | ||
|
|
d3e4a90e70 | ||
|
|
8ebb19fd18 | ||
|
|
02ddc33e6c | ||
|
|
410e8efeba | ||
|
|
e9f8e0bad9 | ||
|
|
f69e0313dc | ||
|
|
baa9b396d9 | ||
|
|
a82b0c516d | ||
|
|
43e2192aa2 | ||
|
|
4cd6453cac | ||
|
|
921d4c24c2 | ||
|
|
4fc7653b12 | ||
|
|
9d0e39a7c2 | ||
|
|
7aa979cf5b | ||
|
|
0aa50614d7 | ||
|
|
6f402c7362 | ||
|
|
2bf43a124d | ||
|
|
3573c53eda | ||
|
|
4546ec4ef7 | ||
|
|
2f7337aaf6 | ||
|
|
046698bcc2 | ||
|
|
06d7bf21d5 | ||
|
|
e7b9ccdf10 | ||
|
|
1e15b043a0 | ||
|
|
6c5f3d76e2 | ||
|
|
8679d6f6af | ||
|
|
f1c7d0f354 | ||
|
|
261e413500 | ||
|
|
094e41d7a7 | ||
|
|
e20299c8ee | ||
|
|
f8962b7ad2 | ||
|
|
c34f829c3e | ||
|
|
46264e4a4a | ||
|
|
096df68ea6 | ||
|
|
35f2055a1e | ||
|
|
e1353eefb3 | ||
|
|
4911a532bf | ||
|
|
96362e03aa | ||
|
|
049b4e09fe | ||
|
|
828c0e28af | ||
|
|
15a638edc0 | ||
|
|
fc8f1b1075 | ||
|
|
318a8e38c9 | ||
|
|
f0dbb02a9f | ||
|
|
649b777b76 | ||
|
|
6fad43670a | ||
|
|
e24b16229e | ||
|
|
21b4b81810 | ||
|
|
1096b1e28e | ||
|
|
03458fedef | ||
|
|
c1a2004344 | ||
|
|
2adb13a209 | ||
|
|
dba194ddb9 | ||
|
|
8179f041e6 | ||
|
|
a13c7a4d84 | ||
|
|
bbf92bb971 | ||
|
|
b33f413635 | ||
|
|
58ffb2bc16 | ||
|
|
0ed112631c | ||
|
|
9cfe8e9422 | ||
|
|
7d3fe72970 | ||
|
|
ac422138fa | ||
|
|
bf8746454a | ||
|
|
b61aa5b4ba | ||
|
|
c2bcd08168 | ||
|
|
48593b8868 | ||
|
|
83d4dc1831 | ||
|
|
0696f3cc41 | ||
|
|
515590495a | ||
|
|
7221bca909 | ||
|
|
ed64a8cd12 | ||
|
|
cbd30d22ff | ||
|
|
0c74dbd436 | ||
|
|
49356cc931 | ||
|
|
ceee6e8b17 | ||
|
|
61ab2754d2 | ||
|
|
2de3df61e8 | ||
|
|
b84d7aa06d | ||
|
|
ed48f900a3 | ||
|
|
d197a49707 | ||
|
|
b8ccaa3bf6 | ||
|
|
507a684b21 | ||
|
|
c969c9387a | ||
|
|
1709db4953 | ||
|
|
4d1c9ba316 | ||
|
|
45b0396355 | ||
|
|
1df2169e48 | ||
|
|
2c056b3621 | ||
|
|
680119006c | ||
|
|
c4ac4b7538 | ||
|
|
ff5d3b49ca | ||
|
|
e101c878f0 | ||
|
|
125193dcfa | ||
|
|
77efa9810d | ||
|
|
7f03d1917b | ||
|
|
55b4ca9350 | ||
|
|
7196a0f9d2 | ||
|
|
2caabde5ca | ||
|
|
137d7663c1 | ||
|
|
508b71a921 | ||
|
|
5d90820005 | ||
|
|
84727e90b1 | ||
|
|
9a1e3d3320 | ||
|
|
d33e0c8ee1 | ||
|
|
3332649480 | ||
|
|
c918b66199 | ||
|
|
dbbf56e17a | ||
|
|
c77500c15a | ||
|
|
75084aaa96 | ||
|
|
35714c8f1c | ||
|
|
3699cc97a6 | ||
|
|
5a7377acda | ||
|
|
6aaee629b5 | ||
|
|
b465fe569c | ||
|
|
5e6f72a688 | ||
|
|
51f80f6c15 | ||
|
|
45c314e594 | ||
|
|
cfce0892e0 | ||
|
|
05d1abf030 | ||
|
|
6c24a2626b | ||
|
|
870c75bd12 | ||
|
|
5fdd771708 | ||
|
|
06f39ac409 | ||
|
|
c92b0a2fb7 | ||
|
|
8a8d0e05ca | ||
|
|
74bae2baac | ||
|
|
4ba48676bd | ||
|
|
78480e7951 | ||
|
|
4cb9c412e8 | ||
|
|
75c83fed96 | ||
|
|
391de20ae0 | ||
|
|
1e2a9e8971 | ||
|
|
43cbd3a283 | ||
|
|
31cf6b5e64 | ||
|
|
99109ab78b | ||
|
|
a80d5f159d | ||
|
|
7ba4fc4aed | ||
|
|
9fb31e9868 | ||
|
|
3a2246de5b | ||
|
|
e7c4e2fa57 | ||
|
|
724ab285f0 | ||
|
|
d60e66fb00 | ||
|
|
97cdaca028 | ||
|
|
3044c8f905 | ||
|
|
2775a2a945 | ||
|
|
c43c1febba | ||
|
|
ceb6471d57 | ||
|
|
b99cc044f3 | ||
|
|
d91429dcec | ||
|
|
b1d1f7d8f1 | ||
|
|
86b608cf41 | ||
|
|
f263f75751 | ||
|
|
24bec05b86 | ||
|
|
ce1a5e9359 | ||
|
|
311525bc06 | ||
|
|
ecdfd96529 | ||
|
|
5aab32bc1a | ||
|
|
e152a1c6f2 | ||
|
|
e84fde78ec | ||
|
|
6ec4652bcf | ||
|
|
a5239c820b | ||
|
|
41b001b22c | ||
|
|
34e903b8b0 | ||
|
|
2b67e953fd | ||
|
|
aa0d3adf1d | ||
|
|
a1f57a8a80 | ||
|
|
6bc82a8580 | ||
|
|
c4c2e5d3a2 | ||
|
|
dd7d4b2173 | ||
|
|
2719c4d545 | ||
|
|
33c1e36b54 | ||
|
|
e7e46e185e | ||
|
|
9200d48873 | ||
|
|
831d054d24 | ||
|
|
f3af804ddb | ||
|
|
1f35149ef0 | ||
|
|
554a18842f | ||
|
|
869243b6d1 | ||
|
|
c0da02326a | ||
|
|
9b5f666fc5 | ||
|
|
1ce93426a4 | ||
|
|
6dacf3478b | ||
|
|
dff91699c3 | ||
|
|
9f83e8c1fc | ||
|
|
7b07cb0759 | ||
|
|
c2e7091632 | ||
|
|
1ab320042e | ||
|
|
b0cd307eaf | ||
|
|
ca2cf20cf3 | ||
|
|
b3acba1d2d | ||
|
|
6d2731c463 | ||
|
|
b7f8f8867c |
2
build/.cvsignore
Normal file
2
build/.cvsignore
Normal file
@@ -0,0 +1,2 @@
|
||||
bin*
|
||||
*.pdb
|
||||
39
build/Jamfile.v2
Normal file
39
build/Jamfile.v2
Normal file
@@ -0,0 +1,39 @@
|
||||
# (C) Copyright Vladimir Prus, David Abrahams, Michael Stevens, Hartmut Kaiser,
|
||||
# William E Kempf 2002-2006
|
||||
# Use, modification and distribution are subject to the
|
||||
# Boost Software License, Version 1.0. (See accompanying file
|
||||
# LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
import os ;
|
||||
|
||||
|
||||
project boost/thread
|
||||
: source-location ../src
|
||||
: requirements <link>shared:<define>BOOST_THREAD_BUILD_DLL=1 <threading>multi
|
||||
: default-build <threading>multi
|
||||
;
|
||||
|
||||
CPP_SOURCES =
|
||||
barrier
|
||||
condition
|
||||
exceptions
|
||||
mutex
|
||||
once
|
||||
recursive_mutex
|
||||
# read_write_mutex
|
||||
thread
|
||||
tss_hooks
|
||||
tss_dll
|
||||
tss_pe
|
||||
tss
|
||||
xtime
|
||||
;
|
||||
|
||||
lib boost_thread
|
||||
: $(CPP_SOURCES).cpp
|
||||
: <link>shared:<define>BOOST_THREAD_BUILD_DLL=1
|
||||
<link>static:<define>BOOST_THREAD_BUILD_LIB=1
|
||||
: # default build
|
||||
: <link>shared:<define>BOOST_THREAD_BUILD_DLL=1
|
||||
<link>static:<define>BOOST_THREAD_BUILD_LIB=1
|
||||
;
|
||||
11
doc/Jamfile.v2
Normal file
11
doc/Jamfile.v2
Normal file
@@ -0,0 +1,11 @@
|
||||
# Copyright (C) 2001-2003
|
||||
# William E. Kempf
|
||||
#
|
||||
# Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
import toolset ;
|
||||
toolset.using doxygen ;
|
||||
|
||||
boostbook thread : thread.xml ;
|
||||
|
||||
73
doc/acknowledgements.xml
Normal file
73
doc/acknowledgements.xml
Normal file
@@ -0,0 +1,73 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
||||
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
|
||||
<!ENTITY % thread.entities SYSTEM "entities.xml">
|
||||
%thread.entities;
|
||||
]>
|
||||
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
|
||||
Subject to the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
|
||||
-->
|
||||
<section id="thread.acknowledgements"
|
||||
last-revision="$Date$">
|
||||
<title>Acknowledgements</title>
|
||||
<para>William E. Kempf was the architect, designer, and implementor of
|
||||
&Boost.Thread;.</para>
|
||||
<para>Mac OS Carbon implementation written by Mac Murrett.</para>
|
||||
<para>Dave Moore provided initial submissions and further comments on the
|
||||
<code>barrier</code>
|
||||
,
|
||||
<code>thread_pool</code>
|
||||
,
|
||||
<code>read_write_mutex</code>
|
||||
,
|
||||
<code>read_write_try_mutex</code>
|
||||
and
|
||||
<code>read_write_timed_mutex</code>
|
||||
classes.</para>
|
||||
<para>Important contributions were also made by Jeremy Siek (lots of input
|
||||
on the design and on the implementation), Alexander Terekhov (lots of input
|
||||
on the Win32 implementation, especially in regards to boost::condition, as
|
||||
well as a lot of explanation of POSIX behavior), Greg Colvin (lots of input
|
||||
on the design), Paul Mclachlan, Thomas Matelich and Iain Hanson (for help
|
||||
in trying to get the build to work on other platforms), and Kevin S. Van
|
||||
Horn (for several updates/corrections to the documentation).</para>
|
||||
<para>Mike Glassford finished changes to &Boost.Thread; that were begun
|
||||
by William Kempf and moved them into the main CVS branch.
|
||||
He also addressed a number of issues that were brought up on the Boost
|
||||
developer's mailing list and provided some additions and changes to the
|
||||
read_write_mutex and related classes.</para>
|
||||
<para>The documentation was written by William E. Kempf. Beman Dawes
|
||||
provided additional documentation material and editing.
|
||||
Mike Glassford finished William Kempf's conversion of the documentation to
|
||||
BoostBook format and added a number of new sections.</para>
|
||||
<para>Discussions on the boost.org mailing list were essential in the
|
||||
development of &Boost.Thread;
|
||||
. As of August 1, 2001, participants included Alan Griffiths, Albrecht
|
||||
Fritzsche, Aleksey Gurtovoy, Alexander Terekhov, Andrew Green, Andy Sawyer,
|
||||
Asger Alstrup Nielsen, Beman Dawes, Bill Klein, Bill Rutiser, Bill Wade,
|
||||
Branko èibej, Brent Verner, Craig Henderson, Csaba Szepesvari,
|
||||
Dale Peakall, Damian Dixon, Dan Nuffer, Darryl Green, Daryle Walker, David
|
||||
Abrahams, David Allan Finch, Dejan Jelovic, Dietmar Kuehl, Douglas Gregor,
|
||||
Duncan Harris, Ed Brey, Eric Swanson, Eugene Karpachov, Fabrice Truillot,
|
||||
Frank Gerlach, Gary Powell, Gernot Neppert, Geurt Vos, Ghazi Ramadan, Greg
|
||||
Colvin, Gregory Seidman, HYS, Iain Hanson, Ian Bruntlett, J Panzer, Jeff
|
||||
Garland, Jeff Paquette, Jens Maurer, Jeremy Siek, Jesse Jones, Joe Gottman,
|
||||
John (EBo) David, John Bandela, John Maddock, John Max Skaller, John
|
||||
Panzer, Jon Jagger , Karl Nelson, Kevlin Henney, KG Chandrasekhar, Levente
|
||||
Farkas, Lie-Quan Lee, Lois Goldthwaite, Luis Pedro Coelho, Marc Girod, Mark
|
||||
A. Borgerding, Mark Rodgers, Marshall Clow, Matthew Austern, Matthew Hurd,
|
||||
Michael D. Crawford, Michael H. Cox , Mike Haller, Miki Jovanovic, Nathan
|
||||
Myers, Paul Moore, Pavel Cisler, Peter Dimov, Petr Kocmid, Philip Nash,
|
||||
Rainer Deyke, Reid Sweatman, Ross Smith, Scott McCaskill, Shalom Reich,
|
||||
Steve Cleary, Steven Kirk, Thomas Holenstein, Thomas Matelich, Trevor
|
||||
Perrin, Valentin Bonnard, Vesa Karvonen, Wayne Miller, and William
|
||||
Kempf.</para>
|
||||
<para>
|
||||
As of February 2006 Anthony Williams and Roland Schwarz took over maintainance
|
||||
and further development of the library after it has been in an orphaned state
|
||||
for a rather long period of time.
|
||||
</para>
|
||||
<para>Apologies for anyone inadvertently missed.</para>
|
||||
</section>
|
||||
|
||||
82
doc/barrier-ref.xml
Normal file
82
doc/barrier-ref.xml
Normal file
@@ -0,0 +1,82 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
||||
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
|
||||
<!ENTITY % thread.entities SYSTEM "entities.xml">
|
||||
%thread.entities;
|
||||
]>
|
||||
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
|
||||
Subject to the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
|
||||
-->
|
||||
<header name="boost/thread/barrier.hpp"
|
||||
last-revision="$Date$">
|
||||
<namespace name="boost">
|
||||
<class name="barrier">
|
||||
<inherit access="private">
|
||||
<type><classname>boost::noncopyable</classname></type>
|
||||
<purpose>Exposition only</purpose>
|
||||
</inherit>
|
||||
|
||||
<purpose>
|
||||
<para>An object of class <classname>barrier</classname> is a synchronization
|
||||
primitive used to cause a set of threads to wait until they each perform a
|
||||
certain function or each reach a particular point in their execution.</para>
|
||||
</purpose>
|
||||
|
||||
<description>
|
||||
<para>When a barrier is created, it is initialized with a thread count N.
|
||||
The first N-1 calls to <code>wait()</code> will all cause their threads to be blocked.
|
||||
The Nth call to <code>wait()</code> will allow all of the waiting threads, including
|
||||
the Nth thread, to be placed in a ready state. The Nth call will also "reset"
|
||||
the barrier such that, if an additional N+1th call is made to <code>wait()</code>,
|
||||
it will be as though this were the first call to <code>wait()</code>; in other
|
||||
words, the N+1th to 2N-1th calls to <code>wait()</code> will cause their
|
||||
threads to be blocked, and the 2Nth call to <code>wait()</code> will allow all of
|
||||
the waiting threads, including the 2Nth thread, to be placed in a ready state
|
||||
and reset the barrier. This functionality allows the same set of N threads to re-use
|
||||
a barrier object to synchronize their execution at multiple points during their
|
||||
execution.</para>
|
||||
<para>See <xref linkend="thread.glossary"/> for definitions of thread
|
||||
states <link linkend="thread.glossary.thread-state">blocked</link>
|
||||
and <link linkend="thread.glossary.thread-state">ready</link>.
|
||||
Note that "waiting" is a synonym for blocked.</para>
|
||||
</description>
|
||||
|
||||
<constructor>
|
||||
<parameter name="count">
|
||||
<paramtype>size_t</paramtype>
|
||||
</parameter>
|
||||
|
||||
<effects><simpara>Constructs a <classname>barrier</classname> object that
|
||||
will cause <code>count</code> threads to block on a call to <code>wait()</code>.
|
||||
</simpara></effects>
|
||||
</constructor>
|
||||
|
||||
<destructor>
|
||||
<effects><simpara>Destroys <code>*this</code>. If threads are still executing
|
||||
their <code>wait()</code> operations, the behavior for these threads is undefined.
|
||||
</simpara></effects>
|
||||
</destructor>
|
||||
|
||||
<method-group name="waiting">
|
||||
<method name="wait">
|
||||
<type>bool</type>
|
||||
|
||||
<effects><simpara>Wait until N threads call <code>wait()</code>, where
|
||||
N equals the <code>count</code> provided to the constructor for the
|
||||
barrier object.</simpara>
|
||||
<simpara><emphasis role="bold">Note</emphasis> that if the barrier is
|
||||
destroyed before <code>wait()</code> can return, the behavior is
|
||||
undefined.</simpara></effects>
|
||||
|
||||
<returns>Exactly one of the N threads will receive a return value
|
||||
of <code>true</code>, the others will receive a value of <code>false</code>.
|
||||
Precisely which thread receives the return value of <code>true</code> will
|
||||
be implementation-defined. Applications can use this value to designate one
|
||||
thread as a leader that will take a certain action, and the other threads
|
||||
emerging from the barrier can wait for that action to take place.</returns>
|
||||
</method>
|
||||
</method-group>
|
||||
</class>
|
||||
</namespace>
|
||||
</header>
|
||||
234
doc/bibliography.xml
Normal file
234
doc/bibliography.xml
Normal file
@@ -0,0 +1,234 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
||||
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
|
||||
<!ENTITY % thread.entities SYSTEM "entities.xml">
|
||||
%thread.entities;
|
||||
]>
|
||||
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
|
||||
Subject to the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
|
||||
-->
|
||||
<bibliography id="thread.bibliography"
|
||||
last-revision="$Date$">
|
||||
<title>Bibliography</title>
|
||||
<biblioentry id="thread.bib.AndrewsSchneider83">
|
||||
<abbrev id="thread.bib.AndrewsSchneider83.abbrev">AndrewsSchnieder83</abbrev>
|
||||
<biblioset relation="journal">
|
||||
<title>ACM Computing Surveys</title>
|
||||
<volumenum>Vol. 15</volumenum>
|
||||
<issuenum>No. 1</issuenum>
|
||||
<date>March, 1983</date>
|
||||
</biblioset>
|
||||
<biblioset relation="article">
|
||||
<authorgroup>
|
||||
<author>
|
||||
<firstname>Gregory</firstname>
|
||||
<othername>R.</othername>
|
||||
<surname>Andrews</surname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Fred</firstname>
|
||||
<othername>B.</othername>
|
||||
<surname>Schneider</surname>
|
||||
</author>
|
||||
</authorgroup>
|
||||
<title>
|
||||
<ulink
|
||||
url="http://www.acm.org/pubs/citations/journals/surveys/1983-15-1/p3-andrews/"
|
||||
>Concepts and Notations for Concurrent Programming</ulink>
|
||||
</title>
|
||||
</biblioset>
|
||||
<para>Good general background reading. Includes descriptions of Path
|
||||
Expressions, Message Passing, and Remote Procedure Call in addition to the
|
||||
basics</para>
|
||||
</biblioentry>
|
||||
<biblioentry id="thread.bib.Boost">
|
||||
<abbrev id="thread.bib.Boost.abbrev">Boost</abbrev>
|
||||
<bibliomisc>The <emphasis>Boost</emphasis> world wide web site.
|
||||
<ulink url="http:/www.boost.org">http://www.boost.org</ulink></bibliomisc>
|
||||
<para>&Boost.Thread; is one of many Boost libraries. The Boost web
|
||||
site includes a great deal of documentation and general information which
|
||||
applies to all Boost libraries. Current copies of the libraries including
|
||||
documentation and test programs may be downloaded from the web
|
||||
site.</para>
|
||||
</biblioentry>
|
||||
<biblioentry id="thread.bib.Hansen73">
|
||||
<abbrev id="thread.bib.Hansen73.abbrev">Hansen73</abbrev>
|
||||
<biblioset relation="journal">
|
||||
<title>ACM Computing Surveys</title>
|
||||
<volumenum>Vol. 5</volumenum>
|
||||
<issuenum>No. 4</issuenum>
|
||||
<date>December, 1973</date>
|
||||
</biblioset>
|
||||
<biblioset relation="article">
|
||||
<author>0-201-63392-2
|
||||
<firstname>Per Brinch</firstname>
|
||||
<lastname>Hansen</lastname>
|
||||
</author>
|
||||
<title>
|
||||
<ulink
|
||||
url="http://www.acm.org/pubs/articles/journals/surveys/1973-5-4/p223-hansen/"
|
||||
>Concurrent Programming Concepts</ulink>
|
||||
</title>
|
||||
</biblioset>
|
||||
<para>"This paper describes the evolution of language features for
|
||||
multiprogramming from event queues and semaphores to critical regions and
|
||||
monitors." Includes analysis of why events are considered error-prone. Also
|
||||
noteworthy because of an introductory quotation from Christopher Alexander;
|
||||
Brinch Hansen was years ahead of others in recognizing pattern concepts
|
||||
applied to software, too.</para>
|
||||
</biblioentry>
|
||||
<biblioentry id="thread.bib.Butenhof97">
|
||||
<abbrev id="thread.bib.Butenhof97.abbrev">Butenhof97</abbrev>
|
||||
<title>
|
||||
<ulink url="http://cseng.aw.com/book/0,3828,0201633922,00.html"
|
||||
>Programming with POSIX Threads </ulink>
|
||||
</title>
|
||||
<author>
|
||||
<firstname>David</firstname>
|
||||
<othername>R.</othername>
|
||||
<surname>Butenhof</surname>
|
||||
</author>
|
||||
<publisher>Addison-Wesley</publisher>
|
||||
<copyright><year>1997</year></copyright>
|
||||
<isbn>ISNB: 0-201-63392-2</isbn>
|
||||
<para>This is a very readable explanation of threads and how to use
|
||||
them. Many of the insights given apply to all multithreaded programming, not
|
||||
just POSIX Threads</para>
|
||||
</biblioentry>
|
||||
<biblioentry id="thread.bib.Hoare74">
|
||||
<abbrev id="thread.bib.Hoare74.abbrev">Hoare74</abbrev>
|
||||
<biblioset relation="journal">
|
||||
<title>Communications of the ACM</title>
|
||||
<volumenum>Vol. 17</volumenum>
|
||||
<issuenum>No. 10</issuenum>
|
||||
<date>October, 1974</date>
|
||||
</biblioset>
|
||||
<biblioset relation="article">
|
||||
<title>
|
||||
<ulink url=" http://www.acm.org/classics/feb96/"
|
||||
>Monitors: An Operating System Structuring Concept</ulink>
|
||||
</title>
|
||||
<author>
|
||||
<firstname>C.A.R.</firstname>
|
||||
<surname>Hoare</surname>
|
||||
</author>
|
||||
<pagenums>549-557</pagenums>
|
||||
</biblioset>
|
||||
<para>Hoare and Brinch Hansen's work on Monitors is the basis for reliable
|
||||
multithreading patterns. This is one of the most often referenced papers in
|
||||
all of computer science, and with good reason.</para>
|
||||
</biblioentry>
|
||||
<biblioentry id="thread.bib.ISO98">
|
||||
<abbrev id="thread.bib.ISO98.abbrev">ISO98</abbrev>
|
||||
<title>
|
||||
<ulink url="http://www.ansi.org">Programming Language C++</ulink>
|
||||
</title>
|
||||
<orgname>ISO/IEC</orgname>
|
||||
<releaseinfo>14882:1998(E)</releaseinfo>
|
||||
<para>This is the official C++ Standards document. Available from the ANSI
|
||||
(American National Standards Institute) Electronic Standards Store.</para>
|
||||
</biblioentry>
|
||||
<biblioentry id="thread.bib.McDowellHelmbold89">
|
||||
<abbrev id="thread.bib.McDowellHelmbold89.abbrev">McDowellHelmbold89</abbrev>
|
||||
<biblioset relation="journal">
|
||||
<title>Communications of the ACM</title>
|
||||
<volumenum>Vol. 21</volumenum>
|
||||
<issuenum>No. 2</issuenum>
|
||||
<date>December, 1989</date>
|
||||
</biblioset>
|
||||
<biblioset>
|
||||
<author>
|
||||
<firstname>Charles</firstname>
|
||||
<othername>E.</othername>
|
||||
<surname>McDowell</surname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>David</firstname>
|
||||
<othername>P.</othername>
|
||||
<surname>Helmbold</surname>
|
||||
</author>
|
||||
<title>
|
||||
<ulink
|
||||
url="http://www.acm.org/pubs/citations/journals/surveys/1989-21-4/p593-mcdowell/"
|
||||
>Debugging Concurrent Programs</ulink>
|
||||
</title>
|
||||
</biblioset>
|
||||
<para>Identifies many of the unique failure modes and debugging difficulties
|
||||
associated with concurrent programs.</para>
|
||||
</biblioentry>
|
||||
<biblioentry id="thread.bib.SchmidtPyarali">
|
||||
<abbrev id="thread.bib.SchmidtPyarali.abbrev">SchmidtPyarali</abbrev>
|
||||
<title>
|
||||
<ulink url="http://www.cs.wustl.edu/~schmidt/win32-cv-1.html8"
|
||||
>Strategies for Implementing POSIX Condition Variables on Win32</ulink>
|
||||
</title>
|
||||
<authorgroup>
|
||||
<author>
|
||||
<firstname>Douglas</firstname>
|
||||
<othername>C.</othername>
|
||||
<surname>Schmidt</surname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Irfan</firstname>
|
||||
<surname>Pyarali</surname>
|
||||
</author>
|
||||
</authorgroup>
|
||||
<orgname>Department of Computer Science, Washington University, St. Louis,
|
||||
Missouri</orgname>
|
||||
<para>Rationale for understanding &Boost.Thread; condition
|
||||
variables. Note that Alexander Terekhov found some bugs in the
|
||||
implementation given in this article, so pthreads-win32 and &Boost.Thread;
|
||||
are even more complicated yet.</para>
|
||||
</biblioentry>
|
||||
<biblioentry id="thread.bib.SchmidtStalRohnertBuschmann">
|
||||
<abbrev
|
||||
id="thread.bib.SchmidtStalRohnertBuschmann.abbrev">SchmidtStalRohnertBuschmann</abbrev>
|
||||
<title>
|
||||
<ulink
|
||||
url="http://www.wiley.com/Corporate/Website/Objects/Products/0,9049,104671,00.html"
|
||||
>Pattern-Oriented Architecture Volume 2</ulink>
|
||||
</title>
|
||||
<subtitle>Patterns for Concurrent and Networked Objects</subtitle>
|
||||
<titleabbrev>POSA2</titleabbrev>
|
||||
<authorgroup>
|
||||
<author>
|
||||
<firstname>Douglas</firstname>
|
||||
<othername>C.</othername>
|
||||
<surname>Schmidt</surname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Michael</firstname>
|
||||
<lastname>Stal</lastname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Hans</firstname>
|
||||
<surname>Rohnert</surname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Frank</firstname>
|
||||
<surname>Buschmann</surname>
|
||||
</author>
|
||||
</authorgroup>
|
||||
<publisher>Wiley</publisher>
|
||||
<copyright><year>2000</year></copyright>
|
||||
<para>This is a very good explanation of how to apply several patterns
|
||||
useful for concurrent programming. Among the patterns documented is the
|
||||
Monitor Pattern mentioned frequently in the &Boost.Thread;
|
||||
documentation.</para>
|
||||
</biblioentry>
|
||||
<biblioentry id="thread.bib.Stroustrup">
|
||||
<abbrev id="thread.bib.Stroustrup.abbrev">Stroustrup</abbrev>
|
||||
<title>
|
||||
<ulink url="http://cseng.aw.com/book/0,3828,0201700735,00.html"
|
||||
>The C++ Programming Language</ulink>
|
||||
</title>
|
||||
<edition>Special Edition</edition>
|
||||
<publisher>Addison-Wesley</publisher>
|
||||
<copyright><year>2000</year></copyright>
|
||||
<isbn>ISBN: 0-201-70073-5</isbn>
|
||||
<para>The first book a C++ programmer should own. Note that the 3rd edition
|
||||
(and subsequent editions like the Special Edition) has been rewritten to
|
||||
cover the ISO standard language and library.</para>
|
||||
</biblioentry>
|
||||
</bibliography>
|
||||
137
doc/build.xml
Normal file
137
doc/build.xml
Normal file
@@ -0,0 +1,137 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
||||
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
|
||||
<!ENTITY % thread.entities SYSTEM "entities.xml">
|
||||
%thread.entities;
|
||||
]>
|
||||
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
|
||||
Copyright (c) 2007 Roland Schwarz
|
||||
Subject to the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
|
||||
-->
|
||||
<section id="thread.build" last-revision="$Date$">
|
||||
<title>Build</title>
|
||||
<para>
|
||||
How you build the &Boost.Thread; libraries, and how you build your own applications
|
||||
that use those libraries, are some of the most frequently asked questions. Build
|
||||
processes are difficult to deal with in a portable manner. That's one reason
|
||||
why &Boost.Thread; makes use of &Boost.Build;.
|
||||
In general you should refer to the documentation for &Boost.Build;.
|
||||
This document will only supply you with some simple usage examples for how to
|
||||
use <emphasis>bjam</emphasis> to build and test &Boost.Thread;. In addition, this document
|
||||
will try to explain the build requirements so that users may create their own
|
||||
build processes (for instance, create an IDE specific project), both for building
|
||||
and testing &Boost.Thread;, as well as for building their own projects using
|
||||
&Boost.Thread;.
|
||||
</para>
|
||||
<section id="thread.build.building">
|
||||
<title>Building the &Boost.Thread; Libraries</title>
|
||||
<para>
|
||||
Building the &Boost.Thread; Library depends on how you intend to use it. You have several options:
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
Using as a <link linkend="thread.build.precompiled">precompiled</link> library, possibly
|
||||
with auto-linking, or for use from within an IDE.
|
||||
</listitem>
|
||||
<listitem>
|
||||
Use from a <link linkend="thread.build.bjam">&Boost.Build;</link> project.
|
||||
</listitem>
|
||||
<listitem>
|
||||
Using in <link linkend="thread.build.source">source</link> form.
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
<section id="thread.build.precompiled">
|
||||
<title>Precompiled</title>
|
||||
<para>
|
||||
Using the &Boost.Thread; library in precompiled form is the way to go if you want to
|
||||
install the library to a standard place, from where your linker is able to resolve code
|
||||
in binary form. You also will want this option if compile time is a concern. Multiple
|
||||
variants are available, for different toolsets and build variants (debug/release).
|
||||
The library files are named <emphasis>{lead}boost_thread{build-specific-tags}.{extension}</emphasis>,
|
||||
where the build-specific-tags indicate the toolset used to build the library, whether it's
|
||||
a debug or release build, what version of &Boost; was used, etc.; and the lead and extension
|
||||
are the appropriate extensions for a dynamic link library or static library for the platform
|
||||
for which &Boost.Thread; is being built.
|
||||
For instance, a debug build of the dynamic library built for Win32 with VC++ 7.1 using Boost 1.34 would
|
||||
be named <emphasis>boost_thread-vc71-mt-gd-1_34.dll</emphasis>.
|
||||
More information on this should be available from the &Boost.Build; documentation.
|
||||
</para>
|
||||
<para>
|
||||
Building should be possible with the default configuration. If you are running into problems,
|
||||
it might be wise to adjust your local settings of &Boost.Build; though. Typically you will
|
||||
need to get your user-config.jam file to reflect your environment, i.e. used toolsets. Please
|
||||
refer to the &Boost.Build; documentation to learn how to do this.
|
||||
</para>
|
||||
<para>
|
||||
To create the libraries you need to open a command shell and change to the
|
||||
<emphasis>boost_root</emphasis> directory. From there you give the command
|
||||
<programlisting>bjam --toolset=<emphasis>mytoolset</emphasis> stage --with-thread</programlisting>
|
||||
Replace <emphasis>mytoolset</emphasis> with the name of your toolset, e.g. msvc-7.1 .
|
||||
This will compile and put the libraries into the <emphasis>stage</emphasis> directory which is just below the
|
||||
<emphasis>boost_root</emphasis> directory. &Boost.Build; by default will generate static and
|
||||
dynamic variants for debug and release.
|
||||
</para>
|
||||
<note>
|
||||
Invoking the above command without the --with-thread switch &Boost.Build; will build all of
|
||||
the Boost distribution, including &Boost.Thread;.
|
||||
</note>
|
||||
<para>
|
||||
The next step is to copy your libraries to a place where your linker is able to pick them up.
|
||||
It is also quite possible to leave them in the stage directory and instruct your IDE to take them
|
||||
from there.
|
||||
</para>
|
||||
<para>
|
||||
In your IDE you then need to add <emphasis>boost_root</emphasis>/boost to the paths where the compiler
|
||||
expects to find files to be included. For toolsets that support <emphasis>auto-linking</emphasis>
|
||||
it is not necessary to explicitly specify the name of the library to link against, it is sufficient
|
||||
to specify the path of the stage directory. Typically this is true on Windows. For gcc you need
|
||||
to specify the exact library name (including all the tags). Please don't forget that threading
|
||||
support must be turned on to be able to use the library. You should be able now to build your
|
||||
project from the IDE.
|
||||
</para>
|
||||
</section>
|
||||
<section id="thread.build.bjam">
|
||||
<title>&Boost.Build; Project</title>
|
||||
<para>
|
||||
If you have decided to use &Boost.Build; as a build environment for your application, you simply
|
||||
need to add a single line to your <emphasis>Jamroot</emphasis> file:
|
||||
<programlisting>use-project /boost : {path-to-boost-root} ;</programlisting>
|
||||
where <emphasis>{path-to-boost-root}</emphasis> needs to be replaced with the location of
|
||||
your copy of the boost tree.
|
||||
Later when you specify a component that needs to link against &Boost.Thread; you specify this
|
||||
as e.g.:
|
||||
<programlisting>exe myapp : {myappsources} /boost//thread ;</programlisting>
|
||||
and you are done.
|
||||
</para>
|
||||
</section>
|
||||
<section id="thread.build.source">
|
||||
<title>Source Form</title>
|
||||
<para>
|
||||
Of course it is also possible to use the &Boost.Thread; library in source form.
|
||||
First you need to specify the <emphasis>boost_root</emphasis>/boost directory as
|
||||
a path where your compiler expects to find files to include. It is not easy
|
||||
to isolate the &Boost.Thread; include files from the rest of the boost
|
||||
library though. You would also need to isolate every include file that the thread
|
||||
library depends on. Next you need to copy the files from
|
||||
<emphasis>boost_root</emphasis>/libs/thread/src to your project and instruct your
|
||||
build system to compile them together with your project. Please look into the
|
||||
<emphasis>Jamfile</emphasis> in <emphasis>boost_root</emphasis>/libs/thread/build
|
||||
to find out which compiler options and defines you will need to get a clean compile.
|
||||
Using the boost library in this way is the least recommended, and should only be
|
||||
considered if avoiding dependency on &Boost.Build; is a requirement. Even if so
|
||||
it might be a better option to use the library in it's precompiled form.
|
||||
Precompiled downloads are available from the boost consulting web site, or as
|
||||
part of most linux distributions.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
<section id="thread.build.testing">
|
||||
<title>Testing the &Boost.Thread; Libraries</title>
|
||||
<para>
|
||||
To test the &Boost.Thread; libraries using &Boost.Build;, simply change to the
|
||||
directory <emphasis>boost_root</emphasis>/libs/thread/test and execute the command:
|
||||
<programlisting>bjam --toolset=<emphasis>mytoolset</emphasis> test</programlisting>
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
2305
doc/concepts.xml
Normal file
2305
doc/concepts.xml
Normal file
File diff suppressed because it is too large
Load Diff
196
doc/condition-ref.xml
Normal file
196
doc/condition-ref.xml
Normal file
@@ -0,0 +1,196 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
||||
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
|
||||
<!ENTITY % thread.entities SYSTEM "entities.xml">
|
||||
%thread.entities;
|
||||
]>
|
||||
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
|
||||
Subject to the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
|
||||
-->
|
||||
<header name="boost/thread/condition.hpp"
|
||||
last-revision="$Date$">
|
||||
<namespace name="boost">
|
||||
<class name="condition">
|
||||
<inherit access="private">
|
||||
<type><classname>boost::noncopyable</classname></type>
|
||||
<purpose>Exposition only</purpose>
|
||||
</inherit>
|
||||
|
||||
<purpose>
|
||||
<para>An object of class <classname>condition</classname> is a
|
||||
synchronization primitive used to cause a thread to wait until a
|
||||
particular shared-data condition (or time) is met.</para>
|
||||
</purpose>
|
||||
|
||||
<description>
|
||||
<para>A <classname>condition</classname> object is always used in
|
||||
conjunction with a <link linkend="thread.concepts.mutexes">mutex</link>
|
||||
object (an object whose type is a model of a <link
|
||||
linkend="thread.concepts.Mutex">Mutex</link> or one of its
|
||||
refinements). The mutex object must be locked prior to waiting on the
|
||||
condition, which is verified by passing a lock object (an object whose
|
||||
type is a model of <link linkend="thread.concepts.Lock">Lock</link> or
|
||||
one of its refinements) to the <classname>condition</classname> object's
|
||||
wait functions. Upon blocking on the <classname>condition</classname>
|
||||
object, the thread unlocks the mutex object. When the thread returns
|
||||
from a call to one of the <classname>condition</classname> object's wait
|
||||
functions the mutex object is again locked. The tricky unlock/lock
|
||||
sequence is performed automatically by the
|
||||
<classname>condition</classname> object's wait functions.</para>
|
||||
<para>The <classname>condition</classname> type is often used to
|
||||
implement the Monitor Object and other important patterns (see
|
||||
&cite.SchmidtStalRohnertBuschmann; and &cite.Hoare74;). Monitors are one
|
||||
of the most important patterns for creating reliable multithreaded
|
||||
programs.</para>
|
||||
<para>See <xref linkend="thread.glossary"/> for definitions of <link
|
||||
linkend="thread.glossary.thread-state">thread states</link>
|
||||
blocked and ready. Note that "waiting" is a synonym for blocked.</para>
|
||||
</description>
|
||||
|
||||
<constructor>
|
||||
<effects><simpara>Constructs a <classname>condition</classname>
|
||||
object.</simpara></effects>
|
||||
</constructor>
|
||||
|
||||
<destructor>
|
||||
<effects><simpara>Destroys <code>*this</code>.</simpara></effects>
|
||||
</destructor>
|
||||
|
||||
<method-group name="notification">
|
||||
<method name="notify_one">
|
||||
<type>void</type>
|
||||
<effects><simpara>If there is a thread waiting on <code>*this</code>,
|
||||
change that thread's state to ready. Otherwise there is no
|
||||
effect.</simpara></effects>
|
||||
<notes><simpara>If more than one thread is waiting on <code>*this</code>,
|
||||
it is unspecified which is made ready. After returning to a ready
|
||||
state the notified thread must still acquire the mutex again (which
|
||||
occurs within the call to one of the <classname>condition</classname>
|
||||
object's wait functions.)</simpara></notes>
|
||||
</method>
|
||||
|
||||
<method name="notify_all">
|
||||
<type>void</type>
|
||||
<effects><simpara>Change the state of all threads waiting on
|
||||
<code>*this</code> to ready. If there are no waiting threads,
|
||||
<code>notify_all()</code> has no effect.</simpara></effects>
|
||||
</method>
|
||||
</method-group>
|
||||
|
||||
<method-group name="waiting">
|
||||
<method name="wait">
|
||||
<template>
|
||||
<template-type-parameter name="ScopedLock"/>
|
||||
</template>
|
||||
|
||||
<type>void</type>
|
||||
|
||||
<parameter name="lock">
|
||||
<paramtype>ScopedLock&</paramtype>
|
||||
</parameter>
|
||||
|
||||
<requires><simpara><code>ScopedLock</code> meets the <link
|
||||
linkend="thread.concepts.ScopedLock">ScopedLock</link>
|
||||
requirements.</simpara></requires>
|
||||
<effects><simpara>Releases the lock on the <link
|
||||
linkend="thread.concepts.mutexes">mutex object</link>
|
||||
associated with <code>lock</code>, blocks the current thread of execution
|
||||
until readied by a call to <code>this->notify_one()</code>
|
||||
or<code> this->notify_all()</code>, and then reacquires the
|
||||
lock.</simpara></effects>
|
||||
<throws><simpara><classname>lock_error</classname> if
|
||||
<code>!lock.locked()</code></simpara></throws>
|
||||
</method>
|
||||
|
||||
<method name="wait">
|
||||
<template>
|
||||
<template-type-parameter name="ScopedLock"/>
|
||||
<template-type-parameter name="Pred"/>
|
||||
</template>
|
||||
|
||||
<type>void</type>
|
||||
|
||||
<parameter name="lock">
|
||||
<paramtype>ScopedLock&</paramtype>
|
||||
</parameter>
|
||||
|
||||
<parameter name="pred">
|
||||
<paramtype>Pred</paramtype>
|
||||
</parameter>
|
||||
|
||||
<requires><simpara><code>ScopedLock</code> meets the <link
|
||||
linkend="thread.concepts.ScopedLock">ScopedLock</link>
|
||||
requirements and the return from <code>pred()</code> is
|
||||
convertible to <code>bool</code>.</simpara></requires>
|
||||
<effects><simpara>As if: <code>while (!pred())
|
||||
wait(lock)</code></simpara></effects>
|
||||
<throws><simpara><classname>lock_error</classname> if
|
||||
<code>!lock.locked()</code></simpara></throws>
|
||||
</method>
|
||||
|
||||
<method name="timed_wait">
|
||||
<template>
|
||||
<template-type-parameter name="ScopedLock"/>
|
||||
</template>
|
||||
|
||||
<type>bool</type>
|
||||
|
||||
<parameter name="lock">
|
||||
<paramtype>ScopedLock&</paramtype>
|
||||
</parameter>
|
||||
|
||||
<parameter name="xt">
|
||||
<paramtype>const <classname>boost::xtime</classname>&</paramtype>
|
||||
</parameter>
|
||||
|
||||
<requires><simpara><code>ScopedLock</code> meets the <link
|
||||
linkend="thread.concepts.ScopedLock">ScopedLock</link>
|
||||
requirements.</simpara></requires>
|
||||
<effects><simpara>Releases the lock on the <link
|
||||
linkend="thread.concepts.mutexes">mutex object</link>
|
||||
associated with <code>lock</code>, blocks the current thread of execution
|
||||
until readied by a call to <code>this->notify_one()</code>
|
||||
or<code> this->notify_all()</code>, or until time <code>xt</code>
|
||||
is reached, and then reacquires the lock.</simpara></effects>
|
||||
<returns><simpara><code>false</code> if time <code>xt</code> is reached,
|
||||
otherwise <code>true</code>.</simpara></returns>
|
||||
<throws><simpara><classname>lock_error</classname> if
|
||||
<code>!lock.locked()</code></simpara></throws>
|
||||
</method>
|
||||
|
||||
<method name="timed_wait">
|
||||
<template>
|
||||
<template-type-parameter name="ScopedLock"/>
|
||||
<template-type-parameter name="Pred"/>
|
||||
</template>
|
||||
|
||||
<type>bool</type>
|
||||
|
||||
<parameter name="lock">
|
||||
<paramtype>ScopedLock&</paramtype>
|
||||
</parameter>
|
||||
|
||||
<parameter name="xt">
|
||||
<paramtype>const <classname>boost::xtime</classname>&</paramtype>
|
||||
</parameter>
|
||||
|
||||
<parameter name="pred">
|
||||
<paramtype>Pred</paramtype>
|
||||
</parameter>
|
||||
|
||||
<requires><simpara><code>ScopedLock</code> meets the <link
|
||||
linkend="thread.concepts.ScopedLock">ScopedLock</link>
|
||||
requirements and the return from <code>pred()</code> is
|
||||
convertible to <code>bool</code>.</simpara></requires>
|
||||
<effects><simpara>As if: <code>while (!pred()) { if (!timed_wait(lock,
|
||||
xt)) return false; } return true;</code></simpara></effects>
|
||||
<returns><simpara><code>false</code> if <code>xt</code> is reached,
|
||||
otherwise <code>true</code>.</simpara></returns>
|
||||
<throws><simpara><classname>lock_error</classname> if
|
||||
<code>!lock.locked()</code></simpara></throws>
|
||||
</method>
|
||||
</method-group>
|
||||
</class>
|
||||
</namespace>
|
||||
</header>
|
||||
96
doc/configuration.xml
Normal file
96
doc/configuration.xml
Normal file
@@ -0,0 +1,96 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
||||
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
|
||||
<!ENTITY % thread.entities SYSTEM "entities.xml">
|
||||
%thread.entities;
|
||||
]>
|
||||
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
|
||||
Subject to the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
|
||||
-->
|
||||
<section id="thread.configuration" last-revision="$Date$">
|
||||
<title>Configuration</title>
|
||||
<para>&Boost.Thread; uses several configuration macros in <boost/config.hpp>,
|
||||
as well as configuration macros meant to be supplied by the application. These
|
||||
macros are documented here.
|
||||
</para>
|
||||
<section id="thread.configuration.public">
|
||||
<title>Library Defined Public Macros</title>
|
||||
<para>
|
||||
These macros are defined by &Boost.Thread; but are expected to be used
|
||||
by application code.
|
||||
</para>
|
||||
<informaltable>
|
||||
<tgroup cols="2">
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Macro</entry>
|
||||
<entry>Meaning</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>BOOST_HAS_THREADS</entry>
|
||||
<entry>
|
||||
Indicates that threading support is available. This means both that there
|
||||
is a platform specific implementation for &Boost.Thread; and that
|
||||
threading support has been enabled in a platform specific manner. For instance,
|
||||
on the Win32 platform there's an implementation for &Boost.Thread;
|
||||
but unless the program is compiled against one of the multithreading runtimes
|
||||
(often determined by the compiler predefining the macro _MT) the BOOST_HAS_THREADS
|
||||
macro remains undefined.
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</informaltable>
|
||||
</section>
|
||||
<section id="thread.configuration.implementation">
|
||||
<title>Library Defined Implementation Macros</title>
|
||||
<para>
|
||||
These macros are defined by &Boost.Thread; and are implementation details
|
||||
of interest only to implementors.
|
||||
</para>
|
||||
<informaltable>
|
||||
<tgroup cols="2">
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Macro</entry>
|
||||
<entry>Meaning</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>BOOST_HAS_WINTHREADS</entry>
|
||||
<entry>
|
||||
Indicates that the platform has the Microsoft Win32 threading libraries,
|
||||
and that they should be used to implement &Boost.Thread;.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>BOOST_HAS_PTHREADS</entry>
|
||||
<entry>
|
||||
Indicates that the platform has the POSIX pthreads libraries, and that
|
||||
they should be used to implement &Boost.Thread;.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>BOOST_HAS_FTIME</entry>
|
||||
<entry>
|
||||
Indicates that the implementation should use GetSystemTimeAsFileTime()
|
||||
and the FILETIME type to calculate the current time. This is an implementation
|
||||
detail used by boost::detail::getcurtime().
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>BOOST_HAS_GETTTIMEOFDAY</entry>
|
||||
<entry>
|
||||
Indicates that the implementation should use gettimeofday() to calculate
|
||||
the current time. This is an implementation detail used by boost::detail::getcurtime().
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</informaltable>
|
||||
</section>
|
||||
</section>
|
||||
159
doc/design.xml
Normal file
159
doc/design.xml
Normal file
@@ -0,0 +1,159 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
||||
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
|
||||
<!ENTITY % thread.entities SYSTEM "entities.xml">
|
||||
%thread.entities;
|
||||
]>
|
||||
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
|
||||
Subject to the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
|
||||
-->
|
||||
<section id="thread.design" last-revision="$Date$">
|
||||
<title>Design</title>
|
||||
<para>With client/server and three-tier architectures becoming common place
|
||||
in today's world, it's becoming increasingly important for programs to be
|
||||
able to handle parallel processing. Modern day operating systems usually
|
||||
provide some support for this through native thread APIs. Unfortunately,
|
||||
writing portable code that makes use of parallel processing in C++ is made
|
||||
very difficult by a lack of a standard interface for these native APIs.
|
||||
Further, these APIs are almost universally C APIs and fail to take
|
||||
advantage of C++'s strengths, or to address concepts unique to C++, such as
|
||||
exceptions.</para>
|
||||
<para>The &Boost.Thread; library is an attempt to define a portable interface
|
||||
for writing parallel processes in C++.</para>
|
||||
<section id="thread.design.goals">
|
||||
<title>Goals</title>
|
||||
<para>The &Boost.Thread; library has several goals that should help to set
|
||||
it apart from other solutions. These goals are listed in order of precedence
|
||||
with full descriptions below.
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>Portability</term>
|
||||
<listitem>
|
||||
<para>&Boost.Thread; was designed to be highly portable. The goal is
|
||||
for the interface to be easily implemented on any platform that
|
||||
supports threads, and possibly even on platforms without native thread
|
||||
support.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>Safety</term>
|
||||
<listitem>
|
||||
<para>&Boost.Thread; was designed to be as safe as possible. Writing
|
||||
<link linkend="thread.glossary.thread-safe">thread-safe</link>
|
||||
code is very difficult and successful libraries must strive to
|
||||
insulate the programmer from dangerous constructs as much as
|
||||
possible. This is accomplished in several ways:
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>C++ language features are used to make correct usage easy
|
||||
(if possible) and error-prone usage impossible or at least more
|
||||
difficult. For example, see the <link
|
||||
linkend="thread.concepts.Mutex">Mutex</link> and <link
|
||||
linkend="thread.concepts.Lock">Lock</link> designs, and note
|
||||
how they interact.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Certain traditional concurrent programming features are
|
||||
considered so error-prone that they are not provided at all. For
|
||||
example, see <xref linkend="thread.rationale.events" />.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Dangerous features, or features which may be misused, are
|
||||
identified as such in the documentation to make users aware of
|
||||
potential pitfalls.</para>
|
||||
</listitem>
|
||||
</itemizedlist></para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>Flexibility</term>
|
||||
<listitem>
|
||||
<para>&Boost.Thread; was designed to be flexible. This goal is often
|
||||
at odds with <emphasis>safety</emphasis>. When functionality might be
|
||||
compromised by the desire to keep the interface safe, &Boost.Thread;
|
||||
has been designed to provide the functionality, but to make it's use
|
||||
prohibitive for general use. In other words, the interfaces have been
|
||||
designed such that it's usually obvious when something is unsafe, and
|
||||
the documentation is written to explain why.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>Efficiency</term>
|
||||
<listitem>
|
||||
<para>&Boost.Thread; was designed to be as efficient as
|
||||
possible. When building a library on top of another library there is
|
||||
always a danger that the result will be so much slower than the
|
||||
"native" API that programmers are inclined to ignore the higher level
|
||||
API. &Boost.Thread; was designed to minimize the chances of this
|
||||
occurring. The interfaces have been crafted to allow an implementation
|
||||
the greatest chance of being as efficient as possible. This goal is
|
||||
often at odds with the goal for <emphasis>safety</emphasis>. Every
|
||||
effort was made to ensure efficient implementations, but when in
|
||||
conflict <emphasis>safety</emphasis> has always taken
|
||||
precedence.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist></para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Iterative Phases</title>
|
||||
<para>Another goal of &Boost.Thread; was to take a dynamic, iterative
|
||||
approach in its development. The computing industry is still exploring the
|
||||
concepts of parallel programming. Most thread libraries supply only simple
|
||||
primitive concepts for thread synchronization. These concepts are very
|
||||
simple, but it is very difficult to use them safely or to provide formal
|
||||
proofs for constructs built on top of them. There has been a lot of research
|
||||
into other concepts, such as in "Communicating Sequential Processes."
|
||||
&Boost.Thread; was designed in iterative steps, with each step providing
|
||||
the building blocks necessary for the next step and giving the researcher
|
||||
the tools necessary to explore new concepts in a portable manner.</para>
|
||||
<para>Given the goal of following a dynamic, iterative approach
|
||||
&Boost.Thread; shall go through several growth cycles. Each phase in its
|
||||
development shall be roughly documented here.</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Phase 1, Synchronization Primitives</title>
|
||||
<para>Boost is all about providing high quality libraries with
|
||||
implementations for many platforms. Unfortunately, there's a big problem
|
||||
faced by developers wishing to supply such high quality libraries, namely
|
||||
thread-safety. The C++ standard doesn't address threads at all, but real
|
||||
world programs often make use of native threading support. A portable
|
||||
library that doesn't address the issue of thread-safety is therefore not
|
||||
much help to a programmer who wants to use the library in his multithreaded
|
||||
application. So there's a very great need for portable primitives that will
|
||||
allow the library developer to create <link
|
||||
linkend="thread.glossary.thread-safe">thread-safe</link>
|
||||
implementations. This need far out weighs the need for portable methods to
|
||||
create and manage threads.</para>
|
||||
<para>Because of this need, the first phase of &Boost.Thread; focuses
|
||||
solely on providing portable primitive concepts for thread
|
||||
synchronization. Types provided in this phase include the
|
||||
<classname>boost::mutex</classname>,
|
||||
<classname>boost::try_mutex</classname>,
|
||||
<classname>boost::timed_mutex</classname>,
|
||||
<classname>boost::recursive_mutex</classname>,
|
||||
<classname>boost::recursive_try_mutex</classname>,
|
||||
<classname>boost::recursive_timed_mutex</classname>, and
|
||||
<classname>boost::lock_error</classname>. These are considered the "core"
|
||||
synchronization primitives, though there are others that will be added in
|
||||
later phases.</para>
|
||||
</section>
|
||||
<section id="thread.design.phase2">
|
||||
<title>Phase 2, Thread Management and Thread Specific Storage</title>
|
||||
<para>This phase addresses the creation and management of threads and
|
||||
provides a mechanism for thread specific storage (data associated with a
|
||||
thread instance). Thread management is a tricky issue in C++, so this
|
||||
phase addresses only the basic needs of multithreaded program. Later
|
||||
phases are likely to add additional functionality in this area. This
|
||||
phase of &Boost.Thread; adds the <classname>boost::thread</classname> and
|
||||
<classname>boost::thread_specific_ptr</classname> types. With these
|
||||
additions the &Boost.Thread; library can be considered minimal but
|
||||
complete.</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>The Next Phase</title>
|
||||
<para>The next phase will address more advanced synchronization concepts,
|
||||
such as read/write mutexes and barriers.</para>
|
||||
</section>
|
||||
</section>
|
||||
31
doc/entities.xml
Normal file
31
doc/entities.xml
Normal file
@@ -0,0 +1,31 @@
|
||||
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
|
||||
Subject to the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
|
||||
-->
|
||||
<!ENTITY Boost "<emphasis role='bold'>Boost</emphasis>">
|
||||
<!ENTITY Boost.Thread "<emphasis role='bold'>Boost.Thread</emphasis>">
|
||||
<!ENTITY Boost.Build "<emphasis role='bold'>Boost.Build</emphasis>">
|
||||
<!ENTITY cite.AndrewsSchneider83 "<citation><xref
|
||||
linkend='thread.bib.AndrewsSchneider83'
|
||||
endterm='thread.bib.AndrewsSchneider83.abbrev'/></citation>">
|
||||
<!ENTITY cite.Boost "<citation><xref linkend='thread.bib.Boost'
|
||||
endterm='thread.bib.Boost.abbrev'/></citation>">
|
||||
<!ENTITY cite.Hansen73 "<citation><xref linkend='thread.bib.Hansen73'
|
||||
endterm='thread.bib.Hansen73.abbrev'/></citation>">
|
||||
<!ENTITY cite.Butenhof97 "<citation><xref linkend='thread.bib.Butenhof97'
|
||||
endterm='thread.bib.Butenhof97.abbrev'/></citation>">
|
||||
<!ENTITY cite.Hoare74 "<citation><xref linkend='thread.bib.Hoare74'
|
||||
endterm='thread.bib.Hoare74.abbrev'/></citation>">
|
||||
<!ENTITY cite.ISO98 "<citation><xref linkend='thread.bib.ISO98'
|
||||
endterm='thread.bib.ISO98.abbrev'/></citation>">
|
||||
<!ENTITY cite.McDowellHelmbold89 "<citation><xref
|
||||
linkend='thread.bib.McDowellHelmbold89'
|
||||
endterm='thread.bib.McDowellHelmbold89.abbrev'/></citation>">
|
||||
<!ENTITY cite.SchmidtPyarali "<citation><xref
|
||||
linkend='thread.bib.SchmidtPyarali'
|
||||
endterm='thread.bib.SchmidtPyarali.abbrev'/></citation>">
|
||||
<!ENTITY cite.SchmidtStalRohnertBuschmann "<citation><xref
|
||||
linkend='thread.bib.SchmidtStalRohnertBuschmann'
|
||||
endterm='thread.bib.SchmidtStalRohnertBuschmann.abbrev'/></citation>">
|
||||
<!ENTITY cite.Stroustrup "<citation><xref linkend='thread.bib.Stroustrup'
|
||||
endterm='thread.bib.Stroustrup.abbrev'/></citation>">
|
||||
62
doc/exceptions-ref.xml
Normal file
62
doc/exceptions-ref.xml
Normal file
@@ -0,0 +1,62 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
||||
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
|
||||
<!ENTITY % thread.entities SYSTEM "entities.xml">
|
||||
%thread.entities;
|
||||
]>
|
||||
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
|
||||
Subject to the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
|
||||
-->
|
||||
<header name="boost/thread/exceptions.hpp"
|
||||
last-revision="$Date$">
|
||||
<namespace name="boost">
|
||||
<class name="lock_error">
|
||||
<purpose>
|
||||
<simpara>The lock_error class defines an exception type thrown
|
||||
to indicate a locking related error has been detected.</simpara>
|
||||
</purpose>
|
||||
|
||||
<description>
|
||||
<simpara>Examples of errors indicated by a lock_error exception
|
||||
include a lock operation which can be determined to result in a
|
||||
deadlock, or unlock operations attempted by a thread that does
|
||||
not own the lock.</simpara>
|
||||
</description>
|
||||
|
||||
<inherit access="public">
|
||||
<type><classname>std::logical_error</classname></type>
|
||||
</inherit>
|
||||
|
||||
<constructor>
|
||||
<effects><simpara>Constructs a <code>lock_error</code> object.
|
||||
</simpara></effects>
|
||||
</constructor>
|
||||
</class>
|
||||
|
||||
<class name="thread_resource_error">
|
||||
<purpose>
|
||||
<simpara>The <classname>thread_resource_error</classname> class
|
||||
defines an exception type that is thrown by constructors in the
|
||||
&Boost.Thread; library when thread-related resources can not be
|
||||
acquired.</simpara>
|
||||
</purpose>
|
||||
|
||||
<description>
|
||||
<simpara><classname>thread_resource_error</classname> is used
|
||||
only when thread-related resources cannot be acquired; memory
|
||||
allocation failures are indicated by
|
||||
<classname>std::bad_alloc</classname>.</simpara>
|
||||
</description>
|
||||
|
||||
<inherit access="public">
|
||||
<type><classname>std::runtime_error</classname></type>
|
||||
</inherit>
|
||||
|
||||
<constructor>
|
||||
<effects><simpara>Constructs a <code>thread_resource_error</code>
|
||||
object.</simpara></effects>
|
||||
</constructor>
|
||||
</class>
|
||||
</namespace>
|
||||
</header>
|
||||
235
doc/faq.xml
Normal file
235
doc/faq.xml
Normal file
@@ -0,0 +1,235 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
||||
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
|
||||
<!ENTITY % thread.entities SYSTEM "entities.xml">
|
||||
%thread.entities;
|
||||
]>
|
||||
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
|
||||
Subject to the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
|
||||
-->
|
||||
<section id="thread.faq" last-revision="$Date$">
|
||||
<title>Frequently Asked Questions</title>
|
||||
<qandaset>
|
||||
<qandaentry>
|
||||
<question>
|
||||
<para>Are lock objects <link
|
||||
linkend="thread.glossary.thread-safe">thread safe</link>?</para>
|
||||
</question>
|
||||
<answer>
|
||||
<para><emphasis role="bold">No!</emphasis> Lock objects are not meant to
|
||||
be shared between threads. They are meant to be short-lived objects
|
||||
created on automatic storage within a code block. Any other usage is
|
||||
just likely to lead to errors and won't really be of actual benefit anyway.
|
||||
Share <link linkend="thread.concepts.mutexes">Mutexes</link>, not
|
||||
Locks. For more information see the <link
|
||||
linkend="thread.rationale.locks">rationale</link> behind the
|
||||
design for lock objects.</para>
|
||||
</answer>
|
||||
</qandaentry>
|
||||
<qandaentry>
|
||||
<question>
|
||||
<para>Why was &Boost.Thread; modeled after (specific library
|
||||
name)?</para>
|
||||
</question>
|
||||
<answer>
|
||||
<para>It wasn't. &Boost.Thread; was designed from scratch. Extensive
|
||||
design discussions involved numerous people representing a wide range of
|
||||
experience across many platforms. To ensure portability, the initial
|
||||
implements were done in parallel using POSIX Threads and the Win32
|
||||
threading API. But the &Boost.Thread; design is very much in the spirit
|
||||
of C++, and thus doesn't model such C based APIs.</para>
|
||||
</answer>
|
||||
</qandaentry>
|
||||
<qandaentry>
|
||||
<question>
|
||||
<para>Why wasn't &Boost.Thread; modeled after (specific library
|
||||
name)?</para>
|
||||
</question>
|
||||
<answer>
|
||||
<para>Existing C++ libraries either seemed dangerous (often failing to
|
||||
take advantage of prior art to reduce errors) or had excessive
|
||||
dependencies on library components unrelated to threading. Existing C
|
||||
libraries couldn't meet our C++ requirements, and were also missing
|
||||
certain features. For instance, the WIN32 thread API lacks condition
|
||||
variables, even though these are critical for the important Monitor
|
||||
pattern &cite.SchmidtStalRohnertBuschmann;.</para>
|
||||
</answer>
|
||||
</qandaentry>
|
||||
<qandaentry>
|
||||
<question>
|
||||
<para>Why do <link linkend="thread.concepts.mutexes">Mutexes</link>
|
||||
have noncopyable semantics?</para>
|
||||
</question>
|
||||
<answer>
|
||||
<para>To ensure that <link
|
||||
linkend="thread.glossary.deadlock">deadlocks</link> don't occur. The
|
||||
only logical form of copy would be to use some sort of shallow copy
|
||||
semantics in which multiple mutex objects could refer to the same mutex
|
||||
state. This means that if ObjA has a mutex object as part of its state
|
||||
and ObjB is copy constructed from it, then when ObjB::foo() locks the
|
||||
mutex it has effectively locked ObjA as well. This behavior can result
|
||||
in deadlock. Other copy semantics result in similar problems (if you
|
||||
think you can prove this to be wrong then supply us with an alternative
|
||||
and we'll reconsider).</para>
|
||||
</answer>
|
||||
</qandaentry>
|
||||
<qandaentry>
|
||||
<question>
|
||||
<para>How can you prevent <link
|
||||
linkend="thread.glossary.deadlock">deadlock</link> from occurring when
|
||||
a thread must lock multiple mutexes?</para>
|
||||
</question>
|
||||
<answer>
|
||||
<para>Always lock them in the same order. One easy way of doing this is
|
||||
to use each mutex's address to determine the order in which they are
|
||||
locked. A future &Boost.Thread; concept may wrap this pattern up in a
|
||||
reusable class.</para>
|
||||
</answer>
|
||||
</qandaentry>
|
||||
<qandaentry>
|
||||
<question>
|
||||
<para>Don't noncopyable <link
|
||||
linkend="thread.concepts.mutexes">Mutex</link> semantics mean that a
|
||||
class with a mutex member will be noncopyable as well?</para>
|
||||
</question>
|
||||
<answer>
|
||||
<para>No, but what it does mean is that the compiler can't generate a
|
||||
copy constructor and assignment operator, so they will have to be coded
|
||||
explicitly. This is a <emphasis role="bold">good thing</emphasis>,
|
||||
however, since the compiler generated operations would not be <link
|
||||
linkend="thread.glossary.thread-safe">thread-safe</link>. The following
|
||||
is a simple example of a class with copyable semantics and internal
|
||||
synchronization through a mutex member.</para>
|
||||
<programlisting>
|
||||
class counter
|
||||
{
|
||||
public:
|
||||
// Doesn't need synchronization since there can be no references to *this
|
||||
// until after it's constructed!
|
||||
explicit counter(int initial_value)
|
||||
: m_value(initial_value)
|
||||
{
|
||||
}
|
||||
// We only need to synchronize other for the same reason we don't have to
|
||||
// synchronize on construction!
|
||||
counter(const counter& other)
|
||||
{
|
||||
boost::mutex::scoped_lock scoped_lock(other.m_mutex);
|
||||
m_value = other.m_value;
|
||||
}
|
||||
// For assignment we need to synchronize both objects!
|
||||
const counter& operator=(const counter& other)
|
||||
{
|
||||
if (this == &other)
|
||||
return *this;
|
||||
boost::mutex::scoped_lock lock1(&m_mutex < &other.m_mutex ? m_mutex : other.m_mutex);
|
||||
boost::mutex::scoped_lock lock2(&m_mutex > &other.m_mutex ? m_mutex : other.m_mutex);
|
||||
m_value = other.m_value;
|
||||
return *this;
|
||||
}
|
||||
int value() const
|
||||
{
|
||||
boost::mutex::scoped_lock scoped_lock(m_mutex);
|
||||
return m_value;
|
||||
}
|
||||
int increment()
|
||||
{
|
||||
boost::mutex::scoped_lock scoped_lock(m_mutex);
|
||||
return ++m_value;
|
||||
}
|
||||
private:
|
||||
mutable boost::mutex m_mutex;
|
||||
int m_value;
|
||||
};
|
||||
</programlisting>
|
||||
</answer>
|
||||
</qandaentry>
|
||||
<qandaentry>
|
||||
<question>
|
||||
<para>How can you lock a <link
|
||||
linkend="thread.concepts.mutexes">Mutex</link> member in a const member
|
||||
function, in order to implement the Monitor Pattern?</para>
|
||||
</question>
|
||||
<answer>
|
||||
<para>The Monitor Pattern &cite.SchmidtStalRohnertBuschmann; mutex
|
||||
should simply be declared as mutable. See the example code above. The
|
||||
internal state of mutex types could have been made mutable, with all
|
||||
lock calls made via const functions, but this does a poor job of
|
||||
documenting the actual semantics (and in fact would be incorrect since
|
||||
the logical state of a locked mutex clearly differs from the logical
|
||||
state of an unlocked mutex). Declaring a mutex member as mutable clearly
|
||||
documents the intended semantics.</para>
|
||||
</answer>
|
||||
</qandaentry>
|
||||
<qandaentry>
|
||||
<question>
|
||||
<para>Why supply <classname>boost::condition</classname> variables rather than
|
||||
event variables?</para>
|
||||
</question>
|
||||
<answer>
|
||||
<para>Condition variables result in user code much less prone to <link
|
||||
linkend="thread.glossary.race-condition">race conditions</link> than
|
||||
event variables. See <xref linkend="thread.rationale.events" />
|
||||
for analysis. Also see &cite.Hoare74; and &cite.SchmidtStalRohnertBuschmann;.
|
||||
</para>
|
||||
</answer>
|
||||
</qandaentry>
|
||||
<qandaentry>
|
||||
<question>
|
||||
<para>Why isn't thread cancellation or termination provided?</para>
|
||||
</question>
|
||||
<answer>
|
||||
<para>There's a valid need for thread termination, so at some point
|
||||
&Boost.Thread; probably will include it, but only after we can find a
|
||||
truly safe (and portable) mechanism for this concept.</para>
|
||||
</answer>
|
||||
</qandaentry>
|
||||
<qandaentry>
|
||||
<question>
|
||||
<para>Is it safe for threads to share automatic storage duration (stack)
|
||||
objects via pointers or references?</para>
|
||||
</question>
|
||||
<answer>
|
||||
<para>Only if you can guarantee that the lifetime of the stack object
|
||||
will not end while other threads might still access the object. Thus the
|
||||
safest practice is to avoid sharing stack objects, particularly in
|
||||
designs where threads are created and destroyed dynamically. Restrict
|
||||
sharing of stack objects to simple designs with very clear and
|
||||
unchanging function and thread lifetimes. (Suggested by Darryl
|
||||
Green).</para>
|
||||
</answer>
|
||||
</qandaentry>
|
||||
<qandaentry>
|
||||
<question>
|
||||
<para>Why has class semaphore disappeared?</para>
|
||||
</question>
|
||||
<answer>
|
||||
<para>Semaphore was removed as too error prone. The same effect can be
|
||||
achieved with greater safety by the combination of a mutex and a
|
||||
condition variable.</para>
|
||||
</answer>
|
||||
</qandaentry>
|
||||
<qandaentry>
|
||||
<question>
|
||||
<para>Why doesn't the thread's ctor take at least a void* to pass any
|
||||
information along with the function? All other threading libs support
|
||||
that and it makes Boost.Threads inferiour. </para>
|
||||
</question>
|
||||
<answer>
|
||||
<para>There is no need, because Boost.Threads are superiour! First
|
||||
thing is that its ctor doesn't take a function but a functor. That
|
||||
means that you can pass an object with an overloaded operator() and
|
||||
include additional data as members in that object. Beware though that
|
||||
this object is copied, use boost::ref to prevent that. Secondly, even
|
||||
a boost::function<void (void)> can carry parameters, you only have to
|
||||
use boost::bind() to create it from any function and bind its
|
||||
parameters.</para>
|
||||
<para>That is also why Boost.Threads are superiour, because they
|
||||
don't require you to pass a type-unsafe void pointer. Rather, you can
|
||||
use the flexible Boost.Functions to create a thread entry out of
|
||||
anything that can be called.</para>
|
||||
</answer>
|
||||
</qandaentry>
|
||||
</qandaset>
|
||||
</section>
|
||||
304
doc/glossary.xml
Normal file
304
doc/glossary.xml
Normal file
@@ -0,0 +1,304 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
||||
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
|
||||
<!ENTITY % thread.entities SYSTEM "entities.xml">
|
||||
%thread.entities;
|
||||
]>
|
||||
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
|
||||
Subject to the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
|
||||
-->
|
||||
<glossary id="thread.glossary" last-revision="$Date$">
|
||||
<title>Glossary</title>
|
||||
<para>Definitions are given in terms of the C++ Standard
|
||||
&cite.ISO98;. References to the standard are in the form [1.2.3/4], which
|
||||
represents the section number, with the paragraph number following the
|
||||
"/".</para>
|
||||
<para>Because the definitions are written in something akin to "standardese",
|
||||
they can be difficult to understand. The intent isn't to confuse, but rather
|
||||
to clarify the additional requirements &Boost.Thread; places on a C++
|
||||
implementation as defined by the C++ Standard.</para>
|
||||
<glossentry id="thread.glossary.thread">
|
||||
<glossterm>Thread</glossterm>
|
||||
<glossdef>
|
||||
<para>Thread is short for "thread of execution". A thread of execution is
|
||||
an execution environment [1.9/7] within the execution environment of a C++
|
||||
program [1.9]. The main() function [3.6.1] of the program is the initial
|
||||
function of the initial thread. A program in a multithreading environment
|
||||
always has an initial thread even if the program explicitly creates no
|
||||
additional threads.</para>
|
||||
<para>Unless otherwise specified, each thread shares all aspects of its
|
||||
execution environment with other threads in the program. Shared aspects of
|
||||
the execution environment include, but are not limited to, the
|
||||
following:</para>
|
||||
<itemizedlist>
|
||||
<listitem><para>Static storage duration (static, extern) objects
|
||||
[3.7.1].</para></listitem>
|
||||
<listitem><para>Dynamic storage duration (heap) objects [3.7.3]. Thus
|
||||
each memory allocation will return a unique addresses, regardless of the
|
||||
thread making the allocation request.</para></listitem>
|
||||
<listitem><para>Automatic storage duration (stack) objects [3.7.2]
|
||||
accessed via pointer or reference from another thread.</para></listitem>
|
||||
<listitem><para>Resources provided by the operating system. For example,
|
||||
files.</para></listitem>
|
||||
<listitem><para>The program itself. In other words, each thread is
|
||||
executing some function of the same program, not a totally different
|
||||
program.</para></listitem>
|
||||
</itemizedlist>
|
||||
<para>Each thread has its own:</para>
|
||||
<itemizedlist>
|
||||
<listitem><para>Registers and current execution sequence (program
|
||||
counter) [1.9/5].</para></listitem>
|
||||
<listitem><para>Automatic storage duration (stack) objects
|
||||
[3.7.2].</para></listitem>
|
||||
</itemizedlist>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
<glossentry id="thread.glossary.thread-safe">
|
||||
<glossterm>Thread-safe</glossterm>
|
||||
<glossdef>
|
||||
<para>A program is thread-safe if it has no <link
|
||||
linkend="thread.glossary.race-condition">race conditions</link>, does
|
||||
not <link linkend="thread.glossary.deadlock">deadlock</link>, and has
|
||||
no <link linkend="thread.glossary.priority-failure">priority
|
||||
failures</link>.</para>
|
||||
<para>Note that thread-safety does not necessarily imply efficiency, and
|
||||
than while some thread-safety violations can be determined statically at
|
||||
compile time, many thread-safety errors can only only be detected at
|
||||
runtime.</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
<glossentry id="thread.glossary.thread-state">
|
||||
<glossterm>Thread State</glossterm>
|
||||
<glossdef>
|
||||
<para>During the lifetime of a thread, it shall be in one of the following
|
||||
states:</para>
|
||||
<table>
|
||||
<title>Thread States</title>
|
||||
<tgroup cols="2" align="left">
|
||||
<thead>
|
||||
<row>
|
||||
<entry>State</entry>
|
||||
<entry>Description</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>Ready</entry>
|
||||
<entry>Ready to run, but waiting for a processor.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>Running</entry>
|
||||
<entry>Currently executing on a processor. Zero or more threads
|
||||
may be running at any time, with a maximum equal to the number of
|
||||
processors.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>Blocked</entry>
|
||||
<entry>Waiting for some resource other than a processor which is
|
||||
not currently available, or for the completion of calls to library
|
||||
functions [1.9/6]. The term "waiting" is synonymous with
|
||||
"blocked"</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>Terminated</entry>
|
||||
<entry>Finished execution but not yet detached or joined.</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
<para>Thread state transitions shall occur only as specified:</para>
|
||||
<table>
|
||||
<title>Thread States Transitions</title>
|
||||
<tgroup cols="3" align="left">
|
||||
<thead>
|
||||
<row>
|
||||
<entry>From</entry>
|
||||
<entry>To</entry>
|
||||
<entry>Cause</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>[none]</entry>
|
||||
<entry>Ready</entry>
|
||||
<entry><para>Thread is created by a call to a library function.
|
||||
In the case of the initial thread, creation is implicit and
|
||||
occurs during the startup of the main() function [3.6.1].</para></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>Ready</entry>
|
||||
<entry>Running</entry>
|
||||
<entry><para>Processor becomes available.</para></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>Running</entry>
|
||||
<entry>Ready</entry>
|
||||
<entry>Thread preempted.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>Running</entry>
|
||||
<entry>Blocked</entry>
|
||||
<entry>Thread calls a library function which waits for a resource or
|
||||
for the completion of I/O.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>Running</entry>
|
||||
<entry>Terminated</entry>
|
||||
<entry>Thread returns from its initial function, calls a thread
|
||||
termination library function, or is canceled by some other thread
|
||||
calling a thread termination library function.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>Blocked</entry>
|
||||
<entry>Ready</entry>
|
||||
<entry>The resource being waited for becomes available, or the
|
||||
blocking library function completes.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>Terminated</entry>
|
||||
<entry>[none]</entry>
|
||||
<entry>Thread is detached or joined by some other thread calling the
|
||||
appropriate library function, or by program termination
|
||||
[3.6.3].</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
<para>[Note: if a suspend() function is added to the threading library,
|
||||
additional transitions to the blocked state will have to be added to the
|
||||
above table.]</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
<glossentry id="thread.glossary.race-condition">
|
||||
<glossterm>Race Condition</glossterm>
|
||||
<glossdef>
|
||||
<para>A race condition is what occurs when multiple threads read from and write
|
||||
to the same memory without proper synchronization, resulting in an incorrect
|
||||
value being read or written. The result of a race condition may be a bit
|
||||
pattern which isn't even a valid value for the data type. A race condition
|
||||
results in undefined behavior [1.3.12].</para>
|
||||
<para>Race conditions can be prevented by serializing memory access using
|
||||
the tools provided by &Boost.Thread;.</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
<glossentry id="thread.glossary.deadlock">
|
||||
<glossterm>Deadlock</glossterm>
|
||||
<glossdef>
|
||||
<para>Deadlock is an execution state where for some set of threads, each
|
||||
thread in the set is blocked waiting for some action by one of the other
|
||||
threads in the set. Since each is waiting on the others, none will ever
|
||||
become ready again.</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
<glossentry id="thread.glossary.starvation">
|
||||
<glossterm>Starvation</glossterm>
|
||||
<glossdef>
|
||||
<para>The condition in which a thread is not making sufficient progress in
|
||||
its work during a given time interval.</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
<glossentry id="thread.glossary.priority-failure">
|
||||
<glossterm>Priority Failure</glossterm>
|
||||
<glossdef>
|
||||
<para>A priority failure (such as priority inversion or infinite overtaking)
|
||||
occurs when threads are executed in such a sequence that required work is not
|
||||
performed in time to be useful.</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
<glossentry id="thread.glossary.undefined-behavior">
|
||||
<glossterm>Undefined Behavior</glossterm>
|
||||
<glossdef>
|
||||
<para>The result of certain operations in &Boost.Thread; is undefined;
|
||||
this means that those operations can invoke almost any behavior when
|
||||
they are executed.</para>
|
||||
|
||||
<para>An operation whose behavior is undefined can work "correctly"
|
||||
in some implementations (i.e., do what the programmer thought it
|
||||
would do), while in other implementations it may exhibit almost
|
||||
any "incorrect" behavior--such as returning an invalid value,
|
||||
throwing an exception, generating an access violation, or terminating
|
||||
the process.</para>
|
||||
|
||||
<para>Executing a statement whose behavior is undefined is a
|
||||
programming error.</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
<glossentry id="thread.glossary.memory-visibility">
|
||||
<glossterm>Memory Visibility</glossterm>
|
||||
<glossdef>
|
||||
<para>An address [1.7] shall always point to the same memory byte,
|
||||
regardless of the thread or processor dereferencing the address.</para>
|
||||
<para>An object [1.8, 1.9] is accessible from multiple threads if it is of
|
||||
static storage duration (static, extern) [3.7.1], or if a pointer or
|
||||
reference to it is explicitly or implicitly dereferenced in multiple
|
||||
threads.</para>
|
||||
<para>For an object accessible from multiple threads, the value of the
|
||||
object accessed from one thread may be indeterminate or different from the
|
||||
value accessed from another thread, except under the conditions specified in
|
||||
the following table. For the same row of the table, the value of an object
|
||||
accessible at the indicated sequence point in thread A will be determinate
|
||||
and the same if accessed at or after the indicated sequence point in thread
|
||||
B, provided the object is not otherwise modified. In the table, the
|
||||
"sequence point at a call" is the sequence point after the evaluation of all
|
||||
function arguments [1.9/17], while the "sequence point after a call" is the
|
||||
sequence point after the copying of the returned value... [1.9/17].</para>
|
||||
<table>
|
||||
<title>Memory Visibility</title>
|
||||
<tgroup cols="2">
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Thread A</entry>
|
||||
<entry>Thread B</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>The sequence point at a call to a library thread-creation
|
||||
function.</entry>
|
||||
<entry>The first sequence point of the initial function in the new
|
||||
thread created by the Thread A call.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>The sequence point at a call to a library function which
|
||||
locks a mutex, directly or by waiting for a condition
|
||||
variable.</entry>
|
||||
<entry>The sequence point after a call to a library function which
|
||||
unlocks the same mutex.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>The last sequence point before thread termination.</entry>
|
||||
<entry>The sequence point after a call to a library function which
|
||||
joins the terminated thread.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>The sequence point at a call to a library function which
|
||||
signals or broadcasts a condition variable.</entry>
|
||||
<entry>The sequence point after the call to the library function
|
||||
which was waiting on that same condition variable or signal.</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
<para>The architecture of the execution environment and the observable
|
||||
behavior of the abstract machine [1.9] shall be the same on all
|
||||
processors.</para>
|
||||
<para>The latitude granted by the C++ standard for an implementation to
|
||||
alter the definition of observable behavior of the abstract machine to
|
||||
include additional library I/O functions [1.9/6] is extended to include
|
||||
threading library functions.</para>
|
||||
<para>When an exception is thrown and there is no matching exception handler
|
||||
in the same thread, behavior is undefined. The preferred behavior is the
|
||||
same as when there is no matching exception handler in a program
|
||||
[15.3/9]. That is, terminate() is called, and it is implementation-defined
|
||||
whether or not the stack is unwound.</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
<section>
|
||||
<title>Acknowledgements</title>
|
||||
<para>This document was originally written by Beman Dawes, and then much
|
||||
improved by the incorporation of comments from William Kempf, who now
|
||||
maintains the contents.</para>
|
||||
<para>The visibility rules are based on &cite.Butenhof97;.</para>
|
||||
</section>
|
||||
</glossary>
|
||||
38
doc/implementation_notes.xml
Normal file
38
doc/implementation_notes.xml
Normal file
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
||||
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
|
||||
<!ENTITY % thread.entities SYSTEM "entities.xml">
|
||||
%thread.entities;
|
||||
]>
|
||||
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
|
||||
Subject to the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
|
||||
-->
|
||||
<section id="thread.implementation_notes" last-revision="$Date$">
|
||||
<title>Implementation Notes</title>
|
||||
<section id="thread.implementation_notes.win32">
|
||||
<title>Win32</title>
|
||||
<para>
|
||||
In the current Win32 implementation, creating a boost::thread object
|
||||
during dll initialization will result in deadlock because the thread
|
||||
class constructor causes the current thread to wait on the thread that
|
||||
is being created until it signals that it has finished its initialization,
|
||||
and, as stated in the
|
||||
<ulink url="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/dllmain.asp">MSDN Library, "DllMain" article, "Remarks" section</ulink>,
|
||||
"Because DLL notifications are serialized, entry-point functions should not
|
||||
attempt to communicate with other threads or processes. Deadlocks may occur as a result."
|
||||
(Also see <ulink url="http://www.microsoft.com/msj/archive/S220.aspx">"Under the Hood", January 1996</ulink>
|
||||
for a more detailed discussion of this issue).
|
||||
</para>
|
||||
<para>
|
||||
The following non-exhaustive list details some of the situations that
|
||||
should be avoided until this issue can be addressed:
|
||||
<itemizedlist>
|
||||
<listitem>Creating a boost::thread object in DllMain() or in any function called by it.</listitem>
|
||||
<listitem>Creating a boost::thread object in the constructor of a global static object or in any function called by one.</listitem>
|
||||
<listitem>Creating a boost::thread object in MFC's CWinApp::InitInstance() function or in any function called by it.</listitem>
|
||||
<listitem>Creating a boost::thread object in the function pointed to by MFC's _pRawDllMain function pointer or in any function called by it.</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
12
doc/index.html
Normal file
12
doc/index.html
Normal file
@@ -0,0 +1,12 @@
|
||||
<!-- Copyright (c) 2002-2003 Beman Dawes, William E. Kempf.
|
||||
Subject to the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="refresh" content="0; URL=../../../doc/html/thread.html">
|
||||
</head>
|
||||
<body>
|
||||
Automatic redirection failed, please go to <a href="../../../doc/html/thread.html">../../../doc/html/thread.html</a>
|
||||
</body>
|
||||
</html>
|
||||
309
doc/mutex-ref.xml
Normal file
309
doc/mutex-ref.xml
Normal file
@@ -0,0 +1,309 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
||||
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
|
||||
<!ENTITY % thread.entities SYSTEM "entities.xml">
|
||||
%thread.entities;
|
||||
]>
|
||||
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
|
||||
Subject to the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
|
||||
-->
|
||||
<header name="boost/thread/mutex.hpp"
|
||||
last-revision="$Date$">
|
||||
<namespace name="boost">
|
||||
<class name="mutex">
|
||||
<purpose>
|
||||
<para>The <classname>mutex</classname> class is a model of the
|
||||
<link linkend="thread.concepts.Mutex">Mutex</link> concept.</para>
|
||||
</purpose>
|
||||
|
||||
<description>
|
||||
<para>The <classname>mutex</classname> class is a model of the
|
||||
<link linkend="thread.concepts.Mutex">Mutex</link> concept.
|
||||
It should be used to synchronize access to shared resources using
|
||||
<link linkend="thread.concepts.unspecified-locking-strategy">Unspecified</link>
|
||||
locking mechanics.</para>
|
||||
|
||||
<para>For classes that model related mutex concepts, see
|
||||
<classname>try_mutex</classname> and <classname>timed_mutex</classname>.</para>
|
||||
|
||||
<para>For <link linkend="thread.concepts.recursive-locking-strategy">Recursive</link>
|
||||
locking mechanics, see <classname>recursive_mutex</classname>,
|
||||
<classname>recursive_try_mutex</classname>, and <classname>recursive_timed_mutex</classname>.
|
||||
</para>
|
||||
|
||||
<para>The <classname>mutex</classname> class supplies the following typedef,
|
||||
which <link linkend="thread.concepts.lock-models">models</link>
|
||||
the specified locking strategy:
|
||||
|
||||
<informaltable>
|
||||
<tgroup cols="2" align="left">
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Lock Name</entry>
|
||||
<entry>Lock Concept</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>scoped_lock</entry>
|
||||
<entry><link linkend="thread.concepts.ScopedLock">ScopedLock</link></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</informaltable>
|
||||
</para>
|
||||
|
||||
<para>The <classname>mutex</classname> class uses an
|
||||
<link linkend="thread.concepts.unspecified-locking-strategy">Unspecified</link>
|
||||
locking strategy, so attempts to recursively lock a <classname>mutex</classname>
|
||||
object or attempts to unlock one by threads that don't own a lock on it result in
|
||||
<emphasis role="bold">undefined behavior</emphasis>.
|
||||
This strategy allows implementations to be as efficient as possible
|
||||
on any given platform. It is, however, recommended that
|
||||
implementations include debugging support to detect misuse when
|
||||
<code>NDEBUG</code> is not defined.</para>
|
||||
|
||||
<para>Like all
|
||||
<link linkend="thread.concepts.mutex-models">mutex models</link>
|
||||
in &Boost.Thread;, <classname>mutex</classname> leaves the
|
||||
<link linkend="thread.concepts.sheduling-policies">scheduling policy</link>
|
||||
as <link linkend="thread.concepts.unspecified-scheduling-policy">Unspecified</link>.
|
||||
Programmers should make no assumptions about the order in which
|
||||
waiting threads acquire a lock.</para>
|
||||
</description>
|
||||
|
||||
<inherit access="private">
|
||||
<type><classname>boost::noncopyable</classname></type>
|
||||
<purpose>Exposition only</purpose>
|
||||
</inherit>
|
||||
|
||||
<typedef name="scoped_lock">
|
||||
<type><emphasis>implementation-defined</emphasis></type>
|
||||
</typedef>
|
||||
|
||||
<constructor>
|
||||
<effects>Constructs a <classname>mutex</classname> object.
|
||||
</effects>
|
||||
|
||||
<postconditions><code>*this</code> is in an unlocked state.
|
||||
</postconditions>
|
||||
</constructor>
|
||||
|
||||
<destructor>
|
||||
<effects>Destroys a <classname>mutex</classname> object.</effects>
|
||||
|
||||
<requires><code>*this</code> is in an unlocked state.</requires>
|
||||
|
||||
<notes><emphasis role="bold">Danger:</emphasis> Destruction of a
|
||||
locked mutex is a serious programming error resulting in undefined
|
||||
behavior such as a program crash.</notes>
|
||||
</destructor>
|
||||
</class>
|
||||
|
||||
<class name="try_mutex">
|
||||
<purpose>
|
||||
<para>The <classname>try_mutex</classname> class is a model of the
|
||||
<link linkend="thread.concepts.TryMutex">TryMutex</link> concept.</para>
|
||||
</purpose>
|
||||
|
||||
<description>
|
||||
<para>The <classname>try_mutex</classname> class is a model of the
|
||||
<link linkend="thread.concepts.TryMutex">TryMutex</link> concept.
|
||||
It should be used to synchronize access to shared resources using
|
||||
<link linkend="thread.concepts.unspecified-locking-strategy">Unspecified</link>
|
||||
locking mechanics.</para>
|
||||
|
||||
<para>For classes that model related mutex concepts, see
|
||||
<classname>mutex</classname> and <classname>timed_mutex</classname>.</para>
|
||||
|
||||
<para>For <link linkend="thread.concepts.recursive-locking-strategy">Recursive</link>
|
||||
locking mechanics, see <classname>recursive_mutex</classname>,
|
||||
<classname>recursive_try_mutex</classname>, and <classname>recursive_timed_mutex</classname>.
|
||||
</para>
|
||||
|
||||
<para>The <classname>try_mutex</classname> class supplies the following typedefs,
|
||||
which <link linkend="thread.concepts.lock-models">model</link>
|
||||
the specified locking strategies:
|
||||
|
||||
<informaltable>
|
||||
<tgroup cols="2" align="left">
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Lock Name</entry>
|
||||
<entry>Lock Concept</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>scoped_lock</entry>
|
||||
<entry><link linkend="thread.concepts.ScopedLock">ScopedLock</link></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>scoped_try_lock</entry>
|
||||
<entry><link linkend="thread.concepts.ScopedTryLock">ScopedTryLock</link></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</informaltable>
|
||||
</para>
|
||||
|
||||
<para>The <classname>try_mutex</classname> class uses an
|
||||
<link linkend="thread.concepts.unspecified-locking-strategy">Unspecified</link>
|
||||
locking strategy, so attempts to recursively lock a <classname>try_mutex</classname>
|
||||
object or attempts to unlock one by threads that don't own a lock on it result in
|
||||
<emphasis role="bold">undefined behavior</emphasis>.
|
||||
This strategy allows implementations to be as efficient as possible
|
||||
on any given platform. It is, however, recommended that
|
||||
implementations include debugging support to detect misuse when
|
||||
<code>NDEBUG</code> is not defined.</para>
|
||||
|
||||
<para>Like all
|
||||
<link linkend="thread.concepts.mutex-models">mutex models</link>
|
||||
in &Boost.Thread;, <classname>try_mutex</classname> leaves the
|
||||
<link linkend="thread.concepts.sheduling-policies">scheduling policy</link>
|
||||
as <link linkend="thread.concepts.unspecified-scheduling-policy">Unspecified</link>.
|
||||
Programmers should make no assumptions about the order in which
|
||||
waiting threads acquire a lock.</para>
|
||||
</description>
|
||||
|
||||
<inherit access="private">
|
||||
<type><classname>boost::noncopyable</classname></type>
|
||||
<purpose>Exposition only</purpose>
|
||||
</inherit>
|
||||
|
||||
<typedef name="scoped_lock">
|
||||
<type><emphasis>implementation-defined</emphasis></type>
|
||||
</typedef>
|
||||
|
||||
<typedef name="scoped_try_lock">
|
||||
<type><emphasis>implementation-defined</emphasis></type>
|
||||
</typedef>
|
||||
|
||||
<constructor>
|
||||
<effects>Constructs a <classname>try_mutex</classname> object.
|
||||
</effects>
|
||||
|
||||
<postconditions><code>*this</code> is in an unlocked state.
|
||||
</postconditions>
|
||||
</constructor>
|
||||
|
||||
<destructor>
|
||||
<effects>Destroys a <classname>try_mutex</classname> object.
|
||||
</effects>
|
||||
|
||||
<requires><code>*this</code> is in an unlocked state.</requires>
|
||||
|
||||
<notes><emphasis role="bold">Danger:</emphasis> Destruction of a
|
||||
locked mutex is a serious programming error resulting in undefined
|
||||
behavior such as a program crash.</notes>
|
||||
</destructor>
|
||||
</class>
|
||||
|
||||
<class name="timed_mutex">
|
||||
<purpose>
|
||||
<para>The <classname>timed_mutex</classname> class is a model of the
|
||||
<link linkend="thread.concepts.TimedMutex">TimedMutex</link> concept.</para>
|
||||
</purpose>
|
||||
|
||||
<description>
|
||||
<para>The <classname>timed_mutex</classname> class is a model of the
|
||||
<link linkend="thread.concepts.TimedMutex">TimedMutex</link> concept.
|
||||
It should be used to synchronize access to shared resources using
|
||||
<link linkend="thread.concepts.unspecified-locking-strategy">Unspecified</link>
|
||||
locking mechanics.</para>
|
||||
|
||||
<para>For classes that model related mutex concepts, see
|
||||
<classname>mutex</classname> and <classname>try_mutex</classname>.</para>
|
||||
|
||||
<para>For <link linkend="thread.concepts.recursive-locking-strategy">Recursive</link>
|
||||
locking mechanics, see <classname>recursive_mutex</classname>,
|
||||
<classname>recursive_try_mutex</classname>, and <classname>recursive_timed_mutex</classname>.
|
||||
</para>
|
||||
|
||||
<para>The <classname>timed_mutex</classname> class supplies the following typedefs,
|
||||
which <link linkend="thread.concepts.lock-models">model</link>
|
||||
the specified locking strategies:
|
||||
|
||||
<informaltable>
|
||||
<tgroup cols="2" align="left">
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Lock Name</entry>
|
||||
<entry>Lock Concept</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>scoped_lock</entry>
|
||||
<entry><link linkend="thread.concepts.ScopedLock">ScopedLock</link></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>scoped_try_lock</entry>
|
||||
<entry><link linkend="thread.concepts.ScopedTryLock">ScopedTryLock</link></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>scoped_timed_lock</entry>
|
||||
<entry><link linkend="thread.concepts.ScopedTimedLock">ScopedTimedLock</link></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</informaltable>
|
||||
</para>
|
||||
|
||||
<para>The <classname>timed_mutex</classname> class uses an
|
||||
<link linkend="thread.concepts.unspecified-locking-strategy">Unspecified</link>
|
||||
locking strategy, so attempts to recursively lock a <classname>timed_mutex</classname>
|
||||
object or attempts to unlock one by threads that don't own a lock on it result in
|
||||
<emphasis role="bold">undefined behavior</emphasis>.
|
||||
This strategy allows implementations to be as efficient as possible
|
||||
on any given platform. It is, however, recommended that
|
||||
implementations include debugging support to detect misuse when
|
||||
<code>NDEBUG</code> is not defined.</para>
|
||||
|
||||
<para>Like all
|
||||
<link linkend="thread.concepts.mutex-models">mutex models</link>
|
||||
in &Boost.Thread;, <classname>timed_mutex</classname> leaves the
|
||||
<link linkend="thread.concepts.sheduling-policies">scheduling policy</link>
|
||||
as <link linkend="thread.concepts.unspecified-scheduling-policy">Unspecified</link>.
|
||||
Programmers should make no assumptions about the order in which
|
||||
waiting threads acquire a lock.</para>
|
||||
</description>
|
||||
|
||||
<inherit access="private">
|
||||
<type><classname>boost::noncopyable</classname></type>
|
||||
<purpose>Exposition only</purpose>
|
||||
</inherit>
|
||||
|
||||
<typedef name="scoped_lock">
|
||||
<type><emphasis>implementation-defined</emphasis></type>
|
||||
</typedef>
|
||||
|
||||
<typedef name="scoped_try_lock">
|
||||
<type><emphasis>implementation-defined</emphasis></type>
|
||||
</typedef>
|
||||
|
||||
<typedef name="scoped_timed_lock">
|
||||
<type><emphasis>implementation-defined</emphasis></type>
|
||||
</typedef>
|
||||
|
||||
<constructor>
|
||||
<effects>Constructs a <classname>timed_mutex</classname> object.
|
||||
</effects>
|
||||
|
||||
<postconditions><code>*this</code> is in an unlocked state.
|
||||
</postconditions>
|
||||
</constructor>
|
||||
|
||||
<destructor>
|
||||
<effects>Destroys a <classname>timed_mutex</classname> object.</effects>
|
||||
|
||||
<requires><code>*this</code> is in an unlocked state.</requires>
|
||||
|
||||
<notes><emphasis role="bold">Danger:</emphasis> Destruction of a
|
||||
locked mutex is a serious programming error resulting in undefined
|
||||
behavior such as a program crash.</notes>
|
||||
</destructor>
|
||||
</class>
|
||||
</namespace>
|
||||
</header>
|
||||
90
doc/once-ref.xml
Normal file
90
doc/once-ref.xml
Normal file
@@ -0,0 +1,90 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
||||
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
|
||||
<!ENTITY % thread.entities SYSTEM "entities.xml">
|
||||
%thread.entities;
|
||||
]>
|
||||
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
|
||||
Subject to the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
|
||||
-->
|
||||
<header name="boost/thread/once.hpp"
|
||||
last-revision="$Date$">
|
||||
<macro name="BOOST_ONCE_INIT">
|
||||
<purpose>The <functionname>call_once</functionname> function and
|
||||
<code>once_flag</code> type (statically initialized to
|
||||
<macroname>BOOST_ONCE_INIT</macroname>) can be used to run a
|
||||
routine exactly once. This can be used to initialize data in a
|
||||
<link linkend="thread.glossary.thread-safe">thread-safe</link>
|
||||
manner.</purpose>
|
||||
|
||||
<description>The implementation-defined macro
|
||||
<macroname>BOOST_ONCE_INIT</macroname> is a constant value used to
|
||||
initialize <code>once_flag</code> instances to indicate that the
|
||||
logically associated routine has not been run yet. See
|
||||
<functionname>call_once</functionname> for more details.</description>
|
||||
</macro>
|
||||
|
||||
<namespace name="boost">
|
||||
<typedef name="once_flag">
|
||||
<purpose>The <functionname>call_once</functionname> function and
|
||||
<code>once_flag</code> type (statically initialized to
|
||||
<macroname>BOOST_ONCE_INIT</macroname>) can be used to run a
|
||||
routine exactly once. This can be used to initialize data in a
|
||||
<link linkend="thread.glossary.thread-safe">thread-safe</link>
|
||||
manner.</purpose>
|
||||
|
||||
<description>The implementation-defined type <code>once_flag</code>
|
||||
is used as a flag to insure a routine is called only once.
|
||||
Instances of this type should be statically initialized to
|
||||
<macroname>BOOST_ONCE_INIT</macroname>. See
|
||||
<functionname>call_once</functionname> for more details.
|
||||
</description>
|
||||
|
||||
<type><emphasis>implementation-defined</emphasis></type>
|
||||
</typedef>
|
||||
|
||||
<function name="call_once">
|
||||
<purpose>The <functionname>call_once</functionname> function and
|
||||
<code>once_flag</code> type (statically initialized to
|
||||
<macroname>BOOST_ONCE_INIT</macroname>) can be used to run a
|
||||
routine exactly once. This can be used to initialize data in a
|
||||
<link linkend="thread.glossary.thread-safe">thread-safe</link>
|
||||
manner.</purpose>
|
||||
|
||||
<description>
|
||||
<para>Example usage is as follows:</para>
|
||||
<para>
|
||||
<programlisting>//Example usage:
|
||||
boost::once_flag once = BOOST_ONCE_INIT;
|
||||
|
||||
void init()
|
||||
{
|
||||
//...
|
||||
}
|
||||
|
||||
void thread_proc()
|
||||
{
|
||||
boost::call_once(&init, once);
|
||||
}</programlisting>
|
||||
</para></description>
|
||||
|
||||
<parameter name="func">
|
||||
<paramtype>void (*func)()</paramtype>
|
||||
</parameter>
|
||||
|
||||
<parameter name="flag">
|
||||
<paramtype>once_flag&</paramtype>
|
||||
</parameter>
|
||||
|
||||
<requires>The function <code>func</code> shall not throw
|
||||
exceptions.</requires>
|
||||
|
||||
<effects>As if (in an atomic fashion):
|
||||
<code>if (flag == BOOST_ONCE_INIT) func();</code></effects>
|
||||
|
||||
<postconditions><code>flag != BOOST_ONCE_INIT</code>
|
||||
</postconditions>
|
||||
</function>
|
||||
</namespace>
|
||||
</header>
|
||||
206
doc/overview.xml
Normal file
206
doc/overview.xml
Normal file
@@ -0,0 +1,206 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
||||
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
|
||||
<!ENTITY % thread.entities SYSTEM "entities.xml">
|
||||
%thread.entities;
|
||||
]>
|
||||
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
|
||||
Subject to the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
|
||||
-->
|
||||
<section id="thread.overview" last-revision="$Date$">
|
||||
<title>Overview</title>
|
||||
<section id="thread.introduction">
|
||||
<title>Introduction</title>
|
||||
<para>&Boost.Thread; allows C++ programs to execute as multiple,
|
||||
asynchronous, independent threads-of-execution. Each thread has its own
|
||||
machine state including program instruction counter and registers. Programs
|
||||
which execute as multiple threads are called multithreaded programs to
|
||||
distinguish them from traditional single-threaded programs. The <link
|
||||
linkend="thread.glossary">glossary</link> gives a more complete description
|
||||
of the multithreading execution environment.</para>
|
||||
<para>Multithreading provides several advantages:
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>Programs which would otherwise block waiting for some external
|
||||
event can continue to respond if the blocking operation is placed in a
|
||||
separate thread. Multithreading is usually an absolute requirement for
|
||||
these programs.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Well-designed multithreaded programs may execute faster than
|
||||
single-threaded programs, particularly on multiprocessor hardware.
|
||||
Note, however, that poorly-designed multithreaded programs are often
|
||||
slower than single-threaded programs.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Some program designs may be easier to formulate using a
|
||||
multithreaded approach. After all, the real world is
|
||||
asynchronous!</para>
|
||||
</listitem>
|
||||
</itemizedlist></para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Dangers</title>
|
||||
<section>
|
||||
<title>General considerations</title>
|
||||
<para>Beyond the errors which can occur in single-threaded programs,
|
||||
multithreaded programs are subject to additional errors:
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><link linkend="thread.glossary.race-condition">Race
|
||||
conditions</link></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><link linkend="thread.glossary.deadlock">Deadlock</link>
|
||||
(sometimes called "deadly embrace")</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><link linkend="thread.glossary.priority-failure">Priority
|
||||
failures</link> (priority inversion, infinite overtaking, starvation,
|
||||
etc.)</para>
|
||||
</listitem>
|
||||
</itemizedlist></para>
|
||||
<para>Every multithreaded program must be designed carefully to avoid these
|
||||
errors. These aren't rare or exotic failures - they are virtually guaranteed
|
||||
to occur unless multithreaded code is designed to avoid them. Priority
|
||||
failures are somewhat less common, but are nonetheless serious.</para>
|
||||
<para>The <link linkend="thread.design">&Boost.Thread; design</link>
|
||||
attempts to minimize these errors, but they will still occur unless the
|
||||
programmer proactively designs to avoid them.</para>
|
||||
<note>Please also see <xref linkend="thread.implementation_notes"/>
|
||||
for additional, implementation-specific considerations.</note>
|
||||
</section>
|
||||
<section>
|
||||
<title>Testing and debugging considerations</title>
|
||||
<para>Multithreaded programs are non-deterministic. In other words, the
|
||||
same program with the same input data may follow different execution
|
||||
paths each time it is invoked. That can make testing and debugging a
|
||||
nightmare:
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>Failures are often not repeatable.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Probe effect causes debuggers to produce very different results
|
||||
from non-debug uses.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Debuggers require special support to show thread state.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Tests on a single processor system may give no indication of
|
||||
serious errors which would appear on multiprocessor systems, and visa
|
||||
versa. Thus test cases should include a varying number of
|
||||
processors.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>For programs which create a varying number of threads according
|
||||
to workload, tests which don't span the full range of possibilities
|
||||
may miss serious errors.</para>
|
||||
</listitem>
|
||||
</itemizedlist></para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Getting a head start</title>
|
||||
<para>Although it might appear that multithreaded programs are inherently
|
||||
unreliable, many reliable multithreaded programs do exist. Multithreading
|
||||
techniques are known which lead to reliable programs.</para>
|
||||
<para>Design patterns for reliable multithreaded programs, including the
|
||||
important <emphasis>monitor</emphasis> pattern, are presented in
|
||||
<emphasis>Pattern-Oriented Software Architecture Volume 2 - Patterns for
|
||||
Concurrent and Networked Objects</emphasis>
|
||||
&cite.SchmidtStalRohnertBuschmann;. Many important multithreading programming
|
||||
considerations (independent of threading library) are discussed in
|
||||
<emphasis>Programming with POSIX Threads</emphasis> &cite.Butenhof97;.</para>
|
||||
<para>Doing some reading before attempting multithreaded designs will
|
||||
give you a head start toward reliable multithreaded programs.</para>
|
||||
</section>
|
||||
</section>
|
||||
<section>
|
||||
<title>C++ Standard Library usage in multithreaded programs</title>
|
||||
<section>
|
||||
<title>Runtime libraries</title>
|
||||
<para>
|
||||
<emphasis role="bold">Warning:</emphasis> Multithreaded programs such as
|
||||
those using &Boost.Thread; must link to <link
|
||||
linkend="thread.glossary.thread-safe">thread-safe</link> versions of
|
||||
all runtime libraries used by the program, including the runtime library
|
||||
for the C++ Standard Library. Failure to do so will cause <link
|
||||
linkend="thread.glossary.race-condition">race conditions</link> to occur
|
||||
when multiple threads simultaneously execute runtime library functions for
|
||||
<code>new</code>, <code>delete</code>, or other language features which
|
||||
imply shared state.</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Potentially non-thread-safe functions</title>
|
||||
<para>Certain C++ Standard Library functions inherited from C are
|
||||
particular problems because they hold internal state between
|
||||
calls:
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><code>rand</code></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><code>strtok</code></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><code>asctime</code></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><code>ctime</code></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><code>gmtime</code></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><code>localtime</code></para>
|
||||
</listitem>
|
||||
</itemizedlist></para>
|
||||
<para>It is possible to write thread-safe implementations of these by
|
||||
using thread specific storage (see
|
||||
<classname>boost::thread_specific_ptr</classname>), and several C++
|
||||
compiler vendors do just that. The technique is well-know and is explained
|
||||
in &cite.Butenhof97;.</para>
|
||||
<para>But at least one vendor (HP-UX) does not provide thread-safe
|
||||
implementations of the above functions in their otherwise thread-safe
|
||||
runtime library. Instead they provide replacement functions with
|
||||
different names and arguments.</para>
|
||||
<para><emphasis role="bold">Recommendation:</emphasis> For the most
|
||||
portable, yet thread-safe code, use Boost replacements for the problem
|
||||
functions. See the <libraryname>Boost Random Number Library</libraryname>
|
||||
and <libraryname>Boost Tokenizer Library</libraryname>.</para>
|
||||
</section>
|
||||
</section>
|
||||
<section>
|
||||
<title>Common guarantees for all &Boost.Thread; components</title>
|
||||
<section>
|
||||
<title>Exceptions</title>
|
||||
<para>&Boost.Thread; destructors never
|
||||
throw exceptions. Unless otherwise specified, other
|
||||
&Boost.Thread; functions that do not have
|
||||
an exception-specification may throw implementation-defined
|
||||
exceptions.</para>
|
||||
<para>In particular, &Boost.Thread;
|
||||
reports failure to allocate storage by throwing an exception of type
|
||||
<code>std::bad_alloc</code> or a class derived from
|
||||
<code>std::bad_alloc</code>, failure to obtain thread resources other than
|
||||
memory by throwing an exception of type
|
||||
<classname>boost::thread_resource_error</classname>, and certain lock
|
||||
related failures by throwing an exception of type
|
||||
<classname>boost::lock_error</classname>.</para>
|
||||
<para><emphasis role="bold">Rationale:</emphasis> Follows the C++ Standard
|
||||
Library practice of allowing all functions except destructors or other
|
||||
specified functions to throw exceptions on errors.</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>NonCopyable requirement</title>
|
||||
<para>&Boost.Thread; classes documented as
|
||||
meeting the NonCopyable requirement disallow copy construction and copy
|
||||
assignment. For the sake of exposition, the synopsis of such classes show
|
||||
private derivation from <classname>boost::noncopyable</classname>. Users
|
||||
should not depend on this derivation, however, as implementations are free
|
||||
to meet the NonCopyable requirement in other ways.</para>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
438
doc/rationale.xml
Normal file
438
doc/rationale.xml
Normal file
@@ -0,0 +1,438 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
||||
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
|
||||
<!ENTITY % thread.entities SYSTEM "entities.xml">
|
||||
%thread.entities;
|
||||
]>
|
||||
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
|
||||
Subject to the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
|
||||
-->
|
||||
<section id="thread.rationale" last-revision="$Date$">
|
||||
<title>Rationale</title>
|
||||
<para>This page explains the rationale behind various design decisions in the
|
||||
&Boost.Thread; library. Having the rationale documented here should explain
|
||||
how we arrived at the current design as well as prevent future rehashing of
|
||||
discussions and thought processes that have already occurred. It can also give
|
||||
users a lot of insight into the design process required for this
|
||||
library.</para>
|
||||
<section id="thread.rationale.Boost.Thread">
|
||||
<title>Rationale for the Creation of &Boost.Thread;</title>
|
||||
<para>Processes often have a degree of "potential parallelism" and it can
|
||||
often be more intuitive to design systems with this in mind. Further, these
|
||||
parallel processes can result in more responsive programs. The benefits for
|
||||
multithreaded programming are quite well known to most modern programmers,
|
||||
yet the C++ language doesn't directly support this concept.</para>
|
||||
<para>Many platforms support multithreaded programming despite the fact that
|
||||
the language doesn't support it. They do this through external libraries,
|
||||
which are, unfortunately, platform specific. POSIX has tried to address this
|
||||
problem through the standardization of a "pthread" library. However, this is
|
||||
a standard only on POSIX platforms, so its portability is limited.</para>
|
||||
<para>Another problem with POSIX and other platform specific thread
|
||||
libraries is that they are almost universally C based libraries. This leaves
|
||||
several C++ specific issues unresolved, such as what happens when an
|
||||
exception is thrown in a thread. Further, there are some C++ concepts, such
|
||||
as destructors, that can make usage much easier than what's available in a C
|
||||
library.</para>
|
||||
<para>What's truly needed is C++ language support for threads. However, the
|
||||
C++ standards committee needs existing practice or a good proposal as a
|
||||
starting point for adding this to the standard.</para>
|
||||
<para>The &Boost.Thread; library was developed to provide a C++ developer
|
||||
with a portable interface for writing multithreaded programs on numerous
|
||||
platforms. There's a hope that the library can be the basis for a more
|
||||
detailed proposal for the C++ standards committee to consider for inclusion
|
||||
in the next C++ standard.</para>
|
||||
</section>
|
||||
<section id="thread.rationale.primitives">
|
||||
<title>Rationale for the Low Level Primitives Supported in &Boost.Thread;</title>
|
||||
<para>The &Boost.Thread; library supplies a set of low level primitives for
|
||||
writing multithreaded programs, such as mutexes and condition variables. In
|
||||
fact, the first release of &Boost.Thread; supports only these low level
|
||||
primitives. However, computer science research has shown that use of these
|
||||
primitives is difficult since it's difficult to mathematically prove that a
|
||||
usage pattern is correct, meaning it doesn't result in race conditions or
|
||||
deadlocks. There are several algebras (such as CSP, CCS and Join calculus)
|
||||
that have been developed to help write provably correct parallel
|
||||
processes. In order to prove the correctness these processes must be coded
|
||||
using higher level abstractions. So why does &Boost.Thread; support the
|
||||
lower level concepts?</para>
|
||||
<para>The reason is simple: the higher level concepts need to be implemented
|
||||
using at least some of the lower level concepts. So having portable lower
|
||||
level concepts makes it easier to develop the higher level concepts and will
|
||||
allow researchers to experiment with various techniques.</para>
|
||||
<para>Beyond this theoretical application of higher level concepts, however,
|
||||
the fact remains that many multithreaded programs are written using only the
|
||||
lower level concepts, so they are useful in and of themselves, even if it's
|
||||
hard to prove that their usage is correct. Since many users will be familiar
|
||||
with these lower level concepts but unfamiliar with any of the higher
|
||||
level concepts, supporting the lower level concepts provides
|
||||
greater accessibility.</para>
|
||||
</section>
|
||||
<section id="thread.rationale.locks">
|
||||
<title>Rationale for the Lock Design</title>
|
||||
<para>Programmers who are used to multithreaded programming issues will
|
||||
quickly note that the &Boost.Thread; design for mutex lock concepts is not
|
||||
<link linkend="thread.glossary.thread-safe">thread-safe</link> (this is
|
||||
clearly documented as well). At first this may seem like a serious design
|
||||
flaw. Why have a multithreading primitive that's not thread-safe
|
||||
itself?</para>
|
||||
<para>A lock object is not a synchronization primitive. A lock object's sole
|
||||
responsibility is to ensure that a mutex is both locked and unlocked in a
|
||||
manner that won't result in the common error of locking a mutex and then
|
||||
forgetting to unlock it. This means that instances of a lock object are only
|
||||
going to be created, at least in theory, within block scope and won't be
|
||||
shared between threads. Only the mutex objects will be created outside of
|
||||
block scope and/or shared between threads. Though it's possible to create a
|
||||
lock object outside of block scope and to share it between threads, to do so
|
||||
would not be a typical usage (in fact, to do so would likely be an
|
||||
error). Nor are there any cases when such usage would be required.</para>
|
||||
<para>Lock objects must maintain some state information. In order to allow a
|
||||
program to determine if a try_lock or timed_lock was successful the lock
|
||||
object must retain state indicating the success or failure of the call made
|
||||
in its constructor. If a lock object were to have such state and remain
|
||||
thread-safe it would need to synchronize access to the state information
|
||||
which would result in roughly doubling the time of most operations. Worse,
|
||||
since checking the state can occur only by a call after construction, we'd
|
||||
have a race condition if the lock object were shared between threads.</para>
|
||||
<para>So, to avoid the overhead of synchronizing access to the state
|
||||
information and to avoid the race condition, the &Boost.Thread; library
|
||||
simply does nothing to make lock objects thread-safe. Instead, sharing a
|
||||
lock object between threads results in undefined behavior. Since the only
|
||||
proper usage of lock objects is within block scope this isn't a problem, and
|
||||
so long as the lock object is properly used there's no danger of any
|
||||
multithreading issues.</para>
|
||||
</section>
|
||||
<section id="thread.rationale.non-copyable">
|
||||
<title>Rationale for NonCopyable Thread Type</title>
|
||||
<para>Programmers who are used to C libraries for multithreaded programming
|
||||
are likely to wonder why &Boost.Thread; uses a noncopyable design for
|
||||
<classname>boost::thread</classname>. After all, the C thread types are
|
||||
copyable, and you often have a need for copying them within user
|
||||
code. However, careful comparison of C designs to C++ designs shows a flaw
|
||||
in this logic.</para>
|
||||
<para>All C types are copyable. It is, in fact, not possible to make a
|
||||
noncopyable type in C. For this reason types that represent system resources
|
||||
in C are often designed to behave very similarly to a pointer to dynamic
|
||||
memory. There's an API for acquiring the resource and an API for releasing
|
||||
the resource. For memory we have pointers as the type and alloc/free for
|
||||
the acquisition and release APIs. For files we have FILE* as the type and
|
||||
fopen/fclose for the acquisition and release APIs. You can freely copy
|
||||
instances of the types but must manually manage the lifetime of the actual
|
||||
resource through the acquisition and release APIs.</para>
|
||||
<para>C++ designs recognize that the acquisition and release APIs are error
|
||||
prone and try to eliminate possible errors by acquiring the resource in the
|
||||
constructor and releasing it in the destructor. The best example of such a
|
||||
design is the std::iostream set of classes which can represent the same
|
||||
resource as the FILE* type in C. A file is opened in the std::fstream's
|
||||
constructor and closed in its destructor. However, if an iostream were
|
||||
copyable it could lead to a file being closed twice, an obvious error, so
|
||||
the std::iostream types are noncopyable by design. This is the same design
|
||||
used by boost::thread, which is a simple and easy to understand design
|
||||
that's consistent with other C++ standard types.</para>
|
||||
<para>During the design of boost::thread it was pointed out that it would be
|
||||
possible to allow it to be a copyable type if some form of "reference
|
||||
management" were used, such as ref-counting or ref-lists, and many argued
|
||||
for a boost::thread_ref design instead. The reasoning was that copying
|
||||
"thread" objects was a typical need in the C libraries, and so presumably
|
||||
would be in the C++ libraries as well. It was also thought that
|
||||
implementations could provide more efficient reference management than
|
||||
wrappers (such as boost::shared_ptr) around a noncopyable thread
|
||||
concept. Analysis of whether or not these arguments would hold true doesn't
|
||||
appear to bear them out. To illustrate the analysis we'll first provide
|
||||
pseudo-code illustrating the six typical usage patterns of a thread
|
||||
object.</para>
|
||||
<section id="thread.rationale.non-copyable.simple">
|
||||
<title>1. Use case: Simple creation of a thread.</title>
|
||||
<programlisting>
|
||||
void foo()
|
||||
{
|
||||
create_thread(&bar);
|
||||
}
|
||||
</programlisting>
|
||||
</section>
|
||||
<section id="thread.rationale.non-copyable.joined">
|
||||
<title>2. Use case: Creation of a thread that's later joined.</title>
|
||||
<programlisting>
|
||||
void foo()
|
||||
{
|
||||
thread = create_thread(&bar);
|
||||
join(thread);
|
||||
}
|
||||
</programlisting>
|
||||
</section>
|
||||
<section id="thread.rationale.non-copyable.loop">
|
||||
<title>3. Use case: Simple creation of several threads in a loop.</title>
|
||||
<programlisting>
|
||||
void foo()
|
||||
{
|
||||
for (int i=0; i<NUM_THREADS; ++i)
|
||||
create_thread(&bar);
|
||||
}
|
||||
</programlisting>
|
||||
</section>
|
||||
<section id="thread.rationale.non-copyable.loop-join">
|
||||
<title>4. Use case: Creation of several threads in a loop which are later joined.</title>
|
||||
<programlisting>
|
||||
void foo()
|
||||
{
|
||||
for (int i=0; i<NUM_THREADS; ++i)
|
||||
threads[i] = create_thread(&bar);
|
||||
for (int i=0; i<NUM_THREADS; ++i)
|
||||
threads[i].join();
|
||||
}
|
||||
</programlisting>
|
||||
</section>
|
||||
<section id="thread.rationale.non-copyable.pass">
|
||||
<title>5. Use case: Creation of a thread whose ownership is passed to another object/method.</title>
|
||||
<programlisting>
|
||||
void foo()
|
||||
{
|
||||
thread = create_thread(&bar);
|
||||
manager.owns(thread);
|
||||
}
|
||||
</programlisting>
|
||||
</section>
|
||||
<section id="thread.rationale.non-copyable.shared">
|
||||
<title>6. Use case: Creation of a thread whose ownership is shared between multiple
|
||||
objects.</title>
|
||||
<programlisting>
|
||||
void foo()
|
||||
{
|
||||
thread = create_thread(&bar);
|
||||
manager1.add(thread);
|
||||
manager2.add(thread);
|
||||
}
|
||||
</programlisting>
|
||||
</section>
|
||||
<para>Of these usage patterns there's only one that requires reference
|
||||
management (number 6). Hopefully it's fairly obvious that this usage pattern
|
||||
simply won't occur as often as the other usage patterns. So there really
|
||||
isn't a "typical need" for a thread concept, though there is some
|
||||
need.</para>
|
||||
<para>Since the need isn't typical we must use different criteria for
|
||||
deciding on either a thread_ref or thread design. Possible criteria include
|
||||
ease of use and performance. So let's analyze both of these
|
||||
carefully.</para>
|
||||
<para>With ease of use we can look at existing experience. The standard C++
|
||||
objects that represent a system resource, such as std::iostream, are
|
||||
noncopyable, so we know that C++ programmers must at least be experienced
|
||||
with this design. Most C++ developers are also used to smart pointers such
|
||||
as boost::shared_ptr, so we know they can at least adapt to a thread_ref
|
||||
concept with little effort. So existing experience isn't going to lead us to
|
||||
a choice.</para>
|
||||
<para>The other thing we can look at is how difficult it is to use both
|
||||
types for the six usage patterns above. If we find it overly difficult to
|
||||
use a concept for any of the usage patterns there would be a good argument
|
||||
for choosing the other design. So we'll code all six usage patterns using
|
||||
both designs.</para>
|
||||
<section id="thread.rationale_comparison.non-copyable.simple">
|
||||
<title>1. Comparison: simple creation of a thread.</title>
|
||||
<programlisting>
|
||||
void foo()
|
||||
{
|
||||
thread thrd(&bar);
|
||||
}
|
||||
void foo()
|
||||
{
|
||||
thread_ref thrd = create_thread(&bar);
|
||||
}
|
||||
</programlisting>
|
||||
</section>
|
||||
<section id="thread.rationale_comparison.non-copyable.joined">
|
||||
<title>2. Comparison: creation of a thread that's later joined.</title>
|
||||
<programlisting>
|
||||
void foo()
|
||||
{
|
||||
thread thrd(&bar);
|
||||
thrd.join();
|
||||
}
|
||||
void foo()
|
||||
{
|
||||
thread_ref thrd =
|
||||
create_thread(&bar);thrd->join();
|
||||
}
|
||||
</programlisting>
|
||||
</section>
|
||||
<section id="thread.rationale_comparison.non-copyable.loop">
|
||||
<title>3. Comparison: simple creation of several threads in a loop.</title>
|
||||
<programlisting>
|
||||
void foo()
|
||||
{
|
||||
for (int i=0; i<NUM_THREADS; ++i)
|
||||
thread thrd(&bar);
|
||||
}
|
||||
void foo()
|
||||
{
|
||||
for (int i=0; i<NUM_THREADS; ++i)
|
||||
thread_ref thrd = create_thread(&bar);
|
||||
}
|
||||
</programlisting>
|
||||
</section>
|
||||
<section id="thread.rationale_comparison.non-copyable.loop-join">
|
||||
<title>4. Comparison: creation of several threads in a loop which are later joined.</title>
|
||||
<programlisting>
|
||||
void foo()
|
||||
{
|
||||
std::auto_ptr<thread> threads[NUM_THREADS];
|
||||
for (int i=0; i<NUM_THREADS; ++i)
|
||||
threads[i] = std::auto_ptr<thread>(new thread(&bar));
|
||||
for (int i= 0; i<NUM_THREADS;
|
||||
++i)threads[i]->join();
|
||||
}
|
||||
void foo()
|
||||
{
|
||||
thread_ref threads[NUM_THREADS];
|
||||
for (int i=0; i<NUM_THREADS; ++i)
|
||||
threads[i] = create_thread(&bar);
|
||||
for (int i= 0; i<NUM_THREADS;
|
||||
++i)threads[i]->join();
|
||||
}
|
||||
</programlisting>
|
||||
</section>
|
||||
<section id="thread.rationale_comparison.non-copyable.pass">
|
||||
<title>5. Comparison: creation of a thread whose ownership is passed to another object/method.</title>
|
||||
<programlisting>
|
||||
void foo()
|
||||
{
|
||||
thread thrd* = new thread(&bar);
|
||||
manager.owns(thread);
|
||||
}
|
||||
void foo()
|
||||
{
|
||||
thread_ref thrd = create_thread(&bar);
|
||||
manager.owns(thrd);
|
||||
}
|
||||
</programlisting>
|
||||
</section>
|
||||
<section id="thread.rationale_comparison.non-copyable.shared">
|
||||
<title>6. Comparison: creation of a thread whose ownership is shared
|
||||
between multiple objects.</title>
|
||||
<programlisting>
|
||||
void foo()
|
||||
{
|
||||
boost::shared_ptr<thread> thrd(new thread(&bar));
|
||||
manager1.add(thrd);
|
||||
manager2.add(thrd);
|
||||
}
|
||||
void foo()
|
||||
{
|
||||
thread_ref thrd = create_thread(&bar);
|
||||
manager1.add(thrd);
|
||||
manager2.add(thrd);
|
||||
}
|
||||
</programlisting>
|
||||
</section>
|
||||
<para>This shows the usage patterns being nearly identical in complexity for
|
||||
both designs. The only actual added complexity occurs because of the use of
|
||||
operator new in
|
||||
<link linkend="thread.rationale_comparison.non-copyable.loop-join">(4)</link>,
|
||||
<link linkend="thread.rationale_comparison.non-copyable.pass">(5)</link>, and
|
||||
<link linkend="thread.rationale_comparison.non-copyable.shared">(6)</link>;
|
||||
and the use of std::auto_ptr and boost::shared_ptr in
|
||||
<link linkend="thread.rationale_comparison.non-copyable.loop-join">(4)</link> and
|
||||
<link linkend="thread.rationale_comparison.non-copyable.shared">(6)</link>
|
||||
respectively. However, that's not really
|
||||
much added complexity, and C++ programmers are used to using these idioms
|
||||
anyway. Some may dislike the presence of operator new in user code, but
|
||||
this can be eliminated by proper design of higher level concepts, such as
|
||||
the boost::thread_group class that simplifies example
|
||||
<link linkend="thread.rationale_comparison.non-copyable.loop-join">(4)</link>
|
||||
down to:</para>
|
||||
<programlisting>
|
||||
void foo()
|
||||
{
|
||||
thread_group threads;
|
||||
for (int i=0; i<NUM_THREADS; ++i)
|
||||
threads.create_thread(&bar);
|
||||
threads.join_all();
|
||||
}
|
||||
</programlisting>
|
||||
<para>So ease of use is really a wash and not much help in picking a
|
||||
design.</para>
|
||||
<para>So what about performance? Looking at the above code examples,
|
||||
we can analyze the theoretical impact to performance that both designs
|
||||
have. For <link linkend="thread.rationale_comparison.non-copyable.simple">(1)</link>
|
||||
we can see that platforms that don't have a ref-counted native
|
||||
thread type (POSIX, for instance) will be impacted by a thread_ref
|
||||
design. Even if the native thread type is ref-counted there may be an impact
|
||||
if more state information has to be maintained for concepts foreign to the
|
||||
native API, such as clean up stacks for Win32 implementations.
|
||||
For <link linkend="thread.rationale_comparison.non-copyable.joined">(2)</link>
|
||||
and <link linkend="thread.rationale_comparison.non-copyable.loop">(3)</link>
|
||||
the performance impact will be identical to
|
||||
<link linkend="thread.rationale_comparison.non-copyable.simple">(1)</link>.
|
||||
For <link linkend="thread.rationale_comparison.non-copyable.loop-join">(4)</link>
|
||||
things get a little more interesting and we find that theoretically at least
|
||||
the thread_ref may perform faster since the thread design requires dynamic
|
||||
memory allocation/deallocation. However, in practice there may be dynamic
|
||||
allocation for the thread_ref design as well, it will just be hidden from
|
||||
the user. As long as the implementation has to do dynamic allocations the
|
||||
thread_ref loses again because of the reference management. For
|
||||
<link linkend="thread.rationale_comparison.non-copyable.pass">(5)</link> we see
|
||||
the same impact as we do for
|
||||
<link linkend="thread.rationale_comparison.non-copyable.loop-join">(4)</link>.
|
||||
For <link linkend="thread.rationale_comparison.non-copyable.shared">(6)</link>
|
||||
we still have a possible impact to
|
||||
the thread design because of dynamic allocation but thread_ref no longer
|
||||
suffers because of its reference management, and in fact, theoretically at
|
||||
least, the thread_ref may do a better job of managing the references. All of
|
||||
this indicates that thread wins for
|
||||
<link linkend="thread.rationale_comparison.non-copyable.simple">(1)</link>,
|
||||
<link linkend="thread.rationale_comparison.non-copyable.joined">(2)</link> and
|
||||
<link linkend="thread.rationale_comparison.non-copyable.loop">(3)</link>; with
|
||||
<link linkend="thread.rationale_comparison.non-copyable.loop-join">(4)</link>
|
||||
and <link linkend="thread.rationale_comparison.non-copyable.pass">(5)</link> the
|
||||
winner depending on the implementation and the platform but with the thread design
|
||||
probably having a better chance; and with
|
||||
<link linkend="thread.rationale_comparison.non-copyable.shared">(6)</link>
|
||||
it will again depend on the
|
||||
implementation and platform but this time we favor thread_ref
|
||||
slightly. Given all of this it's a narrow margin, but the thread design
|
||||
prevails.</para>
|
||||
<para>Given this analysis, and the fact that noncopyable objects for system
|
||||
resources are the normal designs that C++ programmers are used to dealing
|
||||
with, the &Boost.Thread; library has gone with a noncopyable design.</para>
|
||||
</section>
|
||||
<section id="thread.rationale.events">
|
||||
<title>Rationale for not providing <emphasis>Event Variables</emphasis></title>
|
||||
<para><emphasis>Event variables</emphasis> are simply far too
|
||||
error-prone. <classname>boost::condition</classname> variables are a much safer
|
||||
alternative. [Note that Graphical User Interface <emphasis>events</emphasis> are
|
||||
a different concept, and are not what is being discussed here.]</para>
|
||||
<para>Event variables were one of the first synchronization primitives. They
|
||||
are still used today, for example, in the native Windows multithreading
|
||||
API. Yet both respected computer science researchers and experienced
|
||||
multithreading practitioners believe event variables are so inherently
|
||||
error-prone that they should never be used, and thus should not be part of a
|
||||
multithreading library.</para>
|
||||
<para>Per Brinch Hansen &cite.Hansen73; analyzed event variables in some
|
||||
detail, pointing out [emphasis his] that "<emphasis>event operations force
|
||||
the programmer to be aware of the relative speeds of the sending and
|
||||
receiving processes</emphasis>". His summary:</para>
|
||||
<blockquote>
|
||||
<para>We must therefore conclude that event variables of the previous type
|
||||
are impractical for system design. <emphasis>The effect of an interaction
|
||||
between two processes must be independent of the speed at which it is
|
||||
carried out.</emphasis></para>
|
||||
</blockquote>
|
||||
<para>Experienced programmers using the Windows platform today report that
|
||||
event variables are a continuing source of errors, even after previous bad
|
||||
experiences caused them to be very careful in their use of event
|
||||
variables. Overt problems can be avoided, for example, by teaming the event
|
||||
variable with a mutex, but that may just convert a <link
|
||||
linkend="thread.glossary.race-condition">race condition</link> into another
|
||||
problem, such as excessive resource use. One of the most distressing aspects
|
||||
of the experience reports is the claim that many defects are latent. That
|
||||
is, the programs appear to work correctly, but contain hidden timing
|
||||
dependencies which will cause them to fail when environmental factors or
|
||||
usage patterns change, altering relative thread timings.</para>
|
||||
<para>The decision to exclude event variables from &Boost.Thread; has been
|
||||
surprising to some Windows programmers. They have written programs which
|
||||
work using event variables, and wonder what the problem is. It seems similar
|
||||
to the "goto considered harmful" controversy of 30 years ago. It isn't that
|
||||
events, like gotos, can't be made to work, but rather that virtually all
|
||||
programs using alternatives will be easier to write, debug, read, maintain,
|
||||
and will be less likely to contain latent defects.</para>
|
||||
<para>[Rationale provided by Beman Dawes]</para>
|
||||
</section>
|
||||
</section>
|
||||
462
doc/read_write_mutex-ref.xml
Normal file
462
doc/read_write_mutex-ref.xml
Normal file
@@ -0,0 +1,462 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
||||
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
|
||||
<!ENTITY % thread.entities SYSTEM "entities.xml">
|
||||
%thread.entities;
|
||||
]>
|
||||
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
|
||||
Subject to the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
|
||||
-->
|
||||
<header name="boost/thread/read_write_mutex.hpp"
|
||||
last-revision="$Date$">
|
||||
<namespace name="boost">
|
||||
<namespace name="read_write_scheduling_policy">
|
||||
<enum name="read_write_scheduling_policy">
|
||||
<enumvalue name="writer_priority" />
|
||||
<enumvalue name="reader_priority" />
|
||||
<enumvalue name="alternating_many_reads" />
|
||||
<enumvalue name="alternating_single_read" />
|
||||
|
||||
<purpose>
|
||||
<para>Specifies the
|
||||
<link linkend="thread.concepts.read-write-scheduling-policies.inter-class">inter-class sheduling policy</link>
|
||||
to use when a set of threads try to obtain different types of
|
||||
locks simultaneously.</para>
|
||||
</purpose>
|
||||
|
||||
<description>
|
||||
<para>The only clock type supported by &Boost.Thread; is
|
||||
<code>TIME_UTC</code>. The epoch for <code>TIME_UTC</code>
|
||||
is 1970-01-01 00:00:00.</para>
|
||||
</description>
|
||||
</enum>
|
||||
</namespace>
|
||||
|
||||
<class name="read_write_mutex">
|
||||
<purpose>
|
||||
<para>The <classname>read_write_mutex</classname> class is a model of the
|
||||
<link linkend="thread.concepts.ReadWriteMutex">ReadWriteMutex</link> concept.</para>
|
||||
</purpose>
|
||||
|
||||
<description>
|
||||
<para>The <classname>read_write_mutex</classname> class is a model of the
|
||||
<link linkend="thread.concepts.ReadWriteMutex">ReadWriteMutex</link> concept.
|
||||
It should be used to synchronize access to shared resources using
|
||||
<link linkend="thread.concepts.read-write-locking-strategies.unspecified">Unspecified</link>
|
||||
locking mechanics.</para>
|
||||
|
||||
<para>For classes that model related mutex concepts, see
|
||||
<classname>try_read_write_mutex</classname> and <classname>timed_read_write_mutex</classname>.</para>
|
||||
|
||||
<para>The <classname>read_write_mutex</classname> class supplies the following typedefs,
|
||||
which <link linkend="thread.concepts.read-write-lock-models">model</link>
|
||||
the specified locking strategies:
|
||||
|
||||
<informaltable>
|
||||
<tgroup cols="2" align="left">
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Lock Name</entry>
|
||||
<entry>Lock Concept</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>scoped_read_write_lock</entry>
|
||||
<entry><link linkend="thread.concepts.ScopedReadWriteLock">ScopedReadWriteLock</link></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>scoped_read_lock</entry>
|
||||
<entry><link linkend="thread.concepts.ScopedLock">ScopedLock</link></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>scoped_write_lock</entry>
|
||||
<entry><link linkend="thread.concepts.ScopedLock">ScopedLock</link></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</informaltable>
|
||||
</para>
|
||||
|
||||
<para>The <classname>read_write_mutex</classname> class uses an
|
||||
<link linkend="thread.concepts.read-write-locking-strategies.unspecified">Unspecified</link>
|
||||
locking strategy, so attempts to recursively lock a <classname>read_write_mutex</classname>
|
||||
object or attempts to unlock one by threads that don't own a lock on it result in
|
||||
<emphasis role="bold">undefined behavior</emphasis>.
|
||||
This strategy allows implementations to be as efficient as possible
|
||||
on any given platform. It is, however, recommended that
|
||||
implementations include debugging support to detect misuse when
|
||||
<code>NDEBUG</code> is not defined.</para>
|
||||
|
||||
<para>Like all
|
||||
<link linkend="thread.concepts.read-write-mutex-models">read/write mutex models</link>
|
||||
in &Boost.Thread;, <classname>read_write_mutex</classname> has two types of
|
||||
<link linkend="thread.concepts.read-write-scheduling-policies">scheduling policies</link>, an
|
||||
<link linkend="thread.concepts.read-write-scheduling-policies.inter-class">inter-class sheduling policy</link>
|
||||
between threads trying to obtain different types of locks and an
|
||||
<link linkend="thread.concepts.read-write-scheduling-policies.intra-class">intra-class sheduling policy</link>
|
||||
between threads trying to obtain the same type of lock.
|
||||
The <classname>read_write_mutex</classname> class allows the
|
||||
programmer to choose what
|
||||
<link linkend="thread.concepts.read-write-scheduling-policies.inter-class">inter-class sheduling policy</link>
|
||||
will be used; however, like all read/write mutex models,
|
||||
<classname>read_write_mutex</classname> leaves the
|
||||
<link linkend="thread.concepts.read-write-scheduling-policies.intra-class">intra-class sheduling policy</link> as
|
||||
<link linkend="thread.concepts.read-write-locking-strategies.unspecified">Unspecified</link>.
|
||||
</para>
|
||||
|
||||
<note>Self-deadlock is virtually guaranteed if a thread tries to
|
||||
lock the same <classname>read_write_mutex</classname> multiple times
|
||||
unless all locks are read-locks (but see below)</note>
|
||||
</description>
|
||||
|
||||
<inherit access="private">
|
||||
<type><classname>boost::noncopyable</classname></type>
|
||||
<purpose>Exposition only</purpose>
|
||||
</inherit>
|
||||
|
||||
<inherit access="private">
|
||||
<type><classname>boost::noncopyable</classname></type>
|
||||
<purpose>Exposition only</purpose>
|
||||
</inherit>
|
||||
|
||||
<typedef name="scoped_read_write_lock">
|
||||
<type><emphasis>implementation-defined</emphasis></type>
|
||||
</typedef>
|
||||
|
||||
<typedef name="scoped_read_lock">
|
||||
<type><emphasis>implementation-defined</emphasis></type>
|
||||
</typedef>
|
||||
|
||||
<typedef name="scoped_write_lock">
|
||||
<type><emphasis>implementation-defined</emphasis></type>
|
||||
</typedef>
|
||||
|
||||
<constructor>
|
||||
<parameter name="count">
|
||||
<paramtype>boost::read_write_scheduling_policy</paramtype>
|
||||
</parameter>
|
||||
|
||||
<effects>Constructs a <classname>read_write_mutex</classname> object.
|
||||
</effects>
|
||||
|
||||
<postconditions><code>*this</code> is in an unlocked state.
|
||||
</postconditions>
|
||||
</constructor>
|
||||
|
||||
<destructor>
|
||||
<effects>Destroys a <classname>read_write_mutex</classname> object.</effects>
|
||||
|
||||
<requires><code>*this</code> is in an unlocked state.</requires>
|
||||
|
||||
<notes><emphasis role="bold">Danger:</emphasis> Destruction of a
|
||||
locked mutex is a serious programming error resulting in undefined
|
||||
behavior such as a program crash.</notes>
|
||||
</destructor>
|
||||
</class>
|
||||
|
||||
<class name="try_read_write_mutex">
|
||||
<purpose>
|
||||
<para>The <classname>try_read_write_mutex</classname> class is a model of the
|
||||
<link linkend="thread.concepts.TryReadWriteMutex">TryReadWriteMutex</link> concept.</para>
|
||||
</purpose>
|
||||
|
||||
<description>
|
||||
<para>The <classname>try_read_write_mutex</classname> class is a model of the
|
||||
<link linkend="thread.concepts.TryReadWriteMutex">TryReadWriteMutex</link> concept.
|
||||
It should be used to synchronize access to shared resources using
|
||||
<link linkend="thread.concepts.read-write-locking-strategies.unspecified">Unspecified</link>
|
||||
locking mechanics.</para>
|
||||
|
||||
<para>For classes that model related mutex concepts, see
|
||||
<classname>read_write_mutex</classname> and <classname>timed_read_write_mutex</classname>.</para>
|
||||
|
||||
<para>The <classname>try_read_write_mutex</classname> class supplies the following typedefs,
|
||||
which <link linkend="thread.concepts.read-write-lock-models">model</link>
|
||||
the specified locking strategies:
|
||||
|
||||
<informaltable>
|
||||
<tgroup cols="2" align="left">
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Lock Name</entry>
|
||||
<entry>Lock Concept</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>scoped_read_write_lock</entry>
|
||||
<entry><link linkend="thread.concepts.ScopedReadWriteLock">ScopedReadWriteLock</link></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>scoped_try_read_write_lock</entry>
|
||||
<entry><link linkend="thread.concepts.ScopedTryReadWriteLock">ScopedTryReadWriteLock</link></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>scoped_read_lock</entry>
|
||||
<entry><link linkend="thread.concepts.ScopedLock">ScopedLock</link></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>scoped_try_read_lock</entry>
|
||||
<entry><link linkend="thread.concepts.ScopedTryLock">ScopedTryLock</link></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>scoped_write_lock</entry>
|
||||
<entry><link linkend="thread.concepts.ScopedLock">ScopedLock</link></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>scoped_try_write_lock</entry>
|
||||
<entry><link linkend="thread.concepts.ScopedTryLock">ScopedTryLock</link></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</informaltable>
|
||||
</para>
|
||||
|
||||
<para>The <classname>try_read_write_mutex</classname> class uses an
|
||||
<link linkend="thread.concepts.read-write-locking-strategies.unspecified">Unspecified</link>
|
||||
locking strategy, so attempts to recursively lock a <classname>try_read_write_mutex</classname>
|
||||
object or attempts to unlock one by threads that don't own a lock on it result in
|
||||
<emphasis role="bold">undefined behavior</emphasis>.
|
||||
This strategy allows implementations to be as efficient as possible
|
||||
on any given platform. It is, however, recommended that
|
||||
implementations include debugging support to detect misuse when
|
||||
<code>NDEBUG</code> is not defined.</para>
|
||||
|
||||
<para>Like all
|
||||
<link linkend="thread.concepts.read-write-mutex-models">read/write mutex models</link>
|
||||
in &Boost.Thread;, <classname>try_read_write_mutex</classname> has two types of
|
||||
<link linkend="thread.concepts.read-write-scheduling-policies">scheduling policies</link>, an
|
||||
<link linkend="thread.concepts.read-write-scheduling-policies.inter-class">inter-class sheduling policy</link>
|
||||
between threads trying to obtain different types of locks and an
|
||||
<link linkend="thread.concepts.read-write-scheduling-policies.intra-class">intra-class sheduling policy</link>
|
||||
between threads trying to obtain the same type of lock.
|
||||
The <classname>try_read_write_mutex</classname> class allows the
|
||||
programmer to choose what
|
||||
<link linkend="thread.concepts.read-write-scheduling-policies.inter-class">inter-class sheduling policy</link>
|
||||
will be used; however, like all read/write mutex models,
|
||||
<classname>try_read_write_mutex</classname> leaves the
|
||||
<link linkend="thread.concepts.read-write-scheduling-policies.intra-class">intra-class sheduling policy</link> as
|
||||
<link linkend="thread.concepts.unspecified-scheduling-policy">Unspecified</link>.
|
||||
</para>
|
||||
|
||||
<note>Self-deadlock is virtually guaranteed if a thread tries to
|
||||
lock the same <classname>try_read_write_mutex</classname> multiple times
|
||||
unless all locks are read-locks (but see below)</note>
|
||||
</description>
|
||||
|
||||
<inherit access="private">
|
||||
<type><classname>boost::noncopyable</classname></type>
|
||||
<purpose>Exposition only</purpose>
|
||||
</inherit>
|
||||
|
||||
<typedef name="scoped_read_write_lock">
|
||||
<type><emphasis>implementation-defined</emphasis></type>
|
||||
</typedef>
|
||||
|
||||
<typedef name="scoped_try_read_write_lock">
|
||||
<type><emphasis>implementation-defined</emphasis></type>
|
||||
</typedef>
|
||||
|
||||
<typedef name="scoped_read_lock">
|
||||
<type><emphasis>implementation-defined</emphasis></type>
|
||||
</typedef>
|
||||
|
||||
<typedef name="scoped_try_read_lock">
|
||||
<type><emphasis>implementation-defined</emphasis></type>
|
||||
</typedef>
|
||||
|
||||
<typedef name="scoped_write_lock">
|
||||
<type><emphasis>implementation-defined</emphasis></type>
|
||||
</typedef>
|
||||
|
||||
<typedef name="scoped_try_write_lock">
|
||||
<type><emphasis>implementation-defined</emphasis></type>
|
||||
</typedef>
|
||||
|
||||
<constructor>
|
||||
<parameter name="count">
|
||||
<paramtype>boost::read_write_scheduling_policy</paramtype>
|
||||
</parameter>
|
||||
|
||||
<effects>Constructs a <classname>try_read_write_mutex</classname> object.
|
||||
</effects>
|
||||
|
||||
<postconditions><code>*this</code> is in an unlocked state.
|
||||
</postconditions>
|
||||
</constructor>
|
||||
|
||||
<destructor>
|
||||
<effects>Destroys a <classname>try_read_write_mutex</classname> object.</effects>
|
||||
|
||||
<requires><code>*this</code> is in an unlocked state.</requires>
|
||||
|
||||
<notes><emphasis role="bold">Danger:</emphasis> Destruction of a
|
||||
locked mutex is a serious programming error resulting in undefined
|
||||
behavior such as a program crash.</notes>
|
||||
</destructor>
|
||||
</class>
|
||||
|
||||
<class name="timed_read_write_mutex">
|
||||
<purpose>
|
||||
<para>The <classname>timed_read_write_mutex</classname> class is a model of the
|
||||
<link linkend="thread.concepts.TimedReadWriteMutex">TimedReadWriteMutex</link> concept.</para>
|
||||
</purpose>
|
||||
|
||||
<description>
|
||||
<para>The <classname>timed_read_write_mutex</classname> class is a model of the
|
||||
<link linkend="thread.concepts.TimedReadWriteMutex">TimedReadWriteMutex</link> concept.
|
||||
It should be used to synchronize access to shared resources using
|
||||
<link linkend="thread.concepts.read-write-locking-strategies.unspecified">Unspecified</link>
|
||||
locking mechanics.</para>
|
||||
|
||||
<para>For classes that model related mutex concepts, see
|
||||
<classname>read_write_mutex</classname> and <classname>try_read_write_mutex</classname>.</para>
|
||||
|
||||
<para>The <classname>timed_read_write_mutex</classname> class supplies the following typedefs,
|
||||
which <link linkend="thread.concepts.read-write-lock-models">model</link>
|
||||
the specified locking strategies:
|
||||
|
||||
<informaltable>
|
||||
<tgroup cols="2" align="left">
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Lock Name</entry>
|
||||
<entry>Lock Concept</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>scoped_read_write_lock</entry>
|
||||
<entry><link linkend="thread.concepts.ScopedReadWriteLock">ScopedReadWriteLock</link></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>scoped_try_read_write_lock</entry>
|
||||
<entry><link linkend="thread.concepts.ScopedTryReadWriteLock">ScopedTryReadWriteLock</link></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>scoped_timed_read_write_lock</entry>
|
||||
<entry><link linkend="thread.concepts.ScopedTimedReadWriteLock">ScopedTimedReadWriteLock</link></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>scoped_read_lock</entry>
|
||||
<entry><link linkend="thread.concepts.ScopedLock">ScopedLock</link></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>scoped_try_read_lock</entry>
|
||||
<entry><link linkend="thread.concepts.ScopedTryLock">ScopedTryLock</link></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>scoped_timed_read_lock</entry>
|
||||
<entry><link linkend="thread.concepts.ScopedTimedLock">ScopedTimedLock</link></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>scoped_write_lock</entry>
|
||||
<entry><link linkend="thread.concepts.ScopedLock">ScopedLock</link></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>scoped_try_write_lock</entry>
|
||||
<entry><link linkend="thread.concepts.ScopedTryLock">ScopedTryLock</link></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>scoped_timed_write_lock</entry>
|
||||
<entry><link linkend="thread.concepts.ScopedTimedLock">ScopedTimedLock</link></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</informaltable>
|
||||
</para>
|
||||
|
||||
<para>The <classname>timed_read_write_mutex</classname> class uses an
|
||||
<link linkend="thread.concepts.read-write-locking-strategies.unspecified">Unspecified</link>
|
||||
locking strategy, so attempts to recursively lock a <classname>timed_read_write_mutex</classname>
|
||||
object or attempts to unlock one by threads that don't own a lock on it result in
|
||||
<emphasis role="bold">undefined behavior</emphasis>.
|
||||
This strategy allows implementations to be as efficient as possible
|
||||
on any given platform. It is, however, recommended that
|
||||
implementations include debugging support to detect misuse when
|
||||
<code>NDEBUG</code> is not defined.</para>
|
||||
|
||||
<para>Like all
|
||||
<link linkend="thread.concepts.read-write-mutex-models">read/write mutex models</link>
|
||||
in &Boost.Thread;, <classname>timed_read_write_mutex</classname> has two types of
|
||||
<link linkend="thread.concepts.read-write-scheduling-policies">scheduling policies</link>, an
|
||||
<link linkend="thread.concepts.read-write-scheduling-policies.inter-class">inter-class sheduling policy</link>
|
||||
between threads trying to obtain different types of locks and an
|
||||
<link linkend="thread.concepts.read-write-scheduling-policies.intra-class">intra-class sheduling policy</link>
|
||||
between threads trying to obtain the same type of lock.
|
||||
The <classname>timed_read_write_mutex</classname> class allows the
|
||||
programmer to choose what
|
||||
<link linkend="thread.concepts.read-write-scheduling-policies.inter-class">inter-class sheduling policy</link>
|
||||
will be used; however, like all read/write mutex models,
|
||||
<classname>timed_read_write_mutex</classname> leaves the
|
||||
<link linkend="thread.concepts.read-write-scheduling-policies.intra-class">intra-class sheduling policy</link> as
|
||||
<link linkend="thread.concepts.unspecified-scheduling-policy">Unspecified</link>.
|
||||
</para>
|
||||
|
||||
<note>Self-deadlock is virtually guaranteed if a thread tries to
|
||||
lock the same <classname>timed_read_write_mutex</classname> multiple times
|
||||
unless all locks are read-locks (but see below)</note>
|
||||
</description>
|
||||
|
||||
<typedef name="scoped_read_write_lock">
|
||||
<type><emphasis>implementation-defined</emphasis></type>
|
||||
</typedef>
|
||||
|
||||
<typedef name="scoped_try_read_write_lock">
|
||||
<type><emphasis>implementation-defined</emphasis></type>
|
||||
</typedef>
|
||||
|
||||
<typedef name="scoped_timed_read_write_lock">
|
||||
<type><emphasis>implementation-defined</emphasis></type>
|
||||
</typedef>
|
||||
|
||||
<typedef name="scoped_read_lock">
|
||||
<type><emphasis>implementation-defined</emphasis></type>
|
||||
</typedef>
|
||||
|
||||
<typedef name="scoped_try_read_lock">
|
||||
<type><emphasis>implementation-defined</emphasis></type>
|
||||
</typedef>
|
||||
|
||||
<typedef name="scoped_timed_read_lock">
|
||||
<type><emphasis>implementation-defined</emphasis></type>
|
||||
</typedef>
|
||||
|
||||
<typedef name="scoped_write_lock">
|
||||
<type><emphasis>implementation-defined</emphasis></type>
|
||||
</typedef>
|
||||
|
||||
<typedef name="scoped_try_write_lock">
|
||||
<type><emphasis>implementation-defined</emphasis></type>
|
||||
</typedef>
|
||||
|
||||
<typedef name="scoped_timed_write_lock">
|
||||
<type><emphasis>implementation-defined</emphasis></type>
|
||||
</typedef>
|
||||
|
||||
<constructor>
|
||||
<parameter name="count">
|
||||
<paramtype>boost::read_write_scheduling_policy</paramtype>
|
||||
</parameter>
|
||||
|
||||
<effects>Constructs a <classname>timed_read_write_mutex</classname> object.
|
||||
</effects>
|
||||
|
||||
<postconditions><code>*this</code> is in an unlocked state.
|
||||
</postconditions>
|
||||
</constructor>
|
||||
|
||||
<destructor>
|
||||
<effects>Destroys a <classname>timed_read_write_mutex</classname> object.</effects>
|
||||
|
||||
<requires><code>*this</code> is in an unlocked state.</requires>
|
||||
|
||||
<notes><emphasis role="bold">Danger:</emphasis> Destruction of a
|
||||
locked mutex is a serious programming error resulting in undefined
|
||||
behavior such as a program crash.</notes>
|
||||
</destructor>
|
||||
</class>
|
||||
</namespace>
|
||||
</header>
|
||||
306
doc/recursive_mutex-ref.xml
Normal file
306
doc/recursive_mutex-ref.xml
Normal file
@@ -0,0 +1,306 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
||||
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
|
||||
<!ENTITY % thread.entities SYSTEM "entities.xml">
|
||||
%thread.entities;
|
||||
]>
|
||||
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
|
||||
Subject to the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
|
||||
-->
|
||||
<header name="boost/thread/recursive_mutex.hpp"
|
||||
last-revision="$Date$">
|
||||
<namespace name="boost">
|
||||
<class name="recursive_mutex">
|
||||
<purpose>
|
||||
<para>The <classname>recursive_mutex</classname> class is a model of the
|
||||
<link linkend="thread.concepts.Mutex">Mutex</link> concept.</para>
|
||||
</purpose>
|
||||
|
||||
<description>
|
||||
<para>The <classname>recursive_mutex</classname> class is a model of the
|
||||
<link linkend="thread.concepts.Mutex">Mutex</link> concept.
|
||||
It should be used to synchronize access to shared resources using
|
||||
<link linkend="thread.concepts.recursive-locking-strategy">Recursive</link>
|
||||
locking mechanics.</para>
|
||||
|
||||
<para>For classes that model related mutex concepts, see
|
||||
<classname>recursive_try_mutex</classname> and <classname>recursive_timed_mutex</classname>.</para>
|
||||
|
||||
<para>For <link linkend="thread.concepts.unspecified-locking-strategy">Unspecified</link>
|
||||
locking mechanics, see <classname>mutex</classname>,
|
||||
<classname>try_mutex</classname>, and <classname>timed_mutex</classname>.
|
||||
</para>
|
||||
|
||||
<para>The <classname>recursive_mutex</classname> class supplies the following typedef,
|
||||
which models the specified locking strategy:
|
||||
|
||||
<table>
|
||||
<title>Supported Lock Types</title>
|
||||
<tgroup cols="2" align="left">
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Lock Name</entry>
|
||||
<entry>Lock Concept</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>scoped_lock</entry>
|
||||
<entry><link linkend="thread.concepts.ScopedLock">ScopedLock</link></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</para>
|
||||
|
||||
<para>The <classname>recursive_mutex</classname> class uses a
|
||||
<link linkend="thread.concepts.recursive-locking-strategy">Recursive</link>
|
||||
locking strategy, so attempts to recursively lock a
|
||||
<classname>recursive_mutex</classname> object
|
||||
succeed and an internal "lock count" is maintained.
|
||||
Attempts to unlock a <classname>recursive_mutex</classname> object
|
||||
by threads that don't own a lock on it result in
|
||||
<emphasis role="bold">undefined behavior</emphasis>.</para>
|
||||
|
||||
<para>Like all
|
||||
<link linkend="thread.concepts.mutex-models">mutex models</link>
|
||||
in &Boost.Thread;, <classname>recursive_mutex</classname> leaves the
|
||||
<link linkend="thread.concepts.sheduling-policies">scheduling policy</link>
|
||||
as <link linkend="thread.concepts.unspecified-scheduling-policy">Unspecified</link>.
|
||||
Programmers should make no assumptions about the order in which
|
||||
waiting threads acquire a lock.</para>
|
||||
</description>
|
||||
|
||||
<inherit access="private">
|
||||
<type><classname>boost::noncopyable</classname></type>
|
||||
<purpose>Exposition only</purpose>
|
||||
</inherit>
|
||||
|
||||
<typedef name="scoped_lock">
|
||||
<type><emphasis>implementation-defined</emphasis></type>
|
||||
</typedef>
|
||||
|
||||
<constructor>
|
||||
<effects>Constructs a <classname>recursive_mutex</classname> object.
|
||||
</effects>
|
||||
|
||||
<postconditions><code>*this</code> is in an unlocked state.
|
||||
</postconditions>
|
||||
</constructor>
|
||||
|
||||
<destructor>
|
||||
<effects>Destroys a <classname>recursive_mutex</classname> object.</effects>
|
||||
|
||||
<requires><code>*this</code> is in an unlocked state.</requires>
|
||||
|
||||
<notes><emphasis role="bold">Danger:</emphasis> Destruction of a
|
||||
locked mutex is a serious programming error resulting in undefined
|
||||
behavior such as a program crash.</notes>
|
||||
</destructor>
|
||||
</class>
|
||||
|
||||
<class name="recursive_try_mutex">
|
||||
<purpose>
|
||||
<para>The <classname>recursive_try_mutex</classname> class is a model of the
|
||||
<link linkend="thread.concepts.TryMutex">TryMutex</link> concept.</para>
|
||||
</purpose>
|
||||
|
||||
<description>
|
||||
<para>The <classname>recursive_try_mutex</classname> class is a model of the
|
||||
<link linkend="thread.concepts.TryMutex">TryMutex</link> concept.
|
||||
It should be used to synchronize access to shared resources using
|
||||
<link linkend="thread.concepts.recursive-locking-strategy">Recursive</link>
|
||||
locking mechanics.</para>
|
||||
|
||||
<para>For classes that model related mutex concepts, see
|
||||
<classname>recursive_mutex</classname> and <classname>recursive_timed_mutex</classname>.</para>
|
||||
|
||||
<para>For <link linkend="thread.concepts.unspecified-locking-strategy">Unspecified</link>
|
||||
locking mechanics, see <classname>mutex</classname>,
|
||||
<classname>try_mutex</classname>, and <classname>timed_mutex</classname>.
|
||||
</para>
|
||||
|
||||
<para>The <classname>recursive_try_mutex</classname> class supplies the following typedefs,
|
||||
which model the specified locking strategies:
|
||||
|
||||
<table>
|
||||
<title>Supported Lock Types</title>
|
||||
<tgroup cols="2" align="left">
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Lock Name</entry>
|
||||
<entry>Lock Concept</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>scoped_lock</entry>
|
||||
<entry><link linkend="thread.concepts.ScopedLock">ScopedLock</link></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>scoped_try_lock</entry>
|
||||
<entry><link linkend="thread.concepts.ScopedTryLock">ScopedTryLock</link></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</para>
|
||||
|
||||
<para>The <classname>recursive_try_mutex</classname> class uses a
|
||||
<link linkend="thread.concepts.recursive-locking-strategy">Recursive</link>
|
||||
locking strategy, so attempts to recursively lock a
|
||||
<classname>recursive_try_mutex</classname> object
|
||||
succeed and an internal "lock count" is maintained.
|
||||
Attempts to unlock a <classname>recursive_mutex</classname> object
|
||||
by threads that don't own a lock on it result in
|
||||
<emphasis role="bold">undefined behavior</emphasis>.</para>
|
||||
|
||||
<para>Like all
|
||||
<link linkend="thread.concepts.mutex-models">mutex models</link>
|
||||
in &Boost.Thread;, <classname>recursive_try_mutex</classname> leaves the
|
||||
<link linkend="thread.concepts.sheduling-policies">scheduling policy</link>
|
||||
as <link linkend="thread.concepts.unspecified-scheduling-policy">Unspecified</link>.
|
||||
Programmers should make no assumptions about the order in which
|
||||
waiting threads acquire a lock.</para>
|
||||
</description>
|
||||
|
||||
<inherit access="private">
|
||||
<type><classname>boost::noncopyable</classname></type>
|
||||
<purpose>Exposition only</purpose>
|
||||
</inherit>
|
||||
|
||||
<typedef name="scoped_lock">
|
||||
<type><emphasis>implementation-defined</emphasis></type>
|
||||
</typedef>
|
||||
|
||||
<typedef name="scoped_try_lock">
|
||||
<type><emphasis>implementation-defined</emphasis></type>
|
||||
</typedef>
|
||||
|
||||
<constructor>
|
||||
<effects>Constructs a <classname>recursive_try_mutex</classname> object.
|
||||
</effects>
|
||||
|
||||
<postconditions><code>*this</code> is in an unlocked state.
|
||||
</postconditions>
|
||||
</constructor>
|
||||
|
||||
<destructor>
|
||||
<effects>Destroys a <classname>recursive_try_mutex</classname> object.
|
||||
</effects>
|
||||
|
||||
<requires><code>*this</code> is in an unlocked state.</requires>
|
||||
|
||||
<notes><emphasis role="bold">Danger:</emphasis> Destruction of a
|
||||
locked mutex is a serious programming error resulting in undefined
|
||||
behavior such as a program crash.</notes>
|
||||
</destructor>
|
||||
</class>
|
||||
|
||||
<class name="recursive_timed_mutex">
|
||||
<purpose>
|
||||
<para>The <classname>recursive_timed_mutex</classname> class is a model of the
|
||||
<link linkend="thread.concepts.TimedMutex">TimedMutex</link> concept.</para>
|
||||
</purpose>
|
||||
|
||||
<description>
|
||||
<para>The <classname>recursive_timed_mutex</classname> class is a model of the
|
||||
<link linkend="thread.concepts.TimedMutex">TimedMutex</link> concept.
|
||||
It should be used to synchronize access to shared resources using
|
||||
<link linkend="thread.concepts.recursive-locking-strategy">Recursive</link>
|
||||
locking mechanics.</para>
|
||||
|
||||
<para>For classes that model related mutex concepts, see
|
||||
<classname>recursive_mutex</classname> and <classname>recursive_try_mutex</classname>.</para>
|
||||
|
||||
<para>For <link linkend="thread.concepts.unspecified-locking-strategy">Unspecified</link>
|
||||
locking mechanics, see <classname>mutex</classname>,
|
||||
<classname>try_mutex</classname>, and <classname>timed_mutex</classname>.
|
||||
</para>
|
||||
|
||||
<para>The <classname>recursive_timed_mutex</classname> class supplies the following typedefs,
|
||||
which model the specified locking strategies:
|
||||
|
||||
<table>
|
||||
<title>Supported Lock Types</title>
|
||||
<tgroup cols="2" align="left">
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Lock Name</entry>
|
||||
<entry>Lock Concept</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>scoped_lock</entry>
|
||||
<entry><link linkend="thread.concepts.ScopedLock">ScopedLock</link></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>scoped_try_lock</entry>
|
||||
<entry><link linkend="thread.concepts.ScopedTryLock">ScopedTryLock</link></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>scoped_timed_lock</entry>
|
||||
<entry><link linkend="thread.concepts.ScopedTimedLock">ScopedTimedLock</link></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</para>
|
||||
|
||||
<para>The <classname>recursive_timed_mutex</classname> class uses a
|
||||
<link linkend="thread.concepts.recursive-locking-strategy">Recursive</link>
|
||||
locking strategy, so attempts to recursively lock a
|
||||
<classname>recursive_timed_mutex</classname> object
|
||||
succeed and an internal "lock count" is maintained.
|
||||
Attempts to unlock a <classname>recursive_mutex</classname> object
|
||||
by threads that don't own a lock on it result in
|
||||
<emphasis role="bold">undefined behavior</emphasis>.</para>
|
||||
|
||||
<para>Like all
|
||||
<link linkend="thread.concepts.mutex-models">mutex models</link>
|
||||
in &Boost.Thread;, <classname>recursive_timed_mutex</classname> leaves the
|
||||
<link linkend="thread.concepts.sheduling-policies">scheduling policy</link>
|
||||
as <link linkend="thread.concepts.unspecified-scheduling-policy">Unspecified</link>.
|
||||
Programmers should make no assumptions about the order in which
|
||||
waiting threads acquire a lock.</para>
|
||||
</description>
|
||||
|
||||
<inherit access="private">
|
||||
<type><classname>boost::noncopyable</classname></type>
|
||||
<purpose>Exposition only</purpose>
|
||||
</inherit>
|
||||
|
||||
<typedef name="scoped_lock">
|
||||
<type><emphasis>implementation-defined</emphasis></type>
|
||||
</typedef>
|
||||
|
||||
<typedef name="scoped_try_lock">
|
||||
<type><emphasis>implementation-defined</emphasis></type>
|
||||
</typedef>
|
||||
|
||||
<typedef name="scoped_timed_lock">
|
||||
<type><emphasis>implementation-defined</emphasis></type>
|
||||
</typedef>
|
||||
|
||||
<constructor>
|
||||
<effects>Constructs a <classname>recursive_timed_mutex</classname> object.
|
||||
</effects>
|
||||
|
||||
<postconditions><code>*this</code> is in an unlocked state.
|
||||
</postconditions>
|
||||
</constructor>
|
||||
|
||||
<destructor>
|
||||
<effects>Destroys a <classname>recursive_timed_mutex</classname> object.</effects>
|
||||
|
||||
<requires><code>*this</code> is in an unlocked state.</requires>
|
||||
|
||||
<notes><emphasis role="bold">Danger:</emphasis> Destruction of a
|
||||
locked mutex is a serious programming error resulting in undefined
|
||||
behavior such as a program crash.</notes>
|
||||
</destructor>
|
||||
</class>
|
||||
</namespace>
|
||||
</header>
|
||||
30
doc/reference.xml
Normal file
30
doc/reference.xml
Normal file
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
||||
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
|
||||
<!ENTITY % thread.entities SYSTEM "entities.xml">
|
||||
%thread.entities;
|
||||
]>
|
||||
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
|
||||
Subject to the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
|
||||
-->
|
||||
<library-reference id="thread.reference"
|
||||
last-revision="$Date$"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
<xi:include href="barrier-ref.xml"/>
|
||||
<xi:include href="condition-ref.xml"/>
|
||||
<xi:include href="exceptions-ref.xml"/>
|
||||
<xi:include href="mutex-ref.xml"/>
|
||||
<xi:include href="once-ref.xml"/>
|
||||
<xi:include href="recursive_mutex-ref.xml"/>
|
||||
<!--
|
||||
The read_write_mutex is held back from release, since the
|
||||
implementation suffers from a serious, yet unresolved bug.
|
||||
The implementation is likely to appear in a reworked
|
||||
form in the next release.
|
||||
-->
|
||||
<xi:include href="read_write_mutex-ref.xml"/>
|
||||
<xi:include href="thread-ref.xml"/>
|
||||
<xi:include href="tss-ref.xml"/>
|
||||
<xi:include href="xtime-ref.xml"/>
|
||||
</library-reference>
|
||||
204
doc/release_notes.xml
Normal file
204
doc/release_notes.xml
Normal file
@@ -0,0 +1,204 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
||||
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
|
||||
<!ENTITY % thread.entities SYSTEM "entities.xml">
|
||||
%thread.entities;
|
||||
]>
|
||||
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
|
||||
Subject to the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
|
||||
-->
|
||||
<section id="thread.release_notes" last-revision="$Date$">
|
||||
<title>Release Notes</title>
|
||||
<section id="thread.release_notes.boost_1_34_0">
|
||||
<title>Boost 1.34.0</title>
|
||||
|
||||
<section id="thread.release_notes.boost_1_34_0.change_log.maintainance">
|
||||
<title>New team of maintainers</title>
|
||||
|
||||
<para>
|
||||
Since the original author William E. Kempf no longer is available to
|
||||
maintain the &Boost.Thread; library, a new team has been formed
|
||||
in an attempt to continue the work on &Boost.Thread;.
|
||||
Fortunately William E. Kempf has given
|
||||
<ulink url="http://lists.boost.org/Archives/boost/2006/09/110143.php">
|
||||
permission </ulink>
|
||||
to use his work under the boost license.
|
||||
</para>
|
||||
<para>
|
||||
The team currently consists of
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
Anthony Williams, for the Win32 platform,
|
||||
</listitem>
|
||||
<listitem>
|
||||
Roland Schwarz, for the linux platform, and various "housekeeping" tasks.
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
Volunteers for other platforms are welcome!
|
||||
</para>
|
||||
<para>
|
||||
As the &Boost.Thread; was kind of orphaned over the last release, this release
|
||||
attempts to fix the known bugs. Upcoming releases will bring in new things.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="thread.release_notes.boost_1_34_0.change_log.read_write_mutex">
|
||||
<title>read_write_mutex still broken</title>
|
||||
|
||||
<para>
|
||||
<note>
|
||||
It has been decided not to release the Read/Write Mutex, since the current
|
||||
implementation suffers from a serious bug. The documentation of the concepts
|
||||
has been included though, giving the interested reader an opportunity to study the
|
||||
original concepts. Please refer to the following links if you are interested
|
||||
which problems led to the decision to held back this mutex type.The issue
|
||||
has been discovered before 1.33 was released and the code has
|
||||
been omitted from that release. A reworked mutex is expected to appear in 1.35.
|
||||
Also see:
|
||||
<ulink url="http://lists.boost.org/Archives/boost/2005/08/92307.php">
|
||||
read_write_mutex bug</ulink>
|
||||
and
|
||||
<ulink url="http://lists.boost.org/Archives/boost/2005/09/93180.php">
|
||||
read_write_mutex fundamentally broken in 1.33</ulink>
|
||||
</note>
|
||||
</para>
|
||||
</section>
|
||||
|
||||
</section>
|
||||
<section id="thread.release_notes.boost_1_32_0">
|
||||
<title>Boost 1.32.0</title>
|
||||
|
||||
<section id="thread.release_notes.boost_1_32_0.change_log.documentation">
|
||||
<title>Documentation converted to BoostBook</title>
|
||||
|
||||
<para>The documentation was converted to BoostBook format,
|
||||
and a number of errors and inconsistencies were
|
||||
fixed in the process.
|
||||
Since this was a fairly large task, there are likely to be
|
||||
more errors and inconsistencies remaining. If you find any,
|
||||
please report them!</para>
|
||||
</section>
|
||||
|
||||
<section id="thread.release_notes.boost_1_32_0.change_log.static_link">
|
||||
<title>Statically-link build option added</title>
|
||||
|
||||
<para>The option to link &Boost.Thread; as a static
|
||||
library has been added (with some limitations on Win32 platforms).
|
||||
This feature was originally removed from an earlier version
|
||||
of Boost because <classname>boost::thread_specific_ptr</classname>
|
||||
required that &Boost.Thread; be dynamically linked in order
|
||||
for its cleanup functionality to work on Win32 platforms.
|
||||
Because this limitation never applied to non-Win32 platforms,
|
||||
because significant progress has been made in removing
|
||||
the limitation on Win32 platforms (many thanks to
|
||||
Aaron LaFramboise and Roland Scwarz!), and because the lack
|
||||
of static linking is one of the most common complaints of
|
||||
&Boost.Thread; users, this decision was reversed.</para>
|
||||
|
||||
<para>On non-Win32 platforms:
|
||||
To choose the dynamically linked version of &Boost.Thread;
|
||||
using Boost's auto-linking feature, #define BOOST_THREAD_USE_DLL;
|
||||
to choose the statically linked version,
|
||||
#define BOOST_THREAD_USE_LIB.
|
||||
If neither symbols is #defined, the default will be chosen.
|
||||
Currently the default is the statically linked version.</para>
|
||||
|
||||
<para>On Win32 platforms using VC++:
|
||||
Use the same #defines as for non-Win32 platforms
|
||||
(BOOST_THREAD_USE_DLL and BOOST_THREAD_USE_LIB).
|
||||
If neither is #defined, the default will be chosen.
|
||||
Currently the default is the statically linked version
|
||||
if the VC++ run-time library is set to
|
||||
"Multi-threaded" or "Multi-threaded Debug", and
|
||||
the dynamically linked version
|
||||
if the VC++ run-time library is set to
|
||||
"Multi-threaded DLL" or "Multi-threaded Debug DLL".</para>
|
||||
|
||||
<para>On Win32 platforms using compilers other than VC++:
|
||||
Use the same #defines as for non-Win32 platforms
|
||||
(BOOST_THREAD_USE_DLL and BOOST_THREAD_USE_LIB).
|
||||
If neither is #defined, the default will be chosen.
|
||||
Currently the default is the dynamically linked version
|
||||
because it has not yet been possible to implement automatic
|
||||
tss cleanup in the statically linked version for compilers
|
||||
other than VC++, although it is hoped that this will be
|
||||
possible in a future version of &Boost.Thread;.
|
||||
|
||||
Note for advanced users: &Boost.Thread; provides several "hook"
|
||||
functions to allow users to experiment with the statically
|
||||
linked version on Win32 with compilers other than VC++.
|
||||
These functions are on_process_enter(), on_process_exit(),
|
||||
on_thread_enter(), and on_thread_exit(), and are defined
|
||||
in tls_hooks.cpp. See the comments in that file for more
|
||||
information.</para>
|
||||
</section>
|
||||
|
||||
<section id="thread.release_notes.boost_1_32_0.change_log.barrier">
|
||||
<title>Barrier functionality added</title>
|
||||
|
||||
<para>A new class, <classname>boost::barrier</classname>, was added.</para>
|
||||
</section>
|
||||
|
||||
<section id="thread.release_notes.boost_1_32_0.change_log.read_write_mutex">
|
||||
<title>Read/write mutex functionality added</title>
|
||||
|
||||
<para>New classes,
|
||||
<classname>boost::read_write_mutex</classname>,
|
||||
<classname>boost::try_read_write_mutex</classname>, and
|
||||
<classname>boost::timed_read_write_mutex</classname>
|
||||
were added.
|
||||
|
||||
<note>Since the read/write mutex and related classes are new,
|
||||
both interface and implementation are liable to change
|
||||
in future releases of &Boost.Thread;.
|
||||
The lock concepts and lock promotion in particular are
|
||||
still under discussion and very likely to change.</note>
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="thread.release_notes.boost_1_32_0.change_log.thread_specific_ptr">
|
||||
<title>Thread-specific pointer functionality changed</title>
|
||||
|
||||
<para>The <classname>boost::thread_specific_ptr</classname>
|
||||
constructor now takes an optional pointer to a cleanup function that
|
||||
is called to release the thread-specific data that is being pointed
|
||||
to by <classname>boost::thread_specific_ptr</classname> objects.</para>
|
||||
|
||||
<para>Fixed: the number of available thread-specific storage "slots"
|
||||
is too small on some platforms.</para>
|
||||
|
||||
<para>Fixed: <functionname>thread_specific_ptr::reset()</functionname>
|
||||
doesn't check error returned by <functionname>tss::set()</functionname>
|
||||
(the <functionname>tss::set()</functionname> function now throws
|
||||
if it fails instead of returning an error code).</para>
|
||||
|
||||
<para>Fixed: calling
|
||||
<functionname>boost::thread_specific_ptr::reset()</functionname> or
|
||||
<functionname>boost::thread_specific_ptr::release()</functionname>
|
||||
causes double-delete: once when
|
||||
<functionname>boost::thread_specific_ptr::reset()</functionname> or
|
||||
<functionname>boost::thread_specific_ptr::release()</functionname>
|
||||
is called and once when
|
||||
<functionname>boost::thread_specific_ptr::~thread_specific_ptr()</functionname>
|
||||
is called.</para>
|
||||
</section>
|
||||
|
||||
<section id="thread.release_notes.boost_1_32_0.change_log.mutex">
|
||||
<title>Mutex implementation changed for Win32</title>
|
||||
|
||||
<para>On Win32, <classname>boost::mutex</classname>,
|
||||
<classname>boost::try_mutex</classname>, <classname>boost::recursive_mutex</classname>,
|
||||
and <classname>boost::recursive_try_mutex</classname> now use a Win32 critical section
|
||||
whenever possible; otherwise they use a Win32 mutex. As before,
|
||||
<classname>boost::timed_mutex</classname> and
|
||||
<classname>boost::recursive_timed_mutex</classname> use a Win32 mutex.</para>
|
||||
</section>
|
||||
|
||||
<section id="thread.release_notes.boost_1_32_0.change_log.wince">
|
||||
<title>Windows CE support improved</title>
|
||||
|
||||
<para>Minor changes were made to make Boost.Thread work on Windows CE.</para>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
270
doc/thread-ref.xml
Normal file
270
doc/thread-ref.xml
Normal file
@@ -0,0 +1,270 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
||||
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
|
||||
<!ENTITY % thread.entities SYSTEM "entities.xml">
|
||||
%thread.entities;
|
||||
]>
|
||||
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
|
||||
Subject to the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
|
||||
-->
|
||||
<header name="boost/thread/thread.hpp"
|
||||
last-revision="$Date$">
|
||||
<namespace name="boost">
|
||||
<class name="thread">
|
||||
<purpose>
|
||||
<para>The <classname>thread</classname> class represents threads of
|
||||
execution, and provides the functionality to create and manage
|
||||
threads within the &Boost.Thread; library. See
|
||||
<xref linkend="thread.glossary"/> for a precise description of
|
||||
<link linkend="thread.glossary.thread">thread of execution</link>,
|
||||
and for definitions of threading-related terms and of thread states such as
|
||||
<link linkend="thread.glossary.thread-state">blocked</link>.</para>
|
||||
</purpose>
|
||||
|
||||
<description>
|
||||
<para>A <link linkend="thread.glossary.thread">thread of execution</link>
|
||||
has an initial function. For the program's initial thread, the initial
|
||||
function is <code>main()</code>. For other threads, the initial
|
||||
function is <code>operator()</code> of the function object passed to
|
||||
the <classname>thread</classname> object's constructor.</para>
|
||||
|
||||
<para>A thread of execution is said to be "finished"
|
||||
or to have "finished execution" when its initial function returns or
|
||||
is terminated. This includes completion of all thread cleanup
|
||||
handlers, and completion of the normal C++ function return behaviors,
|
||||
such as destruction of automatic storage (stack) objects and releasing
|
||||
any associated implementation resources.</para>
|
||||
|
||||
<para>A thread object has an associated state which is either
|
||||
"joinable" or "non-joinable".</para>
|
||||
|
||||
<para>Except as described below, the policy used by an implementation
|
||||
of &Boost.Thread; to schedule transitions between thread states is
|
||||
unspecified.</para>
|
||||
|
||||
<para><note>Just as the lifetime of a file may be different from the
|
||||
lifetime of an <code>iostream</code> object which represents the file, the lifetime
|
||||
of a thread of execution may be different from the
|
||||
<classname>thread</classname> object which represents the thread of
|
||||
execution. In particular, after a call to <code>join()</code>,
|
||||
the thread of execution will no longer exist even though the
|
||||
<classname>thread</classname> object continues to exist until the
|
||||
end of its normal lifetime. The converse is also possible; if
|
||||
a <classname>thread</classname> object is destroyed without
|
||||
<code>join()</code> first having been called, the thread of execution
|
||||
continues until its initial function completes.</note></para>
|
||||
</description>
|
||||
|
||||
<inherit access="private">
|
||||
<type><classname>boost::noncopyable</classname></type>
|
||||
<purpose>Exposition only</purpose>
|
||||
</inherit>
|
||||
|
||||
<constructor>
|
||||
<effects>Constructs a <classname>thread</classname> object
|
||||
representing the current thread of execution.</effects>
|
||||
|
||||
<postconditions><code>*this</code> is non-joinable.</postconditions>
|
||||
|
||||
<notes><emphasis role="bold">Danger:</emphasis>
|
||||
<code>*this</code> is valid only within the current thread.</notes>
|
||||
</constructor>
|
||||
|
||||
<constructor specifiers="explicit">
|
||||
<parameter name="threadfunc">
|
||||
<paramtype>const boost::function0<void>&</paramtype>
|
||||
</parameter>
|
||||
|
||||
<effects>
|
||||
Starts a new thread of execution and constructs a
|
||||
<classname>thread</classname> object representing it.
|
||||
Copies <code>threadfunc</code> (which in turn copies
|
||||
the function object wrapped by <code>threadfunc</code>)
|
||||
to an internal location which persists for the lifetime
|
||||
of the new thread of execution. Calls <code>operator()</code>
|
||||
on the copy of the <code>threadfunc</code> function object
|
||||
in the new thread of execution.
|
||||
</effects>
|
||||
|
||||
<postconditions><code>*this</code> is joinable.</postconditions>
|
||||
|
||||
<throws><code>boost::thread_resource_error</code> if a new thread
|
||||
of execution cannot be started.</throws>
|
||||
</constructor>
|
||||
|
||||
<destructor>
|
||||
<effects>Destroys <code>*this</code>. The actual thread of
|
||||
execution may continue to execute after the
|
||||
<classname>thread</classname> object has been destroyed.
|
||||
</effects>
|
||||
|
||||
<notes>If <code>*this</code> is joinable the actual thread
|
||||
of execution becomes "detached". Any resources used
|
||||
by the thread will be reclaimed when the thread of execution
|
||||
completes. To ensure such a thread of execution runs to completion
|
||||
before the <classname>thread</classname> object is destroyed, call
|
||||
<code>join()</code>.</notes>
|
||||
</destructor>
|
||||
|
||||
<method-group name="comparison">
|
||||
<method name="operator==" cv="const">
|
||||
<type>bool</type>
|
||||
|
||||
<parameter name="rhs">
|
||||
<type>const thread&</type>
|
||||
</parameter>
|
||||
|
||||
<requires>The thread is non-terminated or <code>*this</code>
|
||||
is joinable.</requires>
|
||||
|
||||
<returns><code>true</code> if <code>*this</code> and
|
||||
<code>rhs</code> represent the same thread of
|
||||
execution.</returns>
|
||||
</method>
|
||||
|
||||
<method name="operator!=" cv="const">
|
||||
<type>bool</type>
|
||||
|
||||
<parameter name="rhs">
|
||||
<type>const thread&</type>
|
||||
</parameter>
|
||||
|
||||
<requires>The thread is non-terminated or <code>*this</code>
|
||||
is joinable.</requires>
|
||||
|
||||
<returns><code>!(*this==rhs)</code>.</returns>
|
||||
</method>
|
||||
</method-group>
|
||||
|
||||
<method-group name="modifier">
|
||||
<method name="join">
|
||||
<type>void</type>
|
||||
|
||||
<requires><code>*this</code> is joinable.</requires>
|
||||
|
||||
<effects>The current thread of execution blocks until the
|
||||
initial function of the thread of execution represented by
|
||||
<code>*this</code> finishes and all resources are
|
||||
reclaimed.</effects>
|
||||
|
||||
<postcondition><code>*this</code> is non-joinable.</postcondition>
|
||||
|
||||
<notes>If <code>*this == thread()</code> the result is
|
||||
implementation-defined. If the implementation doesn't
|
||||
detect this the result will be
|
||||
<link linkend="thread.glossary.deadlock">deadlock</link>.
|
||||
</notes>
|
||||
</method>
|
||||
</method-group>
|
||||
|
||||
<method-group name="static">
|
||||
<method name="sleep" specifiers="static">
|
||||
<type>void</type>
|
||||
|
||||
<parameter name="xt">
|
||||
<paramtype>const <classname>xtime</classname>&</paramtype>
|
||||
</parameter>
|
||||
|
||||
<effects>The current thread of execution blocks until
|
||||
<code>xt</code> is reached.</effects>
|
||||
</method>
|
||||
|
||||
<method name="yield" specifiers="static">
|
||||
<type>void</type>
|
||||
|
||||
<effects>The current thread of execution is placed in the
|
||||
<link linkend="thread.glossary.thread-state">ready</link>
|
||||
state.</effects>
|
||||
|
||||
<notes>
|
||||
<simpara>Allow the current thread to give up the rest of its
|
||||
time slice (or other scheduling quota) to another thread.
|
||||
Particularly useful in non-preemptive implementations.</simpara>
|
||||
</notes>
|
||||
</method>
|
||||
</method-group>
|
||||
</class>
|
||||
|
||||
<class name="thread_group">
|
||||
<purpose>
|
||||
The <classname>thread_group</classname> class provides a container
|
||||
for easy grouping of threads to simplify several common thread
|
||||
creation and management idioms.
|
||||
</purpose>
|
||||
|
||||
<inherit access="private">
|
||||
<type><classname>boost::noncopyable</classname></type>
|
||||
<purpose>Exposition only</purpose>
|
||||
</inherit>
|
||||
|
||||
|
||||
<constructor>
|
||||
<effects>Constructs an empty <classname>thread_group</classname>
|
||||
container.</effects>
|
||||
</constructor>
|
||||
|
||||
<destructor>
|
||||
<effects>Destroys each contained thread object. Destroys <code>*this</code>.</effects>
|
||||
|
||||
<notes>Behavior is undefined if another thread references
|
||||
<code>*this </code> during the execution of the destructor.
|
||||
</notes>
|
||||
</destructor>
|
||||
|
||||
<method-group name="modifier">
|
||||
<method name="create_thread">
|
||||
<type><classname>thread</classname>*</type>
|
||||
|
||||
<parameter name="threadfunc">
|
||||
<paramtype>const boost::function0<void>&</paramtype>
|
||||
</parameter>
|
||||
|
||||
<effects>Creates a new <classname>thread</classname> object
|
||||
that executes <code>threadfunc</code> and adds it to the
|
||||
<code>thread_group</code> container object's list of managed
|
||||
<classname>thread</classname> objects.</effects>
|
||||
|
||||
<returns>Pointer to the newly created
|
||||
<classname>thread</classname> object.</returns>
|
||||
</method>
|
||||
|
||||
<method name="add_thread">
|
||||
<type>void</type>
|
||||
|
||||
<parameter name="thrd">
|
||||
<paramtype><classname>thread</classname>*</paramtype>
|
||||
</parameter>
|
||||
|
||||
<effects>Adds <code>thrd</code> to the
|
||||
<classname>thread_group</classname> object's list of managed
|
||||
<classname>thread</classname> objects. The <code>thrd</code>
|
||||
object must have been allocated via <code>operator new</code> and will
|
||||
be deleted when the group is destroyed.</effects>
|
||||
</method>
|
||||
|
||||
<method name="remove_thread">
|
||||
<type>void</type>
|
||||
|
||||
<parameter name="thrd">
|
||||
<paramtype><classname>thread</classname>*</paramtype>
|
||||
</parameter>
|
||||
|
||||
<effects>Removes <code>thread</code> from <code>*this</code>'s
|
||||
list of managed <classname>thread</classname> objects.</effects>
|
||||
|
||||
<throws><emphasis role="bold">???</emphasis> if
|
||||
<code>thrd</code> is not in <code>*this</code>'s list
|
||||
of managed <classname>thread</classname> objects.</throws>
|
||||
</method>
|
||||
|
||||
<method name="join_all">
|
||||
<type>void</type>
|
||||
|
||||
<effects>Calls <code>join()</code> on each of the managed
|
||||
<classname>thread</classname> objects.</effects>
|
||||
</method>
|
||||
</method-group>
|
||||
</class>
|
||||
</namespace>
|
||||
</header>
|
||||
48
doc/thread.xml
Normal file
48
doc/thread.xml
Normal file
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
||||
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
|
||||
<!ENTITY % thread.entities SYSTEM "entities.xml">
|
||||
%thread.entities;
|
||||
]>
|
||||
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
|
||||
Subject to the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
|
||||
-->
|
||||
<library name="Thread" dirname="thread" id="thread"
|
||||
last-revision="$Date$"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
<libraryinfo>
|
||||
<author>
|
||||
<firstname>William</firstname>
|
||||
<othername>E.</othername>
|
||||
<surname>Kempf</surname>
|
||||
</author>
|
||||
<copyright>
|
||||
<year>2001</year>
|
||||
<year>2002</year>
|
||||
<year>2003</year>
|
||||
<holder>William E. Kempf</holder>
|
||||
</copyright>
|
||||
<legalnotice>
|
||||
<para>Subject to the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)</para>
|
||||
</legalnotice>
|
||||
<librarypurpose>Portable C++ multi-threading</librarypurpose>
|
||||
<librarycategory name="category:concurrent" />
|
||||
<title>Boost.Thread</title>
|
||||
</libraryinfo>
|
||||
<title>Boost.Thread</title>
|
||||
<xi:include href="overview.xml"/>
|
||||
<xi:include href="design.xml"/>
|
||||
<xi:include href="concepts.xml"/>
|
||||
<xi:include href="rationale.xml"/>
|
||||
<xi:include href="reference.xml"/>
|
||||
<xi:include href="faq.xml"/>
|
||||
<xi:include href="configuration.xml"/>
|
||||
<xi:include href="build.xml"/>
|
||||
<xi:include href="implementation_notes.xml"/>
|
||||
<xi:include href="release_notes.xml"/>
|
||||
<xi:include href="glossary.xml"/>
|
||||
<xi:include href="acknowledgements.xml"/>
|
||||
<xi:include href="bibliography.xml"/>
|
||||
</library>
|
||||
206
doc/tss-ref.xml
Normal file
206
doc/tss-ref.xml
Normal file
@@ -0,0 +1,206 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
||||
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
|
||||
<!ENTITY % thread.entities SYSTEM "entities.xml">
|
||||
%thread.entities;
|
||||
]>
|
||||
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
|
||||
Subject to the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
|
||||
-->
|
||||
<header name="boost/thread/tss.hpp"
|
||||
last-revision="$Date$">
|
||||
<namespace name="boost">
|
||||
<class name="thread_specific_ptr">
|
||||
<purpose>
|
||||
The <classname>thread_specific_ptr</classname> class defines
|
||||
an interface for using thread specific storage.
|
||||
</purpose>
|
||||
|
||||
<description>
|
||||
<para>Thread specific storage is data associated with
|
||||
individual threads and is often used to make operations
|
||||
that rely on global data
|
||||
<link linkend="thread.glossary.thread-safe">thread-safe</link>.
|
||||
</para>
|
||||
|
||||
<para>Template <classname>thread_specific_ptr</classname>
|
||||
stores a pointer to an object obtained on a thread-by-thread
|
||||
basis and calls a specified cleanup handler on the contained
|
||||
pointer when the thread terminates. The cleanup handlers are
|
||||
called in the reverse order of construction of the
|
||||
<classname>thread_specific_ptr</classname>s, and for the
|
||||
initial thread are called by the destructor, providing the
|
||||
same ordering guarantees as for normal declarations. Each
|
||||
thread initially stores the null pointer in each
|
||||
<classname>thread_specific_ptr</classname> instance.</para>
|
||||
|
||||
<para>The template <classname>thread_specific_ptr</classname>
|
||||
is useful in the following cases:
|
||||
<itemizedlist>
|
||||
<listitem>An interface was originally written assuming
|
||||
a single thread of control and it is being ported to a
|
||||
multithreaded environment.</listitem>
|
||||
|
||||
<listitem>Each thread of control invokes sequences of
|
||||
methods that share data that are physically unique
|
||||
for each thread, but must be logically accessed
|
||||
through a globally visible access point instead of
|
||||
being explicitly passed.</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</description>
|
||||
|
||||
<inherit access="private">
|
||||
<type><classname>boost::noncopyable</classname></type>
|
||||
<purpose>Exposition only</purpose>
|
||||
</inherit>
|
||||
|
||||
<constructor>
|
||||
<requires>The expression <code>delete get()</code> is well
|
||||
formed.</requires>
|
||||
|
||||
<effects>A thread-specific data key is allocated and visible to
|
||||
all threads in the process. Upon creation, the value
|
||||
<code>NULL</code> will be associated with the new key in all
|
||||
active threads. A cleanup method is registered with the key
|
||||
that will call <code>delete</code> on the value associated
|
||||
with the key for a thread when it exits. When a thread exits,
|
||||
if a key has a registered cleanup method and the thread has a
|
||||
non-<code>NULL</code> value associated with that key, the value
|
||||
of the key is set to <code>NULL</code> and then the cleanup
|
||||
method is called with the previously associated value as its
|
||||
sole argument. The order in which registered cleanup methods
|
||||
are called when a thread exits is undefined. If after all the
|
||||
cleanup methods have been called for all non-<code>NULL</code>
|
||||
values, there are still some non-<code>NULL</code> values
|
||||
with associated cleanup handlers the result is undefined
|
||||
behavior.</effects>
|
||||
|
||||
<throws><classname>boost::thread_resource_error</classname> if
|
||||
the necessary resources can not be obtained.</throws>
|
||||
|
||||
<notes>There may be an implementation specific limit to the
|
||||
number of thread specific storage objects that can be created,
|
||||
and this limit may be small.</notes>
|
||||
|
||||
<rationale>The most common need for cleanup will be to call
|
||||
<code>delete</code> on the associated value. If other forms
|
||||
of cleanup are required the overloaded constructor should be
|
||||
called instead.</rationale>
|
||||
</constructor>
|
||||
|
||||
<constructor>
|
||||
<parameter name="cleanup">
|
||||
<paramtype>void (*cleanup)(void*)</paramtype>
|
||||
</parameter>
|
||||
|
||||
<effects>A thread-specific data key is allocated and visible to
|
||||
all threads in the process. Upon creation, the value
|
||||
<code>NULL</code> will be associated with the new key in all
|
||||
active threads. The <code>cleanup</code> method is registered
|
||||
with the key and will be called for a thread with the value
|
||||
associated with the key for that thread when it exits. When a
|
||||
thread exits, if a key has a registered cleanup method and the
|
||||
thread has a non-<code>NULL</code> value associated with that
|
||||
key, the value of the key is set to <code>NULL</code> and then
|
||||
the cleanup method is called with the previously associated
|
||||
value as its sole argument. The order in which registered
|
||||
cleanup methods are called when a thread exits is undefined.
|
||||
If after all the cleanup methods have been called for all
|
||||
non-<code>NULL</code> values, there are still some
|
||||
non-<code>NULL</code> values with associated cleanup handlers
|
||||
the result is undefined behavior.</effects>
|
||||
|
||||
<throws><classname>boost::thread_resource_error</classname> if
|
||||
the necessary resources can not be obtained.</throws>
|
||||
|
||||
<notes>There may be an implementation specific limit to the
|
||||
number of thread specific storage objects that can be created,
|
||||
and this limit may be small.</notes>
|
||||
|
||||
<rationale>There is the occasional need to register
|
||||
specialized cleanup methods, or to register no cleanup method
|
||||
at all (done by passing <code>NULL</code> to this constructor.
|
||||
</rationale>
|
||||
</constructor>
|
||||
|
||||
<destructor>
|
||||
<effects>Deletes the thread-specific data key allocated by the
|
||||
constructor. The thread-specific data values associated with
|
||||
the key need not be <code>NULL</code>. It is the responsibility
|
||||
of the application to perform any cleanup actions for data
|
||||
associated with the key.</effects>
|
||||
|
||||
<notes>Does not destroy any data that may be stored in any
|
||||
thread's thread specific storage. For this reason you should
|
||||
not destroy a <classname>thread_specific_ptr</classname> object
|
||||
until you are certain there are no threads running that have
|
||||
made use of its thread specific storage.</notes>
|
||||
|
||||
<rationale>Associated data is not cleaned up because registered
|
||||
cleanup methods need to be run in the thread that allocated the
|
||||
associated data to be guarranteed to work correctly. There's no
|
||||
safe way to inject the call into another thread's execution
|
||||
path, making it impossible to call the cleanup methods safely.
|
||||
</rationale>
|
||||
</destructor>
|
||||
|
||||
<method-group name="modifier functions">
|
||||
<method name="release">
|
||||
<type>T*</type>
|
||||
|
||||
<postconditions><code>*this</code> holds the null pointer
|
||||
for the current thread.</postconditions>
|
||||
|
||||
<returns><code>this->get()</code> prior to the call.</returns>
|
||||
|
||||
<rationale>This method provides a mechanism for the user to
|
||||
relinquish control of the data associated with the
|
||||
thread-specific key.</rationale>
|
||||
</method>
|
||||
|
||||
<method name="reset">
|
||||
<type>void</type>
|
||||
|
||||
<parameter name="p">
|
||||
<paramtype>T*</paramtype>
|
||||
<default>0</default>
|
||||
</parameter>
|
||||
|
||||
<effects>If <code>this->get() != p &&
|
||||
this->get() != NULL</code> then call the
|
||||
associated cleanup function.</effects>
|
||||
|
||||
<postconditions><code>*this</code> holds the pointer
|
||||
<code>p</code> for the current thread.</postconditions>
|
||||
</method>
|
||||
</method-group>
|
||||
|
||||
<method-group name="observer functions">
|
||||
<method name="get" cv="const">
|
||||
<type>T*</type>
|
||||
|
||||
<returns>The object stored in thread specific storage for
|
||||
the current thread for <code>*this</code>.</returns>
|
||||
|
||||
<notes>Each thread initially returns 0.</notes>
|
||||
</method>
|
||||
|
||||
<method name="operator->" cv="const">
|
||||
<type>T*</type>
|
||||
|
||||
<returns><code>this->get()</code>.</returns>
|
||||
</method>
|
||||
|
||||
<method name="operator*()" cv="const">
|
||||
<type>T&</type>
|
||||
|
||||
<requires><code>this->get() != 0</code></requires>
|
||||
|
||||
<returns><code>this->get()</code>.</returns>
|
||||
</method>
|
||||
</method-group>
|
||||
</class>
|
||||
</namespace>
|
||||
</header>
|
||||
82
doc/xtime-ref.xml
Normal file
82
doc/xtime-ref.xml
Normal file
@@ -0,0 +1,82 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
||||
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
|
||||
<!ENTITY % thread.entities SYSTEM "entities.xml">
|
||||
%thread.entities;
|
||||
]>
|
||||
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
|
||||
Subject to the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
|
||||
-->
|
||||
<header name="boost/thread/xtime.hpp"
|
||||
last-revision="$Date$">
|
||||
<namespace name="boost">
|
||||
<enum name="xtime_clock_types">
|
||||
<enumvalue name="TIME_UTC" />
|
||||
|
||||
<purpose>
|
||||
<para>Specifies the clock type to use when creating
|
||||
an object of type <classname>xtime</classname>.</para>
|
||||
</purpose>
|
||||
|
||||
<description>
|
||||
<para>The only clock type supported by &Boost.Thread; is
|
||||
<code>TIME_UTC</code>. The epoch for <code>TIME_UTC</code>
|
||||
is 1970-01-01 00:00:00.</para>
|
||||
</description>
|
||||
</enum>
|
||||
|
||||
<struct name="xtime">
|
||||
<purpose>
|
||||
<simpara>An object of type <classname>xtime</classname>
|
||||
defines a time that is used to perform high-resolution time operations.
|
||||
This is a temporary solution that will be replaced by a more robust time
|
||||
library once available in Boost.</simpara>
|
||||
</purpose>
|
||||
|
||||
<description>
|
||||
<simpara>The <classname>xtime</classname> type is used to represent a point on
|
||||
some time scale or a duration in time. This type may be proposed for the C standard by
|
||||
Markus Kuhn. &Boost.Thread; provides only a very minimal implementation of this
|
||||
proposal; it is expected that a full implementation (or some other time
|
||||
library) will be provided in Boost as a separate library, at which time &Boost.Thread;
|
||||
will deprecate its own implementation.</simpara>
|
||||
|
||||
<simpara><emphasis role="bold">Note</emphasis> that the resolution is
|
||||
implementation specific. For many implementations the best resolution
|
||||
of time is far more than one nanosecond, and even when the resolution
|
||||
is reasonably good, the latency of a call to <code>xtime_get()</code>
|
||||
may be significant. For maximum portability, avoid durations of less than
|
||||
one second.</simpara>
|
||||
</description>
|
||||
|
||||
<free-function-group name="creation">
|
||||
<function name="xtime_get">
|
||||
<type>int</type>
|
||||
|
||||
<parameter name="xtp">
|
||||
<paramtype><classname>xtime</classname>*</paramtype>
|
||||
</parameter>
|
||||
|
||||
<parameter name="clock_type">
|
||||
<paramtype>int</paramtype>
|
||||
</parameter>
|
||||
|
||||
<postconditions>
|
||||
<simpara><code>xtp</code> represents the current point in
|
||||
time as a duration since the epoch specified by
|
||||
<code>clock_type</code>.</simpara>
|
||||
</postconditions>
|
||||
|
||||
<returns>
|
||||
<simpara><code>clock_type</code> if successful, otherwise 0.</simpara>
|
||||
</returns>
|
||||
</function>
|
||||
</free-function-group>
|
||||
|
||||
<data-member name="sec">
|
||||
<type><emphasis>platform-specific-type</emphasis></type>
|
||||
</data-member>
|
||||
</struct>
|
||||
</namespace>
|
||||
</header>
|
||||
2
example/.cvsignore
Normal file
2
example/.cvsignore
Normal file
@@ -0,0 +1,2 @@
|
||||
bin
|
||||
*.pdb
|
||||
23
example/Jamfile.v2
Normal file
23
example/Jamfile.v2
Normal file
@@ -0,0 +1,23 @@
|
||||
# Copyright (C) 2001-2003
|
||||
# William E. Kempf
|
||||
#
|
||||
# Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
project boost/thread/example
|
||||
: requirements <library>../build//boost_thread <threading>multi
|
||||
;
|
||||
|
||||
|
||||
exe monitor : monitor.cpp ;
|
||||
exe starvephil : starvephil.cpp ;
|
||||
exe tennis : tennis.cpp ;
|
||||
exe condition : condition.cpp ;
|
||||
exe mutex : mutex.cpp ;
|
||||
exe once : once.cpp ;
|
||||
exe recursive_mutex : recursive_mutex.cpp ;
|
||||
exe thread : thread.cpp ;
|
||||
exe thread_group : thread_group.cpp ;
|
||||
exe tss : tss.cpp ;
|
||||
exe xtime : xtime.cpp ;
|
||||
|
||||
74
example/condition.cpp
Normal file
74
example/condition.cpp
Normal file
@@ -0,0 +1,74 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/thread/condition.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
class bounded_buffer : private boost::noncopyable
|
||||
{
|
||||
public:
|
||||
typedef boost::mutex::scoped_lock lock;
|
||||
|
||||
bounded_buffer(int n) : begin(0), end(0), buffered(0), circular_buf(n) { }
|
||||
|
||||
void send (int m) {
|
||||
lock lk(monitor);
|
||||
while (buffered == circular_buf.size())
|
||||
buffer_not_full.wait(lk);
|
||||
circular_buf[end] = m;
|
||||
end = (end+1) % circular_buf.size();
|
||||
++buffered;
|
||||
buffer_not_empty.notify_one();
|
||||
}
|
||||
int receive() {
|
||||
lock lk(monitor);
|
||||
while (buffered == 0)
|
||||
buffer_not_empty.wait(lk);
|
||||
int i = circular_buf[begin];
|
||||
begin = (begin+1) % circular_buf.size();
|
||||
--buffered;
|
||||
buffer_not_full.notify_one();
|
||||
return i;
|
||||
}
|
||||
|
||||
private:
|
||||
int begin, end, buffered;
|
||||
std::vector<int> circular_buf;
|
||||
boost::condition buffer_not_full, buffer_not_empty;
|
||||
boost::mutex monitor;
|
||||
};
|
||||
|
||||
bounded_buffer buf(2);
|
||||
|
||||
void sender() {
|
||||
int n = 0;
|
||||
while (n < 100) {
|
||||
buf.send(n);
|
||||
std::cout << "sent: " << n << std::endl;
|
||||
++n;
|
||||
}
|
||||
buf.send(-1);
|
||||
}
|
||||
|
||||
void receiver() {
|
||||
int n;
|
||||
do {
|
||||
n = buf.receive();
|
||||
std::cout << "received: " << n << std::endl;
|
||||
} while (n != -1); // -1 indicates end of buffer
|
||||
}
|
||||
|
||||
int main(int, char*[])
|
||||
{
|
||||
boost::thread thrd1(&sender);
|
||||
boost::thread thrd2(&receiver);
|
||||
thrd1.join();
|
||||
thrd2.join();
|
||||
return 0;
|
||||
}
|
||||
112
example/monitor.cpp
Normal file
112
example/monitor.cpp
Normal file
@@ -0,0 +1,112 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <boost/thread/condition.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
namespace {
|
||||
const int ITERS = 100;
|
||||
boost::mutex io_mutex;
|
||||
} // namespace
|
||||
|
||||
template <typename M>
|
||||
class buffer_t
|
||||
{
|
||||
public:
|
||||
typedef typename M::scoped_lock scoped_lock;
|
||||
|
||||
buffer_t(int n)
|
||||
: p(0), c(0), full(0), buf(n)
|
||||
{
|
||||
}
|
||||
|
||||
void send(int m)
|
||||
{
|
||||
scoped_lock lk(mutex);
|
||||
while (full == buf.size())
|
||||
cond.wait(lk);
|
||||
buf[p] = m;
|
||||
p = (p+1) % buf.size();
|
||||
++full;
|
||||
cond.notify_one();
|
||||
}
|
||||
int receive()
|
||||
{
|
||||
scoped_lock lk(mutex);
|
||||
while (full == 0)
|
||||
cond.wait(lk);
|
||||
int i = buf[c];
|
||||
c = (c+1) % buf.size();
|
||||
--full;
|
||||
cond.notify_one();
|
||||
return i;
|
||||
}
|
||||
|
||||
static buffer_t& get_buffer()
|
||||
{
|
||||
static buffer_t buf(2);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void do_sender_thread()
|
||||
{
|
||||
for (int n = 0; n < ITERS; ++n)
|
||||
{
|
||||
{
|
||||
boost::mutex::scoped_lock lock(io_mutex);
|
||||
std::cout << "sending: " << n << std::endl;
|
||||
}
|
||||
get_buffer().send(n);
|
||||
}
|
||||
}
|
||||
|
||||
static void do_receiver_thread()
|
||||
{
|
||||
for (int x=0; x < (ITERS/2); ++x)
|
||||
{
|
||||
int n = get_buffer().receive();
|
||||
{
|
||||
boost::mutex::scoped_lock lock(io_mutex);
|
||||
std::cout << "received: " << n << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
M mutex;
|
||||
boost::condition cond;
|
||||
unsigned int p, c, full;
|
||||
std::vector<int> buf;
|
||||
};
|
||||
|
||||
template <typename M>
|
||||
void do_test(M* dummy=0)
|
||||
{
|
||||
typedef buffer_t<M> buffer_type;
|
||||
buffer_type::get_buffer();
|
||||
boost::thread thrd1(&buffer_type::do_receiver_thread);
|
||||
boost::thread thrd2(&buffer_type::do_receiver_thread);
|
||||
boost::thread thrd3(&buffer_type::do_sender_thread);
|
||||
thrd1.join();
|
||||
thrd2.join();
|
||||
thrd3.join();
|
||||
}
|
||||
|
||||
void test_buffer()
|
||||
{
|
||||
do_test<boost::mutex>();
|
||||
do_test<boost::recursive_mutex>();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_buffer();
|
||||
return 0;
|
||||
}
|
||||
47
example/mutex.cpp
Normal file
47
example/mutex.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <iostream>
|
||||
|
||||
boost::mutex io_mutex; // The iostreams are not guaranteed to be thread-safe!
|
||||
|
||||
class counter
|
||||
{
|
||||
public:
|
||||
counter() : count(0) { }
|
||||
|
||||
int increment() {
|
||||
boost::mutex::scoped_lock scoped_lock(mutex);
|
||||
return ++count;
|
||||
}
|
||||
|
||||
private:
|
||||
boost::mutex mutex;
|
||||
int count;
|
||||
};
|
||||
|
||||
counter c;
|
||||
|
||||
void change_count()
|
||||
{
|
||||
int i = c.increment();
|
||||
boost::mutex::scoped_lock scoped_lock(io_mutex);
|
||||
std::cout << "count == " << i << std::endl;
|
||||
}
|
||||
|
||||
int main(int, char*[])
|
||||
{
|
||||
const int num_threads = 4;
|
||||
boost::thread_group thrds;
|
||||
for (int i=0; i < num_threads; ++i)
|
||||
thrds.create_thread(&change_count);
|
||||
|
||||
thrds.join_all();
|
||||
|
||||
return 0;
|
||||
}
|
||||
31
example/once.cpp
Normal file
31
example/once.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/once.hpp>
|
||||
#include <cassert>
|
||||
|
||||
int value=0;
|
||||
boost::once_flag once = BOOST_ONCE_INIT;
|
||||
|
||||
void init()
|
||||
{
|
||||
++value;
|
||||
}
|
||||
|
||||
void thread_proc()
|
||||
{
|
||||
boost::call_once(&init, once);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
boost::thread_group threads;
|
||||
for (int i=0; i<5; ++i)
|
||||
threads.create_thread(&thread_proc);
|
||||
threads.join_all();
|
||||
assert(value == 1);
|
||||
}
|
||||
49
example/recursive_mutex.cpp
Normal file
49
example/recursive_mutex.cpp
Normal file
@@ -0,0 +1,49 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <iostream>
|
||||
|
||||
class counter
|
||||
{
|
||||
public:
|
||||
counter() : count(0) { }
|
||||
|
||||
int add(int val) {
|
||||
boost::recursive_mutex::scoped_lock scoped_lock(mutex);
|
||||
count += val;
|
||||
return count;
|
||||
}
|
||||
int increment() {
|
||||
boost::recursive_mutex::scoped_lock scoped_lock(mutex);
|
||||
return add(1);
|
||||
}
|
||||
|
||||
private:
|
||||
boost::recursive_mutex mutex;
|
||||
int count;
|
||||
};
|
||||
|
||||
counter c;
|
||||
|
||||
void change_count()
|
||||
{
|
||||
std::cout << "count == " << c.increment() << std::endl;
|
||||
}
|
||||
|
||||
int main(int, char*[])
|
||||
{
|
||||
const int num_threads=4;
|
||||
|
||||
boost::thread_group threads;
|
||||
for (int i=0; i < num_threads; ++i)
|
||||
threads.create_thread(&change_count);
|
||||
|
||||
threads.join_all();
|
||||
|
||||
return 0;
|
||||
}
|
||||
185
example/starvephil.cpp
Normal file
185
example/starvephil.cpp
Normal file
@@ -0,0 +1,185 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/condition.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <iostream>
|
||||
#include <time.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
boost::mutex iomx;
|
||||
} // namespace
|
||||
|
||||
class canteen
|
||||
{
|
||||
public:
|
||||
canteen() : m_chickens(0) { }
|
||||
|
||||
void get(int id)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(m_mutex);
|
||||
while (m_chickens == 0)
|
||||
{
|
||||
{
|
||||
boost::mutex::scoped_lock lock(iomx);
|
||||
std::cout << "(" << clock() << ") Phil" << id <<
|
||||
": wot, no chickens? I'll WAIT ..." << std::endl;
|
||||
}
|
||||
m_condition.wait(lock);
|
||||
}
|
||||
{
|
||||
boost::mutex::scoped_lock lock(iomx);
|
||||
std::cout << "(" << clock() << ") Phil" << id <<
|
||||
": those chickens look good ... one please ..." << std::endl;
|
||||
}
|
||||
m_chickens--;
|
||||
}
|
||||
void put(int value)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(m_mutex);
|
||||
{
|
||||
boost::mutex::scoped_lock lock(iomx);
|
||||
std::cout << "(" << clock()
|
||||
<< ") Chef: ouch ... make room ... this dish is "
|
||||
<< "very hot ..." << std::endl;
|
||||
}
|
||||
boost::xtime xt;
|
||||
boost::xtime_get(&xt, boost::TIME_UTC);
|
||||
xt.sec += 3;
|
||||
boost::thread::sleep(xt);
|
||||
m_chickens += value;
|
||||
{
|
||||
boost::mutex::scoped_lock lock(iomx);
|
||||
std::cout << "(" << clock() <<
|
||||
") Chef: more chickens ... " << m_chickens <<
|
||||
" now available ... NOTIFYING ..." << std::endl;
|
||||
}
|
||||
m_condition.notify_all();
|
||||
}
|
||||
|
||||
private:
|
||||
boost::mutex m_mutex;
|
||||
boost::condition m_condition;
|
||||
int m_chickens;
|
||||
};
|
||||
|
||||
canteen g_canteen;
|
||||
|
||||
void chef()
|
||||
{
|
||||
const int chickens = 4;
|
||||
{
|
||||
boost::mutex::scoped_lock lock(iomx);
|
||||
std::cout << "(" << clock() << ") Chef: starting ..." << std::endl;
|
||||
}
|
||||
for (;;)
|
||||
{
|
||||
{
|
||||
boost::mutex::scoped_lock lock(iomx);
|
||||
std::cout << "(" << clock() << ") Chef: cooking ..." << std::endl;
|
||||
}
|
||||
boost::xtime xt;
|
||||
boost::xtime_get(&xt, boost::TIME_UTC);
|
||||
xt.sec += 2;
|
||||
boost::thread::sleep(xt);
|
||||
{
|
||||
boost::mutex::scoped_lock lock(iomx);
|
||||
std::cout << "(" << clock() << ") Chef: " << chickens
|
||||
<< " chickens, ready-to-go ..." << std::endl;
|
||||
}
|
||||
g_canteen.put(chickens);
|
||||
}
|
||||
}
|
||||
|
||||
struct phil
|
||||
{
|
||||
phil(int id) : m_id(id) { }
|
||||
void run() {
|
||||
{
|
||||
boost::mutex::scoped_lock lock(iomx);
|
||||
std::cout << "(" << clock() << ") Phil" << m_id
|
||||
<< ": starting ..." << std::endl;
|
||||
}
|
||||
for (;;)
|
||||
{
|
||||
if (m_id > 0)
|
||||
{
|
||||
boost::xtime xt;
|
||||
boost::xtime_get(&xt, boost::TIME_UTC);
|
||||
xt.sec += 3;
|
||||
boost::thread::sleep(xt);
|
||||
}
|
||||
{
|
||||
boost::mutex::scoped_lock lock(iomx);
|
||||
std::cout << "(" << clock() << ") Phil" << m_id
|
||||
<< ": gotta eat ..." << std::endl;
|
||||
}
|
||||
g_canteen.get(m_id);
|
||||
{
|
||||
boost::mutex::scoped_lock lock(iomx);
|
||||
std::cout << "(" << clock() << ") Phil" << m_id
|
||||
<< ": mmm ... that's good ..." << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
static void do_thread(void* param) {
|
||||
static_cast<phil*>(param)->run();
|
||||
}
|
||||
|
||||
int m_id;
|
||||
};
|
||||
|
||||
struct thread_adapt
|
||||
{
|
||||
thread_adapt(void (*func)(void*), void* param)
|
||||
: _func(func), _param(param)
|
||||
{
|
||||
}
|
||||
int operator()() const
|
||||
{
|
||||
_func(_param);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void (*_func)(void*);
|
||||
void* _param;
|
||||
};
|
||||
|
||||
class thread_adapter
|
||||
{
|
||||
public:
|
||||
thread_adapter(void (*func)(void*), void* param)
|
||||
: _func(func), _param(param)
|
||||
{
|
||||
}
|
||||
void operator()() const { _func(_param); }
|
||||
private:
|
||||
void (*_func)(void*);
|
||||
void* _param;
|
||||
};
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
boost::thread thrd_chef(&chef);
|
||||
phil p[] = { phil(0), phil(1), phil(2), phil(3), phil(4) };
|
||||
boost::thread thrd_phil0(thread_adapter(&phil::do_thread, &p[0]));
|
||||
boost::thread thrd_phil1(thread_adapter(&phil::do_thread, &p[1]));
|
||||
boost::thread thrd_phil2(thread_adapter(&phil::do_thread, &p[2]));
|
||||
boost::thread thrd_phil3(thread_adapter(&phil::do_thread, &p[3]));
|
||||
boost::thread thrd_phil4(thread_adapter(&phil::do_thread, &p[4]));
|
||||
|
||||
thrd_chef.join();
|
||||
thrd_phil0.join();
|
||||
thrd_phil1.join();
|
||||
thrd_phil2.join();
|
||||
thrd_phil3.join();
|
||||
thrd_phil4.join();
|
||||
|
||||
return 0;
|
||||
}
|
||||
135
example/tennis.cpp
Normal file
135
example/tennis.cpp
Normal file
@@ -0,0 +1,135 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/condition.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <iostream>
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
# include <windows.h>
|
||||
# include <process.h>
|
||||
#endif
|
||||
|
||||
enum game_state
|
||||
{
|
||||
START,
|
||||
PLAYER_A,
|
||||
PLAYER_B,
|
||||
GAME_OVER,
|
||||
ONE_PLAYER_GONE,
|
||||
BOTH_PLAYERS_GONE
|
||||
};
|
||||
|
||||
int state;
|
||||
boost::mutex mutex;
|
||||
boost::condition cond;
|
||||
|
||||
char* player_name(int state)
|
||||
{
|
||||
if (state == PLAYER_A)
|
||||
return "PLAYER-A";
|
||||
if (state == PLAYER_B)
|
||||
return "PLAYER-B";
|
||||
throw "bad player";
|
||||
return 0;
|
||||
}
|
||||
|
||||
void player(void* param)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
|
||||
int active = (int)param;
|
||||
int other = active == PLAYER_A ? PLAYER_B : PLAYER_A;
|
||||
|
||||
while (state < GAME_OVER)
|
||||
{
|
||||
std::cout << player_name(active) << ": Play." << std::endl;
|
||||
state = other;
|
||||
cond.notify_all();
|
||||
do
|
||||
{
|
||||
cond.wait(lock);
|
||||
if (state == other)
|
||||
{
|
||||
std::cout << "---" << player_name(active)
|
||||
<< ": Spurious wakeup!" << std::endl;
|
||||
}
|
||||
} while (state == other);
|
||||
}
|
||||
|
||||
++state;
|
||||
std::cout << player_name(active) << ": Gone." << std::endl;
|
||||
cond.notify_all();
|
||||
}
|
||||
|
||||
struct thread_adapt
|
||||
{
|
||||
thread_adapt(void (*func)(void*), void* param)
|
||||
: _func(func), _param(param)
|
||||
{
|
||||
}
|
||||
int operator()() const
|
||||
{
|
||||
_func(_param);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void (*_func)(void*);
|
||||
void* _param;
|
||||
};
|
||||
|
||||
class thread_adapter
|
||||
{
|
||||
public:
|
||||
thread_adapter(void (*func)(void*), void* param)
|
||||
: _func(func), _param(param)
|
||||
{
|
||||
}
|
||||
void operator()() const { _func(_param); }
|
||||
private:
|
||||
void (*_func)(void*);
|
||||
void* _param;
|
||||
};
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
state = START;
|
||||
|
||||
boost::thread thrda(thread_adapter(&player, (void*)PLAYER_A));
|
||||
boost::thread thrdb(thread_adapter(&player, (void*)PLAYER_B));
|
||||
|
||||
boost::xtime xt;
|
||||
boost::xtime_get(&xt, boost::TIME_UTC);
|
||||
xt.sec += 1;
|
||||
boost::thread::sleep(xt);
|
||||
{
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
std::cout << "---Noise ON..." << std::endl;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 1000000; ++i)
|
||||
cond.notify_all();
|
||||
|
||||
{
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
std::cout << "---Noise OFF..." << std::endl;
|
||||
state = GAME_OVER;
|
||||
cond.notify_all();
|
||||
do
|
||||
{
|
||||
cond.wait(lock);
|
||||
} while (state != BOTH_PLAYERS_GONE);
|
||||
}
|
||||
|
||||
std::cout << "GAME OVER" << std::endl;
|
||||
|
||||
thrda.join();
|
||||
thrdb.join();
|
||||
|
||||
return 0;
|
||||
}
|
||||
35
example/thread.cpp
Normal file
35
example/thread.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <iostream>
|
||||
|
||||
struct thread_alarm
|
||||
{
|
||||
thread_alarm(int secs) : m_secs(secs) { }
|
||||
void operator()()
|
||||
{
|
||||
boost::xtime xt;
|
||||
boost::xtime_get(&xt, boost::TIME_UTC);
|
||||
xt.sec += m_secs;
|
||||
|
||||
boost::thread::sleep(xt);
|
||||
|
||||
std::cout << "alarm sounded..." << std::endl;
|
||||
}
|
||||
|
||||
int m_secs;
|
||||
};
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int secs = 5;
|
||||
std::cout << "setting alarm for 5 seconds..." << std::endl;
|
||||
thread_alarm alarm(secs);
|
||||
boost::thread thrd(alarm);
|
||||
thrd.join();
|
||||
}
|
||||
25
example/thread_group.cpp
Normal file
25
example/thread_group.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <iostream>
|
||||
|
||||
int count = 0;
|
||||
boost::mutex mutex;
|
||||
|
||||
void increment_count()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
std::cout << "count = " << ++count << std::endl;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
boost::thread_group threads;
|
||||
for (int i = 0; i < 10; ++i)
|
||||
threads.create_thread(&increment_count);
|
||||
threads.join_all();
|
||||
}
|
||||
36
example/tss.cpp
Normal file
36
example/tss.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/tss.hpp>
|
||||
#include <cassert>
|
||||
|
||||
boost::thread_specific_ptr<int> value;
|
||||
|
||||
void increment()
|
||||
{
|
||||
int* p = value.get();
|
||||
++*p;
|
||||
}
|
||||
|
||||
void thread_proc()
|
||||
{
|
||||
value.reset(new int(0)); // initialize the thread's storage
|
||||
for (int i=0; i<10; ++i)
|
||||
{
|
||||
increment();
|
||||
int* p = value.get();
|
||||
assert(*p == i+1);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
boost::thread_group threads;
|
||||
for (int i=0; i<5; ++i)
|
||||
threads.create_thread(&thread_proc);
|
||||
threads.join_all();
|
||||
}
|
||||
16
example/xtime.cpp
Normal file
16
example/xtime.cpp
Normal file
@@ -0,0 +1,16 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
boost::xtime xt;
|
||||
boost::xtime_get(&xt, boost::TIME_UTC);
|
||||
xt.sec += 1;
|
||||
boost::thread::sleep(xt); // Sleep for 1 second
|
||||
}
|
||||
19
include/boost/thread.hpp
Normal file
19
include/boost/thread.hpp
Normal file
@@ -0,0 +1,19 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#if !defined(BOOST_THREAD_WEK01082003_HPP)
|
||||
#define BOOST_THREAD_WEK01082003_HPP
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/condition.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/once.hpp>
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
#include <boost/thread/tss.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
|
||||
#endif
|
||||
44
include/boost/thread/barrier.hpp
Normal file
44
include/boost/thread/barrier.hpp
Normal file
@@ -0,0 +1,44 @@
|
||||
// Copyright (C) 2002-2003
|
||||
// David Moore, William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_BARRIER_JDM030602_HPP
|
||||
#define BOOST_BARRIER_JDM030602_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/condition.hpp>
|
||||
|
||||
namespace boost {
|
||||
|
||||
class BOOST_THREAD_DECL barrier
|
||||
{
|
||||
public:
|
||||
barrier(unsigned int count);
|
||||
~barrier();
|
||||
|
||||
bool wait();
|
||||
|
||||
private:
|
||||
mutex m_mutex;
|
||||
// disable warnings about non dll import
|
||||
// see: http://www.boost.org/more/separate_compilation.html#dlls
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4251 4231 4660 4275)
|
||||
#endif
|
||||
condition m_cond;
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
unsigned int m_threshold;
|
||||
unsigned int m_count;
|
||||
unsigned int m_generation;
|
||||
};
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
201
include/boost/thread/condition.hpp
Normal file
201
include/boost/thread/condition.hpp
Normal file
@@ -0,0 +1,201 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_CONDITION_WEK070601_HPP
|
||||
#define BOOST_CONDITION_WEK070601_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/thread/detail/lock.hpp>
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
# include <pthread.h>
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
# include "scoped_critical_region.hpp"
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
struct xtime;
|
||||
// disable warnings about non dll import
|
||||
// see: http://www.boost.org/more/separate_compilation.html#dlls
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4251 4231 4660 4275)
|
||||
#endif
|
||||
|
||||
namespace detail {
|
||||
|
||||
class BOOST_THREAD_DECL condition_impl : private noncopyable
|
||||
{
|
||||
friend class condition;
|
||||
|
||||
public:
|
||||
condition_impl();
|
||||
~condition_impl();
|
||||
|
||||
void notify_one();
|
||||
void notify_all();
|
||||
|
||||
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||
void enter_wait();
|
||||
void do_wait();
|
||||
bool do_timed_wait(const xtime& xt);
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
void do_wait(pthread_mutex_t* pmutex);
|
||||
bool do_timed_wait(const xtime& xt, pthread_mutex_t* pmutex);
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
void* m_gate;
|
||||
void* m_queue;
|
||||
void* m_mutex;
|
||||
unsigned m_gone; // # threads that timed out and never made it to m_queue
|
||||
unsigned long m_blocked; // # threads blocked on the condition
|
||||
unsigned m_waiting; // # threads no longer waiting for the condition but
|
||||
// still waiting to be removed from m_queue
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
pthread_cond_t m_condition;
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
MPSemaphoreID m_gate;
|
||||
MPSemaphoreID m_queue;
|
||||
threads::mac::detail::scoped_critical_region m_mutex;
|
||||
threads::mac::detail::scoped_critical_region m_mutex_mutex;
|
||||
unsigned m_gone; // # threads that timed out and never made it to m_queue
|
||||
unsigned long m_blocked; // # threads blocked on the condition
|
||||
unsigned m_waiting; // # threads no longer waiting for the condition but
|
||||
// still waiting to be removed from m_queue
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
class condition : private noncopyable
|
||||
{
|
||||
public:
|
||||
condition() { }
|
||||
~condition() { }
|
||||
|
||||
void notify_one() { m_impl.notify_one(); }
|
||||
void notify_all() { m_impl.notify_all(); }
|
||||
|
||||
template <typename L>
|
||||
void wait(L& lock)
|
||||
{
|
||||
if (!lock)
|
||||
throw lock_error();
|
||||
|
||||
do_wait(lock.m_mutex);
|
||||
}
|
||||
|
||||
template <typename L, typename Pr>
|
||||
void wait(L& lock, Pr pred)
|
||||
{
|
||||
if (!lock)
|
||||
throw lock_error();
|
||||
|
||||
while (!pred())
|
||||
do_wait(lock.m_mutex);
|
||||
}
|
||||
|
||||
template <typename L>
|
||||
bool timed_wait(L& lock, const xtime& xt)
|
||||
{
|
||||
if (!lock)
|
||||
throw lock_error();
|
||||
|
||||
return do_timed_wait(lock.m_mutex, xt);
|
||||
}
|
||||
|
||||
template <typename L, typename Pr>
|
||||
bool timed_wait(L& lock, const xtime& xt, Pr pred)
|
||||
{
|
||||
if (!lock)
|
||||
throw lock_error();
|
||||
|
||||
while (!pred())
|
||||
{
|
||||
if (!do_timed_wait(lock.m_mutex, xt))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
detail::condition_impl m_impl;
|
||||
|
||||
template <typename M>
|
||||
void do_wait(M& mutex)
|
||||
{
|
||||
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||
m_impl.enter_wait();
|
||||
#endif
|
||||
|
||||
typedef detail::thread::lock_ops<M>
|
||||
#if defined(__HP_aCC) && __HP_aCC <= 33900 && !defined(BOOST_STRICT_CONFIG)
|
||||
# define lock_ops lock_ops_ // HP confuses lock_ops witht the template
|
||||
#endif
|
||||
lock_ops;
|
||||
|
||||
typename lock_ops::lock_state state;
|
||||
lock_ops::unlock(mutex, state);
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
m_impl.do_wait(state.pmutex);
|
||||
#elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||
m_impl.do_wait();
|
||||
#endif
|
||||
|
||||
lock_ops::lock(mutex, state);
|
||||
#undef lock_ops
|
||||
}
|
||||
|
||||
template <typename M>
|
||||
bool do_timed_wait(M& mutex, const xtime& xt)
|
||||
{
|
||||
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||
m_impl.enter_wait();
|
||||
#endif
|
||||
|
||||
typedef detail::thread::lock_ops<M>
|
||||
#if defined(__HP_aCC) && __HP_aCC <= 33900 && !defined(BOOST_STRICT_CONFIG)
|
||||
# define lock_ops lock_ops_ // HP confuses lock_ops witht the template
|
||||
#endif
|
||||
lock_ops;
|
||||
|
||||
typename lock_ops::lock_state state;
|
||||
lock_ops::unlock(mutex, state);
|
||||
|
||||
bool ret = false;
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
ret = m_impl.do_timed_wait(xt, state.pmutex);
|
||||
#elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||
ret = m_impl.do_timed_wait(xt);
|
||||
#endif
|
||||
|
||||
lock_ops::lock(mutex, state);
|
||||
#undef lock_ops
|
||||
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
} // namespace boost
|
||||
|
||||
// Change Log:
|
||||
// 8 Feb 01 WEKEMPF Initial version.
|
||||
// 22 May 01 WEKEMPF Modified to use xtime for time outs.
|
||||
// 23 May 01 WEKEMPF Removed "duration" timed_waits, as they are too
|
||||
// difficult to use with spurious wakeups.
|
||||
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
|
||||
|
||||
#endif // BOOST_CONDITION_WEK070601_HPP
|
||||
95
include/boost/thread/detail/config.hpp
Normal file
95
include/boost/thread/detail/config.hpp
Normal file
@@ -0,0 +1,95 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_THREAD_CONFIG_WEK01032003_HPP
|
||||
#define BOOST_THREAD_CONFIG_WEK01032003_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/detail/workaround.hpp>
|
||||
|
||||
#if BOOST_WORKAROUND(__BORLANDC__, < 0x600)
|
||||
# pragma warn -8008 // Condition always true/false
|
||||
# pragma warn -8080 // Identifier declared but never used
|
||||
# pragma warn -8057 // Parameter never used
|
||||
# pragma warn -8066 // Unreachable code
|
||||
#endif
|
||||
|
||||
// insist on threading support being available:
|
||||
#include <boost/config/requires_threads.hpp>
|
||||
|
||||
// compatibility with the rest of Boost's auto-linking code:
|
||||
#if defined(BOOST_THREAD_DYN_DLL) || defined(BOOST_ALL_DYN_LINK)
|
||||
# undef BOOST_THREAD_USE_LIB
|
||||
# define BOOST_THREAD_USE_DLL
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_THREAD_BUILD_DLL) //Build dll
|
||||
#elif defined(BOOST_THREAD_BUILD_LIB) //Build lib
|
||||
#elif defined(BOOST_THREAD_USE_DLL) //Use dll
|
||||
#elif defined(BOOST_THREAD_USE_LIB) //Use lib
|
||||
#else //Use default
|
||||
# if defined(BOOST_HAS_WINTHREADS)
|
||||
# if defined(BOOST_MSVC) || defined(BOOST_INTEL_WIN)
|
||||
//For compilers supporting auto-tss cleanup
|
||||
//with Boost.Threads lib, use Boost.Threads lib
|
||||
# define BOOST_THREAD_USE_LIB
|
||||
# else
|
||||
//For compilers not yet supporting auto-tss cleanup
|
||||
//with Boost.Threads lib, use Boost.Threads dll
|
||||
# define BOOST_THREAD_USE_DLL
|
||||
# endif
|
||||
# else
|
||||
# define BOOST_THREAD_USE_LIB
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_HAS_DECLSPEC)
|
||||
# if defined(BOOST_THREAD_BUILD_DLL) //Build dll
|
||||
# define BOOST_THREAD_DECL __declspec(dllexport)
|
||||
# elif defined(BOOST_THREAD_USE_DLL) //Use dll
|
||||
# define BOOST_THREAD_DECL __declspec(dllimport)
|
||||
# else
|
||||
# define BOOST_THREAD_DECL
|
||||
# endif
|
||||
#else
|
||||
# define BOOST_THREAD_DECL
|
||||
#endif // BOOST_HAS_DECLSPEC
|
||||
|
||||
//
|
||||
// Automatically link to the correct build variant where possible.
|
||||
//
|
||||
#if !defined(BOOST_ALL_NO_LIB) && !defined(BOOST_THREAD_NO_LIB) && !defined(BOOST_THREAD_BUILD_DLL) && !defined(BOOST_THREAD_BUILD_LIB)
|
||||
//
|
||||
// Tell the autolink to link dynamically, this will get undef'ed by auto_link.hpp
|
||||
// once it's done with it:
|
||||
//
|
||||
#if defined(BOOST_THREAD_USE_DLL)
|
||||
# define BOOST_DYN_LINK
|
||||
#endif
|
||||
//
|
||||
// Set the name of our library, this will get undef'ed by auto_link.hpp
|
||||
// once it's done with it:
|
||||
//
|
||||
#if defined(BOOST_THREAD_LIB_NAME)
|
||||
# define BOOST_LIB_NAME BOOST_THREAD_LIB_NAME
|
||||
#else
|
||||
# define BOOST_LIB_NAME boost_thread
|
||||
#endif
|
||||
//
|
||||
// If we're importing code from a dll, then tell auto_link.hpp about it:
|
||||
//
|
||||
// And include the header that does the work:
|
||||
//
|
||||
#include <boost/config/auto_link.hpp>
|
||||
#endif // auto-linking disabled
|
||||
|
||||
#endif // BOOST_THREAD_CONFIG_WEK1032003_HPP
|
||||
|
||||
// Change Log:
|
||||
// 22 Jan 05 Roland Schwarz (speedsnail)
|
||||
// Usage of BOOST_HAS_DECLSPEC macro.
|
||||
// Default again is static lib usage.
|
||||
// BOOST_DYN_LINK only defined when autolink included.
|
||||
39
include/boost/thread/detail/force_cast.hpp
Normal file
39
include/boost/thread/detail/force_cast.hpp
Normal file
@@ -0,0 +1,39 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// Mac Murrett
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org for most recent version including documentation.
|
||||
|
||||
#ifndef BOOST_FORCE_CAST_MJM012402_HPP
|
||||
#define BOOST_FORCE_CAST_MJM012402_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace detail {
|
||||
namespace thread {
|
||||
|
||||
// force_cast will convert anything to anything.
|
||||
|
||||
// general case
|
||||
template<class Return_Type, class Argument_Type>
|
||||
inline Return_Type &force_cast(Argument_Type &rSrc)
|
||||
{
|
||||
return(*reinterpret_cast<Return_Type *>(&rSrc));
|
||||
}
|
||||
|
||||
// specialization for const
|
||||
template<class Return_Type, class Argument_Type>
|
||||
inline const Return_Type &force_cast(const Argument_Type &rSrc)
|
||||
{
|
||||
return(*reinterpret_cast<const Return_Type *>(&rSrc));
|
||||
}
|
||||
|
||||
} // namespace thread
|
||||
} // namespace detail
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_FORCE_CAST_MJM012402_HPP
|
||||
209
include/boost/thread/detail/lock.hpp
Normal file
209
include/boost/thread/detail/lock.hpp
Normal file
@@ -0,0 +1,209 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_XLOCK_WEK070601_HPP
|
||||
#define BOOST_XLOCK_WEK070601_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
|
||||
namespace boost {
|
||||
|
||||
class condition;
|
||||
struct xtime;
|
||||
|
||||
namespace detail { namespace thread {
|
||||
|
||||
template <typename Mutex>
|
||||
class lock_ops : private noncopyable
|
||||
{
|
||||
private:
|
||||
lock_ops() { }
|
||||
|
||||
public:
|
||||
typedef typename Mutex::cv_state lock_state;
|
||||
|
||||
static void lock(Mutex& m)
|
||||
{
|
||||
m.do_lock();
|
||||
}
|
||||
static bool trylock(Mutex& m)
|
||||
{
|
||||
return m.do_trylock();
|
||||
}
|
||||
static bool timedlock(Mutex& m, const xtime& xt)
|
||||
{
|
||||
return m.do_timedlock(xt);
|
||||
}
|
||||
static void unlock(Mutex& m)
|
||||
{
|
||||
m.do_unlock();
|
||||
}
|
||||
static void lock(Mutex& m, lock_state& state)
|
||||
{
|
||||
m.do_lock(state);
|
||||
}
|
||||
static void unlock(Mutex& m, lock_state& state)
|
||||
{
|
||||
m.do_unlock(state);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Mutex>
|
||||
class scoped_lock : private noncopyable
|
||||
{
|
||||
public:
|
||||
typedef Mutex mutex_type;
|
||||
|
||||
explicit scoped_lock(Mutex& mx, bool initially_locked=true)
|
||||
: m_mutex(mx), m_locked(false)
|
||||
{
|
||||
if (initially_locked) lock();
|
||||
}
|
||||
~scoped_lock()
|
||||
{
|
||||
if (m_locked) unlock();
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
if (m_locked) throw lock_error();
|
||||
lock_ops<Mutex>::lock(m_mutex);
|
||||
m_locked = true;
|
||||
}
|
||||
void unlock()
|
||||
{
|
||||
if (!m_locked) throw lock_error();
|
||||
lock_ops<Mutex>::unlock(m_mutex);
|
||||
m_locked = false;
|
||||
}
|
||||
|
||||
bool locked() const { return m_locked; }
|
||||
operator const void*() const { return m_locked ? this : 0; }
|
||||
|
||||
private:
|
||||
friend class boost::condition;
|
||||
|
||||
Mutex& m_mutex;
|
||||
bool m_locked;
|
||||
};
|
||||
|
||||
template <typename TryMutex>
|
||||
class scoped_try_lock : private noncopyable
|
||||
{
|
||||
public:
|
||||
typedef TryMutex mutex_type;
|
||||
|
||||
explicit scoped_try_lock(TryMutex& mx)
|
||||
: m_mutex(mx), m_locked(false)
|
||||
{
|
||||
try_lock();
|
||||
}
|
||||
scoped_try_lock(TryMutex& mx, bool initially_locked)
|
||||
: m_mutex(mx), m_locked(false)
|
||||
{
|
||||
if (initially_locked) lock();
|
||||
}
|
||||
~scoped_try_lock()
|
||||
{
|
||||
if (m_locked) unlock();
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
if (m_locked) throw lock_error();
|
||||
lock_ops<TryMutex>::lock(m_mutex);
|
||||
m_locked = true;
|
||||
}
|
||||
bool try_lock()
|
||||
{
|
||||
if (m_locked) throw lock_error();
|
||||
return (m_locked = lock_ops<TryMutex>::trylock(m_mutex));
|
||||
}
|
||||
void unlock()
|
||||
{
|
||||
if (!m_locked) throw lock_error();
|
||||
lock_ops<TryMutex>::unlock(m_mutex);
|
||||
m_locked = false;
|
||||
}
|
||||
|
||||
bool locked() const { return m_locked; }
|
||||
operator const void*() const { return m_locked ? this : 0; }
|
||||
|
||||
private:
|
||||
friend class boost::condition;
|
||||
|
||||
TryMutex& m_mutex;
|
||||
bool m_locked;
|
||||
};
|
||||
|
||||
template <typename TimedMutex>
|
||||
class scoped_timed_lock : private noncopyable
|
||||
{
|
||||
public:
|
||||
typedef TimedMutex mutex_type;
|
||||
|
||||
scoped_timed_lock(TimedMutex& mx, const xtime& xt)
|
||||
: m_mutex(mx), m_locked(false)
|
||||
{
|
||||
timed_lock(xt);
|
||||
}
|
||||
scoped_timed_lock(TimedMutex& mx, bool initially_locked)
|
||||
: m_mutex(mx), m_locked(false)
|
||||
{
|
||||
if (initially_locked) lock();
|
||||
}
|
||||
~scoped_timed_lock()
|
||||
{
|
||||
if (m_locked) unlock();
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
if (m_locked) throw lock_error();
|
||||
lock_ops<TimedMutex>::lock(m_mutex);
|
||||
m_locked = true;
|
||||
}
|
||||
bool try_lock()
|
||||
{
|
||||
if (m_locked) throw lock_error();
|
||||
return (m_locked = lock_ops<TimedMutex>::trylock(m_mutex));
|
||||
}
|
||||
bool timed_lock(const xtime& xt)
|
||||
{
|
||||
if (m_locked) throw lock_error();
|
||||
return (m_locked = lock_ops<TimedMutex>::timedlock(m_mutex, xt));
|
||||
}
|
||||
void unlock()
|
||||
{
|
||||
if (!m_locked) throw lock_error();
|
||||
lock_ops<TimedMutex>::unlock(m_mutex);
|
||||
m_locked = false;
|
||||
}
|
||||
|
||||
bool locked() const { return m_locked; }
|
||||
operator const void*() const { return m_locked ? this : 0; }
|
||||
|
||||
private:
|
||||
friend class boost::condition;
|
||||
|
||||
TimedMutex& m_mutex;
|
||||
bool m_locked;
|
||||
};
|
||||
|
||||
} // namespace thread
|
||||
} // namespace detail
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_XLOCK_WEK070601_HPP
|
||||
|
||||
// Change Log:
|
||||
// 8 Feb 01 WEKEMPF Initial version.
|
||||
// 22 May 01 WEKEMPF Modified to use xtime for time outs.
|
||||
// 30 Jul 01 WEKEMPF Moved lock types into boost::detail::thread. Renamed
|
||||
// some types. Added locked() methods.
|
||||
1106
include/boost/thread/detail/read_write_lock.hpp
Normal file
1106
include/boost/thread/detail/read_write_lock.hpp
Normal file
File diff suppressed because it is too large
Load Diff
59
include/boost/thread/detail/singleton.hpp
Normal file
59
include/boost/thread/detail/singleton.hpp
Normal file
@@ -0,0 +1,59 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// Mac Murrett
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org for most recent version including documentation.
|
||||
|
||||
#ifndef BOOST_SINGLETON_MJM012402_HPP
|
||||
#define BOOST_SINGLETON_MJM012402_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace detail {
|
||||
namespace thread {
|
||||
|
||||
// class singleton has the same goal as all singletons: create one instance of
|
||||
// a class on demand, then dish it out as requested.
|
||||
|
||||
template <class T>
|
||||
class singleton : private T
|
||||
{
|
||||
private:
|
||||
singleton();
|
||||
~singleton();
|
||||
|
||||
public:
|
||||
static T &instance();
|
||||
};
|
||||
|
||||
|
||||
template <class T>
|
||||
inline singleton<T>::singleton()
|
||||
{
|
||||
/* no-op */
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline singleton<T>::~singleton()
|
||||
{
|
||||
/* no-op */
|
||||
}
|
||||
|
||||
template <class T>
|
||||
/*static*/ T &singleton<T>::instance()
|
||||
{
|
||||
// function-local static to force this to work correctly at static
|
||||
// initialization time.
|
||||
static singleton<T> s_oT;
|
||||
return(s_oT);
|
||||
}
|
||||
|
||||
} // namespace thread
|
||||
} // namespace detail
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_SINGLETON_MJM012402_HPP
|
||||
78
include/boost/thread/detail/tss_hooks.hpp
Normal file
78
include/boost/thread/detail/tss_hooks.hpp
Normal file
@@ -0,0 +1,78 @@
|
||||
// (C) Copyright Michael Glassford 2004.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#if !defined(BOOST_TLS_HOOKS_HPP)
|
||||
#define BOOST_TLS_HOOKS_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
|
||||
typedef void (__cdecl *thread_exit_handler)(void);
|
||||
|
||||
extern "C" BOOST_THREAD_DECL int at_thread_exit(
|
||||
thread_exit_handler exit_handler
|
||||
);
|
||||
//Add a function to the list of functions that will
|
||||
//be called when a thread is about to exit.
|
||||
//Currently only implemented for Win32, but should
|
||||
//later be implemented for all platforms.
|
||||
//Used by Win32 implementation of Boost.Threads
|
||||
//tss to perform cleanup.
|
||||
//Like the C runtime library atexit() function,
|
||||
//which it mimics, at_thread_exit() returns
|
||||
//zero if successful and a nonzero
|
||||
//value if an error occurs.
|
||||
|
||||
#endif //defined(BOOST_HAS_WINTHREADS)
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
|
||||
extern "C" BOOST_THREAD_DECL void on_process_enter(void);
|
||||
//Function to be called when the exe or dll
|
||||
//that uses Boost.Threads first starts
|
||||
//or is first loaded.
|
||||
//Should be called only before the first call to
|
||||
//on_thread_enter().
|
||||
//Called automatically by Boost.Threads when
|
||||
//a method for doing so has been discovered.
|
||||
//May be omitted; may be called multiple times.
|
||||
|
||||
extern "C" BOOST_THREAD_DECL void on_process_exit(void);
|
||||
//Function to be called when the exe or dll
|
||||
//that uses Boost.Threads first starts
|
||||
//or is first loaded.
|
||||
//Should be called only after the last call to
|
||||
//on_exit_thread().
|
||||
//Called automatically by Boost.Threads when
|
||||
//a method for doing so has been discovered.
|
||||
//Must not be omitted; may be called multiple times.
|
||||
|
||||
extern "C" BOOST_THREAD_DECL void on_thread_enter(void);
|
||||
//Function to be called just after a thread starts
|
||||
//in an exe or dll that uses Boost.Threads.
|
||||
//Must be called in the context of the thread
|
||||
//that is starting.
|
||||
//Called automatically by Boost.Threads when
|
||||
//a method for doing so has been discovered.
|
||||
//May be omitted; may be called multiple times.
|
||||
|
||||
extern "C" BOOST_THREAD_DECL void on_thread_exit(void);
|
||||
//Function to be called just be fore a thread ends
|
||||
//in an exe or dll that uses Boost.Threads.
|
||||
//Must be called in the context of the thread
|
||||
//that is ending.
|
||||
//Called automatically by Boost.Threads when
|
||||
//a method for doing so has been discovered.
|
||||
//Must not be omitted; may be called multiple times.
|
||||
|
||||
extern "C" void tss_cleanup_implemented(void);
|
||||
//Dummy function used both to detect whether tss cleanup
|
||||
//cleanup has been implemented and to force
|
||||
//it to be linked into the Boost.Threads library.
|
||||
|
||||
#endif //defined(BOOST_HAS_WINTHREADS)
|
||||
|
||||
#endif //!defined(BOOST_TLS_HOOKS_HPP)
|
||||
94
include/boost/thread/exceptions.hpp
Normal file
94
include/boost/thread/exceptions.hpp
Normal file
@@ -0,0 +1,94 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_THREAD_EXCEPTIONS_PDM070801_H
|
||||
#define BOOST_THREAD_EXCEPTIONS_PDM070801_H
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
// pdm: Sorry, but this class is used all over the place & I end up
|
||||
// with recursive headers if I don't separate it
|
||||
// wek: Not sure why recursive headers would cause compilation problems
|
||||
// given the include guards, but regardless it makes sense to
|
||||
// seperate this out any way.
|
||||
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace boost {
|
||||
|
||||
class BOOST_THREAD_DECL thread_exception : public std::exception
|
||||
{
|
||||
protected:
|
||||
thread_exception();
|
||||
thread_exception(int sys_err_code);
|
||||
|
||||
public:
|
||||
~thread_exception() throw();
|
||||
|
||||
int native_error() const;
|
||||
|
||||
private:
|
||||
int m_sys_err;
|
||||
};
|
||||
|
||||
class BOOST_THREAD_DECL lock_error : public thread_exception
|
||||
{
|
||||
public:
|
||||
lock_error();
|
||||
lock_error(int sys_err_code);
|
||||
~lock_error() throw();
|
||||
|
||||
virtual const char* what() const throw();
|
||||
};
|
||||
|
||||
class BOOST_THREAD_DECL thread_resource_error : public thread_exception
|
||||
{
|
||||
public:
|
||||
thread_resource_error();
|
||||
thread_resource_error(int sys_err_code);
|
||||
~thread_resource_error() throw();
|
||||
|
||||
virtual const char* what() const throw();
|
||||
};
|
||||
|
||||
class BOOST_THREAD_DECL unsupported_thread_option : public thread_exception
|
||||
{
|
||||
public:
|
||||
unsupported_thread_option();
|
||||
unsupported_thread_option(int sys_err_code);
|
||||
~unsupported_thread_option() throw();
|
||||
|
||||
virtual const char* what() const throw();
|
||||
};
|
||||
|
||||
class BOOST_THREAD_DECL invalid_thread_argument : public thread_exception
|
||||
{
|
||||
public:
|
||||
invalid_thread_argument();
|
||||
invalid_thread_argument(int sys_err_code);
|
||||
~invalid_thread_argument() throw();
|
||||
|
||||
virtual const char* what() const throw();
|
||||
};
|
||||
|
||||
class BOOST_THREAD_DECL thread_permission_error : public thread_exception
|
||||
{
|
||||
public:
|
||||
thread_permission_error();
|
||||
thread_permission_error(int sys_err_code);
|
||||
~thread_permission_error() throw();
|
||||
|
||||
virtual const char* what() const throw();
|
||||
};
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_THREAD_CONFIG_PDM070801_H
|
||||
|
||||
// Change log:
|
||||
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
|
||||
|
||||
170
include/boost/thread/mutex.hpp
Normal file
170
include/boost/thread/mutex.hpp
Normal file
@@ -0,0 +1,170 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_MUTEX_WEK070601_HPP
|
||||
#define BOOST_MUTEX_WEK070601_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/thread/detail/lock.hpp>
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
# include <pthread.h>
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_HAS_MPTASKS)
|
||||
# include "scoped_critical_region.hpp"
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
struct xtime;
|
||||
// disable warnings about non dll import
|
||||
// see: http://www.boost.org/more/separate_compilation.html#dlls
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4251 4231 4660 4275)
|
||||
#endif
|
||||
|
||||
class BOOST_THREAD_DECL mutex
|
||||
: private noncopyable
|
||||
{
|
||||
public:
|
||||
friend class detail::thread::lock_ops<mutex>;
|
||||
|
||||
typedef detail::thread::scoped_lock<mutex> scoped_lock;
|
||||
|
||||
mutex();
|
||||
~mutex();
|
||||
|
||||
private:
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
typedef void* cv_state;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
struct cv_state
|
||||
{
|
||||
pthread_mutex_t* pmutex;
|
||||
};
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
struct cv_state
|
||||
{
|
||||
};
|
||||
#endif
|
||||
void do_lock();
|
||||
void do_unlock();
|
||||
void do_lock(cv_state& state);
|
||||
void do_unlock(cv_state& state);
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
void* m_mutex;
|
||||
bool m_critical_section;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
pthread_mutex_t m_mutex;
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
threads::mac::detail::scoped_critical_region m_mutex;
|
||||
threads::mac::detail::scoped_critical_region m_mutex_mutex;
|
||||
#endif
|
||||
};
|
||||
|
||||
class BOOST_THREAD_DECL try_mutex
|
||||
: private noncopyable
|
||||
{
|
||||
public:
|
||||
friend class detail::thread::lock_ops<try_mutex>;
|
||||
|
||||
typedef detail::thread::scoped_lock<try_mutex> scoped_lock;
|
||||
typedef detail::thread::scoped_try_lock<try_mutex> scoped_try_lock;
|
||||
|
||||
try_mutex();
|
||||
~try_mutex();
|
||||
|
||||
private:
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
typedef void* cv_state;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
struct cv_state
|
||||
{
|
||||
pthread_mutex_t* pmutex;
|
||||
};
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
struct cv_state
|
||||
{
|
||||
};
|
||||
#endif
|
||||
void do_lock();
|
||||
bool do_trylock();
|
||||
void do_unlock();
|
||||
void do_lock(cv_state& state);
|
||||
void do_unlock(cv_state& state);
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
void* m_mutex;
|
||||
bool m_critical_section;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
pthread_mutex_t m_mutex;
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
threads::mac::detail::scoped_critical_region m_mutex;
|
||||
threads::mac::detail::scoped_critical_region m_mutex_mutex;
|
||||
#endif
|
||||
};
|
||||
|
||||
class BOOST_THREAD_DECL timed_mutex
|
||||
: private noncopyable
|
||||
{
|
||||
public:
|
||||
friend class detail::thread::lock_ops<timed_mutex>;
|
||||
|
||||
typedef detail::thread::scoped_lock<timed_mutex> scoped_lock;
|
||||
typedef detail::thread::scoped_try_lock<timed_mutex> scoped_try_lock;
|
||||
typedef detail::thread::scoped_timed_lock<timed_mutex> scoped_timed_lock;
|
||||
|
||||
timed_mutex();
|
||||
~timed_mutex();
|
||||
|
||||
private:
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
typedef void* cv_state;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
struct cv_state
|
||||
{
|
||||
pthread_mutex_t* pmutex;
|
||||
};
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
struct cv_state
|
||||
{
|
||||
};
|
||||
#endif
|
||||
void do_lock();
|
||||
bool do_trylock();
|
||||
bool do_timedlock(const xtime& xt);
|
||||
void do_unlock();
|
||||
void do_lock(cv_state& state);
|
||||
void do_unlock(cv_state& state);
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
void* m_mutex;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
pthread_mutex_t m_mutex;
|
||||
pthread_cond_t m_condition;
|
||||
bool m_locked;
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
threads::mac::detail::scoped_critical_region m_mutex;
|
||||
threads::mac::detail::scoped_critical_region m_mutex_mutex;
|
||||
#endif
|
||||
};
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
} // namespace boost
|
||||
|
||||
// Change Log:
|
||||
// 8 Feb 01 WEKEMPF Initial version.
|
||||
// 22 May 01 WEKEMPF Modified to use xtime for time outs. Factored out
|
||||
// to three classes, mutex, try_mutex and timed_mutex.
|
||||
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
|
||||
|
||||
#endif // BOOST_MUTEX_WEK070601_HPP
|
||||
37
include/boost/thread/once.hpp
Normal file
37
include/boost/thread/once.hpp
Normal file
@@ -0,0 +1,37 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_ONCE_WEK080101_HPP
|
||||
#define BOOST_ONCE_WEK080101_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
# include <pthread.h>
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
|
||||
typedef pthread_once_t once_flag;
|
||||
#define BOOST_ONCE_INIT PTHREAD_ONCE_INIT
|
||||
|
||||
#elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||
|
||||
typedef long once_flag;
|
||||
#define BOOST_ONCE_INIT 0
|
||||
|
||||
#endif
|
||||
|
||||
void BOOST_THREAD_DECL call_once(void (*func)(), once_flag& flag);
|
||||
|
||||
} // namespace boost
|
||||
|
||||
// Change Log:
|
||||
// 1 Aug 01 WEKEMPF Initial version.
|
||||
|
||||
#endif // BOOST_ONCE_WEK080101_HPP
|
||||
287
include/boost/thread/read_write_mutex.hpp
Normal file
287
include/boost/thread/read_write_mutex.hpp
Normal file
@@ -0,0 +1,287 @@
|
||||
// Copyright (C) 2002-2003
|
||||
// David Moore, William E. Kempf, Michael Glassford
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// A Boost::threads implementation of a synchronization
|
||||
// primitive which can allow multiple readers or a single
|
||||
// writer to have access to a shared resource.
|
||||
|
||||
#ifndef BOOST_READ_WRITE_MUTEX_JDM030602_HPP
|
||||
#define BOOST_READ_WRITE_MUTEX_JDM030602_HPP
|
||||
|
||||
#error Read Write Mutex is broken, do not include this header
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/detail/workaround.hpp>
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/detail/lock.hpp>
|
||||
#include <boost/thread/detail/read_write_lock.hpp>
|
||||
#include <boost/thread/condition.hpp>
|
||||
|
||||
namespace boost {
|
||||
// disable warnings about non dll import
|
||||
// see: http://www.boost.org/more/separate_compilation.html#dlls
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4251 4231 4660 4275)
|
||||
#endif
|
||||
namespace read_write_scheduling_policy {
|
||||
enum read_write_scheduling_policy_enum
|
||||
{
|
||||
writer_priority, //Prefer writers; can starve readers
|
||||
reader_priority, //Prefer readers; can starve writers
|
||||
alternating_many_reads, //Alternate readers and writers; before a writer, release all queued readers
|
||||
alternating_single_read //Alternate readers and writers; before a writer, release only one queued reader
|
||||
};
|
||||
} // namespace read_write_scheduling_policy
|
||||
|
||||
namespace detail {
|
||||
|
||||
namespace thread {
|
||||
|
||||
// Shared implementation construct for explicit Scheduling Policies
|
||||
// This implementation is susceptible to self-deadlock, though....
|
||||
template<typename Mutex>
|
||||
struct read_write_mutex_impl
|
||||
{
|
||||
typedef Mutex mutex_type;
|
||||
typedef detail::thread::scoped_lock<Mutex> scoped_lock;
|
||||
typedef detail::thread::scoped_try_lock<Mutex> scoped_try_lock;
|
||||
typedef detail::thread::scoped_timed_lock<Mutex> scoped_timed_lock;
|
||||
|
||||
read_write_mutex_impl(read_write_scheduling_policy::read_write_scheduling_policy_enum sp);
|
||||
#if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(582))
|
||||
~read_write_mutex_impl();
|
||||
#endif
|
||||
|
||||
Mutex m_prot;
|
||||
|
||||
const read_write_scheduling_policy::read_write_scheduling_policy_enum m_sp;
|
||||
int m_state; //-1 = write lock; 0 = unlocked; >0 = read locked
|
||||
|
||||
boost::condition m_waiting_writers;
|
||||
boost::condition m_waiting_readers;
|
||||
boost::condition m_waiting_promotion;
|
||||
int m_num_waiting_writers;
|
||||
int m_num_waiting_readers;
|
||||
bool m_state_waiting_promotion;
|
||||
|
||||
int m_num_waking_writers;
|
||||
int m_num_waking_readers;
|
||||
int m_num_max_waking_writers; //Debug only
|
||||
int m_num_max_waking_readers; //Debug only
|
||||
|
||||
bool m_readers_next;
|
||||
|
||||
void do_read_lock();
|
||||
void do_write_lock();
|
||||
void do_write_unlock();
|
||||
void do_read_unlock();
|
||||
bool do_try_write_lock();
|
||||
bool do_try_read_lock();
|
||||
bool do_timed_write_lock(const xtime &xt);
|
||||
bool do_timed_read_lock(const xtime &xt);
|
||||
|
||||
void do_demote_to_read_lock();
|
||||
bool do_try_demote_to_read_lock();
|
||||
bool do_timed_demote_to_read_lock(const xtime &xt);
|
||||
|
||||
void do_promote_to_write_lock();
|
||||
bool do_try_promote_to_write_lock();
|
||||
bool do_timed_promote_to_write_lock(const xtime &xt);
|
||||
|
||||
bool locked();
|
||||
read_write_lock_state::read_write_lock_state_enum state();
|
||||
|
||||
private:
|
||||
|
||||
bool do_demote_to_read_lock_impl();
|
||||
|
||||
enum scheduling_reason
|
||||
{
|
||||
scheduling_reason_unlock,
|
||||
scheduling_reason_timeout,
|
||||
scheduling_reason_demote
|
||||
};
|
||||
|
||||
void do_scheduling_impl(const scheduling_reason reason);
|
||||
bool do_wake_one_reader(void);
|
||||
bool do_wake_all_readers(void);
|
||||
bool do_wake_writer(void);
|
||||
bool waker_exists(void);
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace thread
|
||||
|
||||
class BOOST_THREAD_DECL read_write_mutex : private noncopyable
|
||||
{
|
||||
public:
|
||||
|
||||
read_write_mutex(read_write_scheduling_policy::read_write_scheduling_policy_enum sp);
|
||||
~read_write_mutex();
|
||||
|
||||
read_write_scheduling_policy::read_write_scheduling_policy_enum policy() const { return m_impl.m_sp; }
|
||||
|
||||
friend class detail::thread::read_write_lock_ops<read_write_mutex>;
|
||||
|
||||
typedef detail::thread::scoped_read_write_lock<
|
||||
read_write_mutex> scoped_read_write_lock;
|
||||
|
||||
typedef detail::thread::scoped_read_lock<
|
||||
read_write_mutex> scoped_read_lock;
|
||||
|
||||
typedef detail::thread::scoped_write_lock<
|
||||
read_write_mutex> scoped_write_lock;
|
||||
|
||||
private:
|
||||
|
||||
// Operations that will eventually be done only
|
||||
// via lock types
|
||||
void do_write_lock();
|
||||
void do_read_lock();
|
||||
void do_write_unlock();
|
||||
void do_read_unlock();
|
||||
|
||||
void do_demote_to_read_lock();
|
||||
|
||||
void do_promote_to_write_lock();
|
||||
|
||||
bool locked();
|
||||
read_write_lock_state::read_write_lock_state_enum state();
|
||||
|
||||
detail::thread::read_write_mutex_impl<mutex> m_impl;
|
||||
};
|
||||
|
||||
class BOOST_THREAD_DECL try_read_write_mutex : private noncopyable
|
||||
{
|
||||
public:
|
||||
|
||||
try_read_write_mutex(read_write_scheduling_policy::read_write_scheduling_policy_enum sp);
|
||||
~try_read_write_mutex();
|
||||
|
||||
read_write_scheduling_policy::read_write_scheduling_policy_enum policy() const { return m_impl.m_sp; }
|
||||
|
||||
friend class detail::thread::read_write_lock_ops<try_read_write_mutex>;
|
||||
|
||||
typedef detail::thread::scoped_read_write_lock<
|
||||
try_read_write_mutex> scoped_read_write_lock;
|
||||
typedef detail::thread::scoped_try_read_write_lock<
|
||||
try_read_write_mutex> scoped_try_read_write_lock;
|
||||
|
||||
typedef detail::thread::scoped_read_lock<
|
||||
try_read_write_mutex> scoped_read_lock;
|
||||
typedef detail::thread::scoped_try_read_lock<
|
||||
try_read_write_mutex> scoped_try_read_lock;
|
||||
|
||||
typedef detail::thread::scoped_write_lock<
|
||||
try_read_write_mutex> scoped_write_lock;
|
||||
typedef detail::thread::scoped_try_write_lock<
|
||||
try_read_write_mutex> scoped_try_write_lock;
|
||||
|
||||
private:
|
||||
|
||||
// Operations that will eventually be done only
|
||||
// via lock types
|
||||
void do_write_lock();
|
||||
void do_read_lock();
|
||||
void do_write_unlock();
|
||||
void do_read_unlock();
|
||||
bool do_try_write_lock();
|
||||
bool do_try_read_lock();
|
||||
|
||||
|
||||
void do_demote_to_read_lock();
|
||||
bool do_try_demote_to_read_lock();
|
||||
|
||||
void do_promote_to_write_lock();
|
||||
bool do_try_promote_to_write_lock();
|
||||
|
||||
bool locked();
|
||||
read_write_lock_state::read_write_lock_state_enum state();
|
||||
|
||||
detail::thread::read_write_mutex_impl<try_mutex> m_impl;
|
||||
};
|
||||
|
||||
class BOOST_THREAD_DECL timed_read_write_mutex : private noncopyable
|
||||
{
|
||||
public:
|
||||
|
||||
timed_read_write_mutex(read_write_scheduling_policy::read_write_scheduling_policy_enum sp);
|
||||
~timed_read_write_mutex();
|
||||
|
||||
read_write_scheduling_policy::read_write_scheduling_policy_enum policy() const { return m_impl.m_sp; }
|
||||
|
||||
friend class detail::thread::read_write_lock_ops<timed_read_write_mutex>;
|
||||
|
||||
typedef detail::thread::scoped_read_write_lock<
|
||||
timed_read_write_mutex> scoped_read_write_lock;
|
||||
typedef detail::thread::scoped_try_read_write_lock<
|
||||
timed_read_write_mutex> scoped_try_read_write_lock;
|
||||
typedef detail::thread::scoped_timed_read_write_lock<
|
||||
timed_read_write_mutex> scoped_timed_read_write_lock;
|
||||
|
||||
typedef detail::thread::scoped_read_lock<
|
||||
timed_read_write_mutex> scoped_read_lock;
|
||||
typedef detail::thread::scoped_try_read_lock<
|
||||
timed_read_write_mutex> scoped_try_read_lock;
|
||||
typedef detail::thread::scoped_timed_read_lock<
|
||||
timed_read_write_mutex> scoped_timed_read_lock;
|
||||
|
||||
typedef detail::thread::scoped_write_lock<
|
||||
timed_read_write_mutex> scoped_write_lock;
|
||||
typedef detail::thread::scoped_try_write_lock<
|
||||
timed_read_write_mutex> scoped_try_write_lock;
|
||||
typedef detail::thread::scoped_timed_write_lock<
|
||||
timed_read_write_mutex> scoped_timed_write_lock;
|
||||
|
||||
private:
|
||||
|
||||
// Operations that will eventually be done only
|
||||
// via lock types
|
||||
void do_write_lock();
|
||||
void do_read_lock();
|
||||
void do_write_unlock();
|
||||
void do_read_unlock();
|
||||
bool do_try_write_lock();
|
||||
bool do_try_read_lock();
|
||||
bool do_timed_write_lock(const xtime &xt);
|
||||
bool do_timed_read_lock(const xtime &xt);
|
||||
|
||||
void do_demote_to_read_lock();
|
||||
bool do_try_demote_to_read_lock();
|
||||
bool do_timed_demote_to_read_lock(const xtime &xt);
|
||||
|
||||
void do_promote_to_write_lock();
|
||||
bool do_try_promote_to_write_lock();
|
||||
bool do_timed_promote_to_write_lock(const xtime &xt);
|
||||
|
||||
bool locked();
|
||||
read_write_lock_state::read_write_lock_state_enum state();
|
||||
|
||||
detail::thread::read_write_mutex_impl<timed_mutex> m_impl;
|
||||
};
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
|
||||
// Change Log:
|
||||
// 10 Mar 02
|
||||
// Original version.
|
||||
// 4 May 04 GlassfordM
|
||||
// Implement lock promotion and demotion.
|
||||
// Add locked() and state() member functions for debugging
|
||||
// (should these be made public?).
|
||||
// Rename to improve consistency and eliminate abbreviations:
|
||||
// Use "read" and "write" instead of "shared" and "exclusive".
|
||||
// Change "rd" to "read", "wr" to "write", "rw" to "read_write".
|
||||
// Add mutex_type typdef.
|
||||
184
include/boost/thread/recursive_mutex.hpp
Normal file
184
include/boost/thread/recursive_mutex.hpp
Normal file
@@ -0,0 +1,184 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_RECURSIVE_MUTEX_WEK070601_HPP
|
||||
#define BOOST_RECURSIVE_MUTEX_WEK070601_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/thread/detail/lock.hpp>
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
# include <pthread.h>
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_HAS_MPTASKS)
|
||||
# include "scoped_critical_region.hpp"
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
struct xtime;
|
||||
// disable warnings about non dll import
|
||||
// see: http://www.boost.org/more/separate_compilation.html#dlls
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4251 4231 4660 4275)
|
||||
#endif
|
||||
class BOOST_THREAD_DECL recursive_mutex
|
||||
: private noncopyable
|
||||
{
|
||||
public:
|
||||
friend class detail::thread::lock_ops<recursive_mutex>;
|
||||
|
||||
typedef detail::thread::scoped_lock<recursive_mutex> scoped_lock;
|
||||
|
||||
recursive_mutex();
|
||||
~recursive_mutex();
|
||||
|
||||
private:
|
||||
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||
typedef std::size_t cv_state;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
struct cv_state
|
||||
{
|
||||
long count;
|
||||
pthread_mutex_t* pmutex;
|
||||
};
|
||||
#endif
|
||||
void do_lock();
|
||||
void do_unlock();
|
||||
void do_lock(cv_state& state);
|
||||
void do_unlock(cv_state& state);
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
void* m_mutex;
|
||||
bool m_critical_section;
|
||||
unsigned long m_count;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
pthread_mutex_t m_mutex;
|
||||
unsigned m_count;
|
||||
# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
|
||||
pthread_cond_t m_unlocked;
|
||||
pthread_t m_thread_id;
|
||||
bool m_valid_id;
|
||||
# endif
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
threads::mac::detail::scoped_critical_region m_mutex;
|
||||
threads::mac::detail::scoped_critical_region m_mutex_mutex;
|
||||
std::size_t m_count;
|
||||
#endif
|
||||
};
|
||||
|
||||
class BOOST_THREAD_DECL recursive_try_mutex
|
||||
: private noncopyable
|
||||
{
|
||||
public:
|
||||
friend class detail::thread::lock_ops<recursive_try_mutex>;
|
||||
|
||||
typedef detail::thread::scoped_lock<recursive_try_mutex> scoped_lock;
|
||||
typedef detail::thread::scoped_try_lock<
|
||||
recursive_try_mutex> scoped_try_lock;
|
||||
|
||||
recursive_try_mutex();
|
||||
~recursive_try_mutex();
|
||||
|
||||
private:
|
||||
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||
typedef std::size_t cv_state;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
struct cv_state
|
||||
{
|
||||
long count;
|
||||
pthread_mutex_t* pmutex;
|
||||
};
|
||||
#endif
|
||||
void do_lock();
|
||||
bool do_trylock();
|
||||
void do_unlock();
|
||||
void do_lock(cv_state& state);
|
||||
void do_unlock(cv_state& state);
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
void* m_mutex;
|
||||
bool m_critical_section;
|
||||
unsigned long m_count;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
pthread_mutex_t m_mutex;
|
||||
unsigned m_count;
|
||||
# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
|
||||
pthread_cond_t m_unlocked;
|
||||
pthread_t m_thread_id;
|
||||
bool m_valid_id;
|
||||
# endif
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
threads::mac::detail::scoped_critical_region m_mutex;
|
||||
threads::mac::detail::scoped_critical_region m_mutex_mutex;
|
||||
std::size_t m_count;
|
||||
#endif
|
||||
};
|
||||
|
||||
class BOOST_THREAD_DECL recursive_timed_mutex
|
||||
: private noncopyable
|
||||
{
|
||||
public:
|
||||
friend class detail::thread::lock_ops<recursive_timed_mutex>;
|
||||
|
||||
typedef detail::thread::scoped_lock<recursive_timed_mutex> scoped_lock;
|
||||
typedef detail::thread::scoped_try_lock<
|
||||
recursive_timed_mutex> scoped_try_lock;
|
||||
typedef detail::thread::scoped_timed_lock<
|
||||
recursive_timed_mutex> scoped_timed_lock;
|
||||
|
||||
recursive_timed_mutex();
|
||||
~recursive_timed_mutex();
|
||||
|
||||
private:
|
||||
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||
typedef std::size_t cv_state;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
struct cv_state
|
||||
{
|
||||
long count;
|
||||
pthread_mutex_t* pmutex;
|
||||
};
|
||||
#endif
|
||||
void do_lock();
|
||||
bool do_trylock();
|
||||
bool do_timedlock(const xtime& xt);
|
||||
void do_unlock();
|
||||
void do_lock(cv_state& state);
|
||||
void do_unlock(cv_state& state);
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
void* m_mutex;
|
||||
unsigned long m_count;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
pthread_mutex_t m_mutex;
|
||||
pthread_cond_t m_unlocked;
|
||||
pthread_t m_thread_id;
|
||||
bool m_valid_id;
|
||||
unsigned m_count;
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
threads::mac::detail::scoped_critical_region m_mutex;
|
||||
threads::mac::detail::scoped_critical_region m_mutex_mutex;
|
||||
std::size_t m_count;
|
||||
#endif
|
||||
};
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_RECURSIVE_MUTEX_WEK070601_HPP
|
||||
|
||||
// Change Log:
|
||||
// 8 Feb 01 WEKEMPF Initial version.
|
||||
// 1 Jun 01 WEKEMPF Modified to use xtime for time outs. Factored out
|
||||
// to three classes, mutex, try_mutex and timed_mutex.
|
||||
// 11 Jun 01 WEKEMPF Modified to use PTHREAD_MUTEX_RECURSIVE if available.
|
||||
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
|
||||
89
include/boost/thread/thread.hpp
Normal file
89
include/boost/thread/thread.hpp
Normal file
@@ -0,0 +1,89 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_THREAD_WEK070601_HPP
|
||||
#define BOOST_THREAD_WEK070601_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
# include <pthread.h>
|
||||
# include <boost/thread/condition.hpp>
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
# include <Multiprocessing.h>
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
struct xtime;
|
||||
// disable warnings about non dll import
|
||||
// see: http://www.boost.org/more/separate_compilation.html#dlls
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4251 4231 4660 4275)
|
||||
#endif
|
||||
class BOOST_THREAD_DECL thread : private noncopyable
|
||||
{
|
||||
public:
|
||||
thread();
|
||||
explicit thread(const function0<void>& threadfunc);
|
||||
~thread();
|
||||
|
||||
bool operator==(const thread& other) const;
|
||||
bool operator!=(const thread& other) const;
|
||||
|
||||
void join();
|
||||
|
||||
static void sleep(const xtime& xt);
|
||||
static void yield();
|
||||
|
||||
private:
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
void* m_thread;
|
||||
unsigned int m_id;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
private:
|
||||
pthread_t m_thread;
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
MPQueueID m_pJoinQueueID;
|
||||
MPTaskID m_pTaskID;
|
||||
#endif
|
||||
bool m_joinable;
|
||||
};
|
||||
|
||||
class BOOST_THREAD_DECL thread_group : private noncopyable
|
||||
{
|
||||
public:
|
||||
thread_group();
|
||||
~thread_group();
|
||||
|
||||
thread* create_thread(const function0<void>& threadfunc);
|
||||
void add_thread(thread* thrd);
|
||||
void remove_thread(thread* thrd);
|
||||
void join_all();
|
||||
int size();
|
||||
|
||||
private:
|
||||
std::list<thread*> m_threads;
|
||||
mutex m_mutex;
|
||||
};
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
} // namespace boost
|
||||
|
||||
// Change Log:
|
||||
// 8 Feb 01 WEKEMPF Initial version.
|
||||
// 1 Jun 01 WEKEMPF Added boost::thread initial implementation.
|
||||
// 3 Jul 01 WEKEMPF Redesigned boost::thread to be noncopyable.
|
||||
|
||||
#endif // BOOST_THREAD_WEK070601_HPP
|
||||
128
include/boost/thread/tss.hpp
Normal file
128
include/boost/thread/tss.hpp
Normal file
@@ -0,0 +1,128 @@
|
||||
// Copyright (C) 2001-2003 William E. Kempf
|
||||
// Copyright (C) 2006 Roland Schwarz
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_TSS_WEK070601_HPP
|
||||
#define BOOST_TSS_WEK070601_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
# include <pthread.h>
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
# include <Multiprocessing.h>
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
// disable warnings about non dll import
|
||||
// see: http://www.boost.org/more/separate_compilation.html#dlls
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4251 4231 4660 4275)
|
||||
#endif
|
||||
|
||||
namespace detail {
|
||||
|
||||
class BOOST_THREAD_DECL tss : private noncopyable
|
||||
{
|
||||
public:
|
||||
tss(boost::function1<void, void*>* pcleanup) {
|
||||
if (pcleanup == 0) throw boost::thread_resource_error();
|
||||
try
|
||||
{
|
||||
init(pcleanup);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
delete pcleanup;
|
||||
throw boost::thread_resource_error();
|
||||
}
|
||||
}
|
||||
|
||||
~tss();
|
||||
void* get() const;
|
||||
void set(void* value);
|
||||
void cleanup(void* p);
|
||||
|
||||
private:
|
||||
unsigned int m_slot; //This is a "pseudo-slot", not a native slot
|
||||
|
||||
void init(boost::function1<void, void*>* pcleanup);
|
||||
};
|
||||
|
||||
#if defined(BOOST_HAS_MPTASKS)
|
||||
void thread_cleanup();
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
struct tss_adapter
|
||||
{
|
||||
template <typename F>
|
||||
tss_adapter(const F& cleanup) : m_cleanup(cleanup) { }
|
||||
void operator()(void* p) { m_cleanup(static_cast<T*>(p)); }
|
||||
boost::function1<void, T*> m_cleanup;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename T>
|
||||
class thread_specific_ptr : private noncopyable
|
||||
{
|
||||
public:
|
||||
thread_specific_ptr()
|
||||
: m_tss(new boost::function1<void, void*>(
|
||||
boost::detail::tss_adapter<T>(
|
||||
&thread_specific_ptr<T>::cleanup)))
|
||||
{
|
||||
}
|
||||
thread_specific_ptr(void (*clean)(T*))
|
||||
: m_tss(new boost::function1<void, void*>(
|
||||
boost::detail::tss_adapter<T>(clean)))
|
||||
{
|
||||
}
|
||||
~thread_specific_ptr() { reset(); }
|
||||
|
||||
T* get() const { return static_cast<T*>(m_tss.get()); }
|
||||
T* operator->() const { return get(); }
|
||||
T& operator*() const { return *get(); }
|
||||
T* release() { T* temp = get(); if (temp) m_tss.set(0); return temp; }
|
||||
void reset(T* p=0)
|
||||
{
|
||||
T* cur = get();
|
||||
if (cur == p) return;
|
||||
m_tss.set(p);
|
||||
if (cur) m_tss.cleanup(cur);
|
||||
}
|
||||
|
||||
private:
|
||||
static void cleanup(T* p) { delete p; }
|
||||
detail::tss m_tss;
|
||||
};
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif //BOOST_TSS_WEK070601_HPP
|
||||
|
||||
// Change Log:
|
||||
// 6 Jun 01
|
||||
// WEKEMPF Initial version.
|
||||
// 30 May 02 WEKEMPF
|
||||
// Added interface to set specific cleanup handlers.
|
||||
// Removed TLS slot limits from most implementations.
|
||||
// 22 Mar 04 GlassfordM for WEKEMPF
|
||||
// Fixed: thread_specific_ptr::reset() doesn't check error returned
|
||||
// by tss::set(); tss::set() now throws if it fails.
|
||||
// Fixed: calling thread_specific_ptr::reset() or
|
||||
// thread_specific_ptr::release() causes double-delete: once on
|
||||
// reset()/release() and once on ~thread_specific_ptr().
|
||||
54
include/boost/thread/xtime.hpp
Normal file
54
include/boost/thread/xtime.hpp
Normal file
@@ -0,0 +1,54 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_XTIME_WEK070601_HPP
|
||||
#define BOOST_XTIME_WEK070601_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/cstdint.hpp>
|
||||
|
||||
namespace boost {
|
||||
|
||||
enum xtime_clock_types
|
||||
{
|
||||
TIME_UTC=1
|
||||
// TIME_TAI,
|
||||
// TIME_MONOTONIC,
|
||||
// TIME_PROCESS,
|
||||
// TIME_THREAD,
|
||||
// TIME_LOCAL,
|
||||
// TIME_SYNC,
|
||||
// TIME_RESOLUTION
|
||||
};
|
||||
|
||||
struct xtime
|
||||
{
|
||||
#if defined(BOOST_NO_INT64_T)
|
||||
typedef int_fast32_t xtime_sec_t; //INT_FAST32_MIN <= sec <= INT_FAST32_MAX
|
||||
#else
|
||||
typedef int_fast64_t xtime_sec_t; //INT_FAST64_MIN <= sec <= INT_FAST64_MAX
|
||||
#endif
|
||||
|
||||
typedef int_fast32_t xtime_nsec_t; //0 <= xtime.nsec < NANOSECONDS_PER_SECOND
|
||||
|
||||
xtime_sec_t sec;
|
||||
xtime_nsec_t nsec;
|
||||
};
|
||||
|
||||
int BOOST_THREAD_DECL xtime_get(struct xtime* xtp, int clock_type);
|
||||
|
||||
inline int xtime_cmp(const xtime& xt1, const xtime& xt2)
|
||||
{
|
||||
if (xt1.sec == xt2.sec)
|
||||
return (int)(xt1.nsec - xt2.nsec);
|
||||
else
|
||||
return (xt1.sec > xt2.sec) ? 1 : -1;
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif //BOOST_XTIME_WEK070601_HPP
|
||||
13
index.html
Normal file
13
index.html
Normal file
@@ -0,0 +1,13 @@
|
||||
<!-- Copyright (c) 2002-2003 William E. Kempf.
|
||||
Subject to the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
|
||||
-->
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="refresh" content="0; URL=doc/index.html">
|
||||
</head>
|
||||
<body>
|
||||
Automatic redirection failed, please go to <a href="doc/index.html">doc/index.html</a>
|
||||
</body>
|
||||
</html>
|
||||
42
src/barrier.cpp
Normal file
42
src/barrier.cpp
Normal file
@@ -0,0 +1,42 @@
|
||||
// Copyright (C) 2002-2003
|
||||
// David Moore, William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/barrier.hpp>
|
||||
#include <string> // see http://article.gmane.org/gmane.comp.lib.boost.devel/106981
|
||||
|
||||
namespace boost {
|
||||
|
||||
barrier::barrier(unsigned int count)
|
||||
: m_threshold(count), m_count(count), m_generation(0)
|
||||
{
|
||||
if (count == 0)
|
||||
throw std::invalid_argument("count cannot be zero.");
|
||||
}
|
||||
|
||||
barrier::~barrier()
|
||||
{
|
||||
}
|
||||
|
||||
bool barrier::wait()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(m_mutex);
|
||||
unsigned int gen = m_generation;
|
||||
|
||||
if (--m_count == 0)
|
||||
{
|
||||
m_generation++;
|
||||
m_count = m_threshold;
|
||||
m_cond.notify_all();
|
||||
return true;
|
||||
}
|
||||
|
||||
while (gen == m_generation)
|
||||
m_cond.wait(lock);
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
692
src/condition.cpp
Normal file
692
src/condition.cpp
Normal file
@@ -0,0 +1,692 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/thread/condition.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/limits.hpp>
|
||||
#include <cassert>
|
||||
#include "timeconv.inl"
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
# ifndef NOMINMAX
|
||||
# define NOMINMAX
|
||||
# endif
|
||||
# include <windows.h>
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
# include <errno.h>
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
# include <MacErrors.h>
|
||||
# include "mac/init.hpp"
|
||||
# include "mac/safe.hpp"
|
||||
#endif
|
||||
|
||||
// The following include can be removed after the bug on QNX
|
||||
// has been tracked down. I need this only for debugging
|
||||
//#if !defined(NDEBUG) && defined(BOOST_HAS_PTHREADS)
|
||||
#include <iostream>
|
||||
//#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace detail {
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
condition_impl::condition_impl()
|
||||
: m_gone(0), m_blocked(0), m_waiting(0)
|
||||
{
|
||||
m_gate = reinterpret_cast<void*>(CreateSemaphore(0, 1, 1, 0));
|
||||
m_queue = reinterpret_cast<void*>(
|
||||
CreateSemaphore(0, 0, (std::numeric_limits<long>::max)(), 0));
|
||||
m_mutex = reinterpret_cast<void*>(CreateMutex(0, 0, 0));
|
||||
|
||||
if (!m_gate || !m_queue || !m_mutex)
|
||||
{
|
||||
int res = 0;
|
||||
if (m_gate)
|
||||
{
|
||||
res = CloseHandle(reinterpret_cast<HANDLE>(m_gate));
|
||||
assert(res);
|
||||
}
|
||||
if (m_queue)
|
||||
{
|
||||
res = CloseHandle(reinterpret_cast<HANDLE>(m_queue));
|
||||
assert(res);
|
||||
}
|
||||
if (m_mutex)
|
||||
{
|
||||
res = CloseHandle(reinterpret_cast<HANDLE>(m_mutex));
|
||||
assert(res);
|
||||
}
|
||||
|
||||
throw thread_resource_error();
|
||||
}
|
||||
}
|
||||
|
||||
condition_impl::~condition_impl()
|
||||
{
|
||||
int res = 0;
|
||||
res = CloseHandle(reinterpret_cast<HANDLE>(m_gate));
|
||||
assert(res);
|
||||
res = CloseHandle(reinterpret_cast<HANDLE>(m_queue));
|
||||
assert(res);
|
||||
res = CloseHandle(reinterpret_cast<HANDLE>(m_mutex));
|
||||
assert(res);
|
||||
}
|
||||
|
||||
void condition_impl::notify_one()
|
||||
{
|
||||
unsigned signals = 0;
|
||||
|
||||
int res = 0;
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
|
||||
if (m_waiting != 0) // the m_gate is already closed
|
||||
{
|
||||
if (m_blocked == 0)
|
||||
{
|
||||
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||
assert(res);
|
||||
return;
|
||||
}
|
||||
|
||||
++m_waiting;
|
||||
--m_blocked;
|
||||
signals = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
if (m_blocked > m_gone)
|
||||
{
|
||||
if (m_gone != 0)
|
||||
{
|
||||
m_blocked -= m_gone;
|
||||
m_gone = 0;
|
||||
}
|
||||
signals = m_waiting = 1;
|
||||
--m_blocked;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||
assert(res);
|
||||
}
|
||||
}
|
||||
|
||||
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||
assert(res);
|
||||
|
||||
if (signals)
|
||||
{
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_queue), signals, 0);
|
||||
assert(res);
|
||||
}
|
||||
}
|
||||
|
||||
void condition_impl::notify_all()
|
||||
{
|
||||
unsigned signals = 0;
|
||||
|
||||
int res = 0;
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
|
||||
if (m_waiting != 0) // the m_gate is already closed
|
||||
{
|
||||
if (m_blocked == 0)
|
||||
{
|
||||
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||
assert(res);
|
||||
return;
|
||||
}
|
||||
|
||||
m_waiting += (signals = m_blocked);
|
||||
m_blocked = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
if (m_blocked > m_gone)
|
||||
{
|
||||
if (m_gone != 0)
|
||||
{
|
||||
m_blocked -= m_gone;
|
||||
m_gone = 0;
|
||||
}
|
||||
signals = m_waiting = m_blocked;
|
||||
m_blocked = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||
assert(res);
|
||||
}
|
||||
}
|
||||
|
||||
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||
assert(res);
|
||||
|
||||
if (signals)
|
||||
{
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_queue), signals, 0);
|
||||
assert(res);
|
||||
}
|
||||
}
|
||||
|
||||
void condition_impl::enter_wait()
|
||||
{
|
||||
int res = 0;
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
++m_blocked;
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||
assert(res);
|
||||
}
|
||||
|
||||
void condition_impl::do_wait()
|
||||
{
|
||||
int res = 0;
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue), INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
|
||||
unsigned was_waiting=0;
|
||||
unsigned was_gone=0;
|
||||
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
was_waiting = m_waiting;
|
||||
was_gone = m_gone;
|
||||
if (was_waiting != 0)
|
||||
{
|
||||
if (--m_waiting == 0)
|
||||
{
|
||||
if (m_blocked != 0)
|
||||
{
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1,
|
||||
0); // open m_gate
|
||||
assert(res);
|
||||
was_waiting = 0;
|
||||
}
|
||||
else if (m_gone != 0)
|
||||
m_gone = 0;
|
||||
}
|
||||
}
|
||||
else if (++m_gone == ((std::numeric_limits<unsigned>::max)() / 2))
|
||||
{
|
||||
// timeout occured, normalize the m_gone count
|
||||
// this may occur if many calls to wait with a timeout are made and
|
||||
// no call to notify_* is made
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
m_blocked -= m_gone;
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||
assert(res);
|
||||
m_gone = 0;
|
||||
}
|
||||
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||
assert(res);
|
||||
|
||||
if (was_waiting == 1)
|
||||
{
|
||||
for (/**/ ; was_gone; --was_gone)
|
||||
{
|
||||
// better now than spurious later
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue),
|
||||
INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
}
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||
assert(res);
|
||||
}
|
||||
}
|
||||
|
||||
bool condition_impl::do_timed_wait(const xtime& xt)
|
||||
{
|
||||
bool ret = false;
|
||||
unsigned int res = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
int milliseconds;
|
||||
to_duration(xt, milliseconds);
|
||||
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue),
|
||||
milliseconds);
|
||||
assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
|
||||
ret = (res == WAIT_OBJECT_0);
|
||||
|
||||
if (res == WAIT_TIMEOUT)
|
||||
{
|
||||
xtime cur;
|
||||
xtime_get(&cur, TIME_UTC);
|
||||
if (xtime_cmp(xt, cur) > 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
unsigned was_waiting=0;
|
||||
unsigned was_gone=0;
|
||||
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
was_waiting = m_waiting;
|
||||
was_gone = m_gone;
|
||||
if (was_waiting != 0)
|
||||
{
|
||||
if (!ret) // timeout
|
||||
{
|
||||
if (m_blocked != 0)
|
||||
--m_blocked;
|
||||
else
|
||||
++m_gone; // count spurious wakeups
|
||||
}
|
||||
if (--m_waiting == 0)
|
||||
{
|
||||
if (m_blocked != 0)
|
||||
{
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1,
|
||||
0); // open m_gate
|
||||
assert(res);
|
||||
was_waiting = 0;
|
||||
}
|
||||
else if (m_gone != 0)
|
||||
m_gone = 0;
|
||||
}
|
||||
}
|
||||
else if (++m_gone == ((std::numeric_limits<unsigned>::max)() / 2))
|
||||
{
|
||||
// timeout occured, normalize the m_gone count
|
||||
// this may occur if many calls to wait with a timeout are made and
|
||||
// no call to notify_* is made
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
m_blocked -= m_gone;
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||
assert(res);
|
||||
m_gone = 0;
|
||||
}
|
||||
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||
assert(res);
|
||||
|
||||
if (was_waiting == 1)
|
||||
{
|
||||
for (/**/ ; was_gone; --was_gone)
|
||||
{
|
||||
// better now than spurious later
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue),
|
||||
INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
}
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||
assert(res);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
condition_impl::condition_impl()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_cond_init(&m_condition, 0);
|
||||
if (res != 0)
|
||||
throw thread_resource_error();
|
||||
}
|
||||
|
||||
condition_impl::~condition_impl()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_cond_destroy(&m_condition);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
void condition_impl::notify_one()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_cond_signal(&m_condition);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
void condition_impl::notify_all()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_cond_broadcast(&m_condition);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
void condition_impl::do_wait(pthread_mutex_t* pmutex)
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_cond_wait(&m_condition, pmutex);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
bool condition_impl::do_timed_wait(const xtime& xt, pthread_mutex_t* pmutex)
|
||||
{
|
||||
timespec ts;
|
||||
to_timespec(xt, ts);
|
||||
|
||||
int res = 0;
|
||||
res = pthread_cond_timedwait(&m_condition, pmutex, &ts);
|
||||
// Test code for QNX debugging, to get information during regressions
|
||||
#ifndef NDEBUG
|
||||
if (res == EINVAL) {
|
||||
boost::xtime now;
|
||||
boost::xtime_get(&now, boost::TIME_UTC);
|
||||
std::cerr << "now: " << now.sec << " " << now.nsec << std::endl;
|
||||
std::cerr << "time: " << time(0) << std::endl;
|
||||
std::cerr << "xtime: " << xt.sec << " " << xt.nsec << std::endl;
|
||||
std::cerr << "ts: " << ts.tv_sec << " " << ts.tv_nsec << std::endl;
|
||||
std::cerr << "pmutex: " << pmutex << std::endl;
|
||||
std::cerr << "condition: " << &m_condition << std::endl;
|
||||
assert(res != EINVAL);
|
||||
}
|
||||
#endif
|
||||
assert(res == 0 || res == ETIMEDOUT);
|
||||
|
||||
return res != ETIMEDOUT;
|
||||
}
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
|
||||
using threads::mac::detail::safe_enter_critical_region;
|
||||
using threads::mac::detail::safe_wait_on_semaphore;
|
||||
|
||||
condition_impl::condition_impl()
|
||||
: m_gone(0), m_blocked(0), m_waiting(0)
|
||||
{
|
||||
threads::mac::detail::thread_init();
|
||||
|
||||
OSStatus lStatus = noErr;
|
||||
|
||||
lStatus = MPCreateSemaphore(1, 1, &m_gate);
|
||||
if(lStatus == noErr)
|
||||
lStatus = MPCreateSemaphore(ULONG_MAX, 0, &m_queue);
|
||||
|
||||
if(lStatus != noErr || !m_gate || !m_queue)
|
||||
{
|
||||
if (m_gate)
|
||||
{
|
||||
lStatus = MPDeleteSemaphore(m_gate);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
if (m_queue)
|
||||
{
|
||||
lStatus = MPDeleteSemaphore(m_queue);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
throw thread_resource_error();
|
||||
}
|
||||
}
|
||||
|
||||
condition_impl::~condition_impl()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = MPDeleteSemaphore(m_gate);
|
||||
assert(lStatus == noErr);
|
||||
lStatus = MPDeleteSemaphore(m_queue);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
void condition_impl::notify_one()
|
||||
{
|
||||
unsigned signals = 0;
|
||||
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||
m_mutex_mutex);
|
||||
assert(lStatus == noErr);
|
||||
|
||||
if (m_waiting != 0) // the m_gate is already closed
|
||||
{
|
||||
if (m_blocked == 0)
|
||||
{
|
||||
lStatus = MPExitCriticalRegion(m_mutex);
|
||||
assert(lStatus == noErr);
|
||||
return;
|
||||
}
|
||||
|
||||
++m_waiting;
|
||||
--m_blocked;
|
||||
}
|
||||
else
|
||||
{
|
||||
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
|
||||
assert(lStatus == noErr);
|
||||
if (m_blocked > m_gone)
|
||||
{
|
||||
if (m_gone != 0)
|
||||
{
|
||||
m_blocked -= m_gone;
|
||||
m_gone = 0;
|
||||
}
|
||||
signals = m_waiting = 1;
|
||||
--m_blocked;
|
||||
}
|
||||
else
|
||||
{
|
||||
lStatus = MPSignalSemaphore(m_gate);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
lStatus = MPExitCriticalRegion(m_mutex);
|
||||
assert(lStatus == noErr);
|
||||
|
||||
while (signals)
|
||||
{
|
||||
lStatus = MPSignalSemaphore(m_queue);
|
||||
assert(lStatus == noErr);
|
||||
--signals;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void condition_impl::notify_all()
|
||||
{
|
||||
unsigned signals = 0;
|
||||
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||
m_mutex_mutex);
|
||||
assert(lStatus == noErr);
|
||||
|
||||
if (m_waiting != 0) // the m_gate is already closed
|
||||
{
|
||||
if (m_blocked == 0)
|
||||
{
|
||||
lStatus = MPExitCriticalRegion(m_mutex);
|
||||
assert(lStatus == noErr);
|
||||
return;
|
||||
}
|
||||
|
||||
m_waiting += (signals = m_blocked);
|
||||
m_blocked = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
|
||||
assert(lStatus == noErr);
|
||||
if (m_blocked > m_gone)
|
||||
{
|
||||
if (m_gone != 0)
|
||||
{
|
||||
m_blocked -= m_gone;
|
||||
m_gone = 0;
|
||||
}
|
||||
signals = m_waiting = m_blocked;
|
||||
m_blocked = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
lStatus = MPSignalSemaphore(m_gate);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
lStatus = MPExitCriticalRegion(m_mutex);
|
||||
assert(lStatus == noErr);
|
||||
|
||||
while (signals)
|
||||
{
|
||||
lStatus = MPSignalSemaphore(m_queue);
|
||||
assert(lStatus == noErr);
|
||||
--signals;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void condition_impl::enter_wait()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
|
||||
assert(lStatus == noErr);
|
||||
++m_blocked;
|
||||
lStatus = MPSignalSemaphore(m_gate);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
void condition_impl::do_wait()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = safe_wait_on_semaphore(m_queue, kDurationForever);
|
||||
assert(lStatus == noErr);
|
||||
|
||||
unsigned was_waiting=0;
|
||||
unsigned was_gone=0;
|
||||
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||
m_mutex_mutex);
|
||||
assert(lStatus == noErr);
|
||||
was_waiting = m_waiting;
|
||||
was_gone = m_gone;
|
||||
if (was_waiting != 0)
|
||||
{
|
||||
if (--m_waiting == 0)
|
||||
{
|
||||
if (m_blocked != 0)
|
||||
{
|
||||
lStatus = MPSignalSemaphore(m_gate); // open m_gate
|
||||
assert(lStatus == noErr);
|
||||
was_waiting = 0;
|
||||
}
|
||||
else if (m_gone != 0)
|
||||
m_gone = 0;
|
||||
}
|
||||
}
|
||||
else if (++m_gone == ((std::numeric_limits<unsigned>::max)() / 2))
|
||||
{
|
||||
// timeout occured, normalize the m_gone count
|
||||
// this may occur if many calls to wait with a timeout are made and
|
||||
// no call to notify_* is made
|
||||
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
|
||||
assert(lStatus == noErr);
|
||||
m_blocked -= m_gone;
|
||||
lStatus = MPSignalSemaphore(m_gate);
|
||||
assert(lStatus == noErr);
|
||||
m_gone = 0;
|
||||
}
|
||||
lStatus = MPExitCriticalRegion(m_mutex);
|
||||
assert(lStatus == noErr);
|
||||
|
||||
if (was_waiting == 1)
|
||||
{
|
||||
for (/**/ ; was_gone; --was_gone)
|
||||
{
|
||||
// better now than spurious later
|
||||
lStatus = safe_wait_on_semaphore(m_queue, kDurationForever);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
lStatus = MPSignalSemaphore(m_gate);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
}
|
||||
|
||||
bool condition_impl::do_timed_wait(const xtime& xt)
|
||||
{
|
||||
int milliseconds;
|
||||
to_duration(xt, milliseconds);
|
||||
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = safe_wait_on_semaphore(m_queue, milliseconds);
|
||||
assert(lStatus == noErr || lStatus == kMPTimeoutErr);
|
||||
|
||||
bool ret = (lStatus == noErr);
|
||||
|
||||
unsigned was_waiting=0;
|
||||
unsigned was_gone=0;
|
||||
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||
m_mutex_mutex);
|
||||
assert(lStatus == noErr);
|
||||
was_waiting = m_waiting;
|
||||
was_gone = m_gone;
|
||||
if (was_waiting != 0)
|
||||
{
|
||||
if (!ret) // timeout
|
||||
{
|
||||
if (m_blocked != 0)
|
||||
--m_blocked;
|
||||
else
|
||||
++m_gone; // count spurious wakeups
|
||||
}
|
||||
if (--m_waiting == 0)
|
||||
{
|
||||
if (m_blocked != 0)
|
||||
{
|
||||
lStatus = MPSignalSemaphore(m_gate); // open m_gate
|
||||
assert(lStatus == noErr);
|
||||
was_waiting = 0;
|
||||
}
|
||||
else if (m_gone != 0)
|
||||
m_gone = 0;
|
||||
}
|
||||
}
|
||||
else if (++m_gone == ((std::numeric_limits<unsigned>::max)() / 2))
|
||||
{
|
||||
// timeout occured, normalize the m_gone count
|
||||
// this may occur if many calls to wait with a timeout are made and
|
||||
// no call to notify_* is made
|
||||
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
|
||||
assert(lStatus == noErr);
|
||||
m_blocked -= m_gone;
|
||||
lStatus = MPSignalSemaphore(m_gate);
|
||||
assert(lStatus == noErr);
|
||||
m_gone = 0;
|
||||
}
|
||||
lStatus = MPExitCriticalRegion(m_mutex);
|
||||
assert(lStatus == noErr);
|
||||
|
||||
if (was_waiting == 1)
|
||||
{
|
||||
for (/**/ ; was_gone; --was_gone)
|
||||
{
|
||||
// better now than spurious later
|
||||
lStatus = safe_wait_on_semaphore(m_queue, kDurationForever);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
lStatus = MPSignalSemaphore(m_gate);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace boost
|
||||
|
||||
// Change Log:
|
||||
// 8 Feb 01 WEKEMPF Initial version.
|
||||
// 22 May 01 WEKEMPF Modified to use xtime for time outs.
|
||||
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
|
||||
124
src/exceptions.cpp
Normal file
124
src/exceptions.cpp
Normal file
@@ -0,0 +1,124 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
namespace boost {
|
||||
|
||||
thread_exception::thread_exception()
|
||||
: m_sys_err(0)
|
||||
{
|
||||
}
|
||||
|
||||
thread_exception::thread_exception(int sys_err_code)
|
||||
: m_sys_err(sys_err_code)
|
||||
{
|
||||
}
|
||||
|
||||
thread_exception::~thread_exception() throw()
|
||||
{
|
||||
}
|
||||
|
||||
int thread_exception::native_error() const
|
||||
{
|
||||
return m_sys_err;
|
||||
}
|
||||
|
||||
lock_error::lock_error()
|
||||
{
|
||||
}
|
||||
|
||||
lock_error::lock_error(int sys_err_code)
|
||||
: thread_exception(sys_err_code)
|
||||
{
|
||||
}
|
||||
|
||||
lock_error::~lock_error() throw()
|
||||
{
|
||||
}
|
||||
|
||||
const char* lock_error::what() const throw()
|
||||
{
|
||||
return "boost::lock_error";
|
||||
}
|
||||
|
||||
thread_resource_error::thread_resource_error()
|
||||
{
|
||||
}
|
||||
|
||||
thread_resource_error::thread_resource_error(int sys_err_code)
|
||||
: thread_exception(sys_err_code)
|
||||
{
|
||||
}
|
||||
|
||||
thread_resource_error::~thread_resource_error() throw()
|
||||
{
|
||||
}
|
||||
|
||||
const char* thread_resource_error::what() const throw()
|
||||
{
|
||||
return "boost::thread_resource_error";
|
||||
}
|
||||
|
||||
unsupported_thread_option::unsupported_thread_option()
|
||||
{
|
||||
}
|
||||
|
||||
unsupported_thread_option::unsupported_thread_option(int sys_err_code)
|
||||
: thread_exception(sys_err_code)
|
||||
{
|
||||
}
|
||||
|
||||
unsupported_thread_option::~unsupported_thread_option() throw()
|
||||
{
|
||||
}
|
||||
|
||||
const char* unsupported_thread_option::what() const throw()
|
||||
{
|
||||
return "boost::unsupported_thread_option";
|
||||
}
|
||||
|
||||
invalid_thread_argument::invalid_thread_argument()
|
||||
{
|
||||
}
|
||||
|
||||
invalid_thread_argument::invalid_thread_argument(int sys_err_code)
|
||||
: thread_exception(sys_err_code)
|
||||
{
|
||||
}
|
||||
|
||||
invalid_thread_argument::~invalid_thread_argument() throw()
|
||||
{
|
||||
}
|
||||
|
||||
const char* invalid_thread_argument::what() const throw()
|
||||
{
|
||||
return "boost::invalid_thread_argument";
|
||||
}
|
||||
|
||||
thread_permission_error::thread_permission_error()
|
||||
{
|
||||
}
|
||||
|
||||
thread_permission_error::thread_permission_error(int sys_err_code)
|
||||
: thread_exception(sys_err_code)
|
||||
{
|
||||
}
|
||||
|
||||
thread_permission_error::~thread_permission_error() throw()
|
||||
{
|
||||
}
|
||||
|
||||
const char* thread_permission_error::what() const throw()
|
||||
{
|
||||
return "boost::thread_permission_error";
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
8
src/mac/debug_prefix.hpp
Normal file
8
src/mac/debug_prefix.hpp
Normal file
@@ -0,0 +1,8 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#define TARGET_CARBON 1
|
||||
66
src/mac/delivery_man.cpp
Normal file
66
src/mac/delivery_man.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#include "delivery_man.hpp"
|
||||
|
||||
#include "os.hpp"
|
||||
#include "execution_context.hpp"
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
delivery_man::delivery_man():
|
||||
m_pPackage(NULL),
|
||||
m_pSemaphore(kInvalidID),
|
||||
m_bPackageWaiting(false)
|
||||
{
|
||||
assert(at_st());
|
||||
|
||||
OSStatus lStatus = MPCreateSemaphore(1UL, 0UL, &m_pSemaphore);
|
||||
// TODO - throw on error here
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
delivery_man::~delivery_man()
|
||||
{
|
||||
assert(m_bPackageWaiting == false);
|
||||
|
||||
OSStatus lStatus = MPDeleteSemaphore(m_pSemaphore);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
|
||||
void delivery_man::accept_deliveries()
|
||||
{
|
||||
if(m_bPackageWaiting)
|
||||
{
|
||||
assert(m_pPackage != NULL);
|
||||
m_pPackage->accept();
|
||||
m_pPackage = NULL;
|
||||
m_bPackageWaiting = false;
|
||||
|
||||
// signal to the thread making the call that we're done
|
||||
OSStatus lStatus = MPSignalSemaphore(m_pSemaphore);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
84
src/mac/delivery_man.hpp
Normal file
84
src/mac/delivery_man.hpp
Normal file
@@ -0,0 +1,84 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#ifndef BOOST_DELIVERY_MAN_MJM012402_HPP
|
||||
#define BOOST_DELIVERY_MAN_MJM012402_HPP
|
||||
|
||||
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/utility.hpp>
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
|
||||
#include "package.hpp"
|
||||
|
||||
#include <Multiprocessing.h>
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
// class delivery_man is intended to move boost::function objects from MP tasks to
|
||||
// other execution contexts (such as deferred task time or system task time).
|
||||
|
||||
class delivery_man: private noncopyable
|
||||
{
|
||||
public:
|
||||
delivery_man();
|
||||
~delivery_man();
|
||||
|
||||
public:
|
||||
template<class R>
|
||||
R deliver(function<R> &rFunctor);
|
||||
|
||||
void accept_deliveries();
|
||||
|
||||
private:
|
||||
base_package *m_pPackage;
|
||||
mutex m_oMutex;
|
||||
MPSemaphoreID m_pSemaphore;
|
||||
bool m_bPackageWaiting;
|
||||
};
|
||||
|
||||
|
||||
template<class R>
|
||||
R delivery_man::deliver(function<R> &rFunctor)
|
||||
{
|
||||
assert(at_mp());
|
||||
|
||||
// lock our mutex
|
||||
mutex::scoped_lock oLock(m_oMutex);
|
||||
|
||||
// create a package and save it
|
||||
package<R> oPackage(rFunctor);
|
||||
m_pPackage = &oPackage;
|
||||
m_bPackageWaiting = true;
|
||||
|
||||
// wait on the semaphore
|
||||
OSStatus lStatus = MPWaitOnSemaphore(m_pSemaphore, kDurationForever);
|
||||
assert(lStatus == noErr);
|
||||
|
||||
return(oPackage.return_value());
|
||||
}
|
||||
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_DELIVERY_MAN_MJM012402_HPP
|
||||
93
src/mac/dt_scheduler.cpp
Normal file
93
src/mac/dt_scheduler.cpp
Normal file
@@ -0,0 +1,93 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#include "dt_scheduler.hpp"
|
||||
|
||||
#include "ot_context.hpp"
|
||||
|
||||
|
||||
#include <boost/thread/detail/singleton.hpp>
|
||||
|
||||
#include <OpenTransportProtocol.h>
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
const OTTimeout k_ulTimerTaskDelay = 1UL;
|
||||
|
||||
|
||||
dt_scheduler::dt_scheduler():
|
||||
m_bReschedule(false),
|
||||
m_uppTask(NULL),
|
||||
m_lTask(0UL)
|
||||
{
|
||||
using ::boost::detail::thread::singleton;
|
||||
|
||||
ot_context &rContext(singleton<ot_context>::instance());
|
||||
|
||||
m_uppTask = NewOTProcessUPP(task_entry);
|
||||
m_lTask = OTCreateTimerTaskInContext(m_uppTask, this, rContext.get_context());
|
||||
}
|
||||
|
||||
dt_scheduler::~dt_scheduler()
|
||||
{
|
||||
OTDestroyTimerTask(m_lTask);
|
||||
m_lTask = 0UL;
|
||||
DisposeOTProcessUPP(m_uppTask);
|
||||
m_uppTask = NULL;
|
||||
}
|
||||
|
||||
|
||||
void dt_scheduler::start_polling()
|
||||
{
|
||||
m_bReschedule = true;
|
||||
schedule_task();
|
||||
}
|
||||
|
||||
void dt_scheduler::stop_polling()
|
||||
{
|
||||
m_bReschedule = false;
|
||||
}
|
||||
|
||||
|
||||
void dt_scheduler::schedule_task()
|
||||
{
|
||||
if(m_bReschedule)
|
||||
{
|
||||
OTScheduleTimerTask(m_lTask, k_ulTimerTaskDelay);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*static*/ pascal void dt_scheduler::task_entry(void *pRefCon)
|
||||
{
|
||||
dt_scheduler *pThis = reinterpret_cast<dt_scheduler *>(pRefCon);
|
||||
assert(pThis != NULL);
|
||||
pThis->task();
|
||||
}
|
||||
|
||||
void dt_scheduler::task()
|
||||
{
|
||||
periodic_function();
|
||||
schedule_task();
|
||||
}
|
||||
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
63
src/mac/dt_scheduler.hpp
Normal file
63
src/mac/dt_scheduler.hpp
Normal file
@@ -0,0 +1,63 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#ifndef BOOST_DT_SCHEDULER_MJM012402_HPP
|
||||
#define BOOST_DT_SCHEDULER_MJM012402_HPP
|
||||
|
||||
|
||||
#include "periodical.hpp"
|
||||
|
||||
#include <OpenTransport.h>
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
// class dt_scheduler calls its pure-virtual periodic_function method periodically at
|
||||
// deferred task time. This is generally 1kHz under Mac OS 9.
|
||||
|
||||
class dt_scheduler
|
||||
{
|
||||
public:
|
||||
dt_scheduler();
|
||||
virtual ~dt_scheduler();
|
||||
|
||||
protected:
|
||||
void start_polling();
|
||||
void stop_polling();
|
||||
|
||||
private:
|
||||
virtual void periodic_function() = 0;
|
||||
|
||||
private:
|
||||
void schedule_task();
|
||||
static pascal void task_entry(void *pRefCon);
|
||||
void task();
|
||||
|
||||
private:
|
||||
bool m_bReschedule;
|
||||
OTProcessUPP m_uppTask;
|
||||
long m_lTask;
|
||||
};
|
||||
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_DT_SCHEDULER_MJM012402_HPP
|
||||
60
src/mac/execution_context.cpp
Normal file
60
src/mac/execution_context.cpp
Normal file
@@ -0,0 +1,60 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#include <Debugging.h>
|
||||
#include <Multiprocessing.h>
|
||||
|
||||
#include "execution_context.hpp"
|
||||
#include "init.hpp"
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
|
||||
execution_context_t execution_context()
|
||||
{
|
||||
// make sure that MP services are available the first time through
|
||||
static bool bIgnored = detail::thread_init();
|
||||
|
||||
// first check if we're an MP task
|
||||
if(MPTaskIsPreemptive(kInvalidID))
|
||||
{
|
||||
return(k_eExecutionContextMPTask);
|
||||
}
|
||||
|
||||
#if TARGET_CARBON
|
||||
// Carbon has TaskLevel
|
||||
UInt32 ulLevel = TaskLevel();
|
||||
|
||||
if(ulLevel == 0UL)
|
||||
{
|
||||
return(k_eExecutionContextSystemTask);
|
||||
}
|
||||
|
||||
if(ulLevel & kInDeferredTaskMask)
|
||||
{
|
||||
return(k_eExecutionContextDeferredTask);
|
||||
}
|
||||
|
||||
return(k_eExecutionContextOther);
|
||||
#else
|
||||
// this can be implemented using TaskLevel if you don't mind linking against
|
||||
// DebugLib (and therefore breaking Mac OS 8.6 support), or CurrentExecutionLevel.
|
||||
# error execution_context unimplimented
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
47
src/mac/execution_context.hpp
Normal file
47
src/mac/execution_context.hpp
Normal file
@@ -0,0 +1,47 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#ifndef BOOST_EXECUTION_CONTEXT_MJM012402_HPP
|
||||
#define BOOST_EXECUTION_CONTEXT_MJM012402_HPP
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
|
||||
// utility functions for figuring out what context your code is executing in.
|
||||
// Bear in mind that at_mp and in_blue are the only functions guarenteed by
|
||||
// Apple to work. There is simply no way of being sure that you will not get
|
||||
// false readings about task level at interrupt time in blue.
|
||||
|
||||
typedef enum {
|
||||
k_eExecutionContextSystemTask,
|
||||
k_eExecutionContextDeferredTask,
|
||||
k_eExecutionContextMPTask,
|
||||
k_eExecutionContextOther
|
||||
} execution_context_t;
|
||||
|
||||
execution_context_t execution_context();
|
||||
|
||||
inline bool at_st()
|
||||
{ return(execution_context() == k_eExecutionContextSystemTask); }
|
||||
|
||||
inline bool at_mp()
|
||||
{ return(execution_context() == k_eExecutionContextMPTask); }
|
||||
inline bool in_blue()
|
||||
{ return(!at_mp()); }
|
||||
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_EXECUTION_CONTEXT_MJM012402_HPP
|
||||
58
src/mac/init.cpp
Normal file
58
src/mac/init.cpp
Normal file
@@ -0,0 +1,58 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#include "init.hpp"
|
||||
|
||||
#include "remote_call_manager.hpp"
|
||||
|
||||
|
||||
#include <boost/thread/detail/singleton.hpp>
|
||||
|
||||
#include <Multiprocessing.h>
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
// force these to get called by the end of static initialization time.
|
||||
static bool g_bInitialized = (thread_init() && create_singletons());
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool thread_init()
|
||||
{
|
||||
static bool bResult = MPLibraryIsLoaded();
|
||||
|
||||
return(bResult);
|
||||
}
|
||||
|
||||
bool create_singletons()
|
||||
{
|
||||
using ::boost::detail::thread::singleton;
|
||||
|
||||
singleton<remote_call_manager>::instance();
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
34
src/mac/init.hpp
Normal file
34
src/mac/init.hpp
Normal file
@@ -0,0 +1,34 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#ifndef BOOST_INIT_MJM012402_HPP
|
||||
#define BOOST_INIT_MJM012402_HPP
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
bool thread_init();
|
||||
bool create_singletons();
|
||||
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_INIT_MJM012402_HPP
|
||||
24
src/mac/msl_replacements/assert.cpp
Normal file
24
src/mac/msl_replacements/assert.cpp
Normal file
@@ -0,0 +1,24 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
|
||||
#include <MacTypes.h>
|
||||
|
||||
#include "remote_calls.hpp"
|
||||
|
||||
// this function will be called when an assertion fails. We redirect the assertion
|
||||
// to DebugStr (MacsBug under Mac OS 1.x-9.x, Console under Mac OS X).
|
||||
void __assertion_failed(char const *pszAssertion, char const *pszFile, int nLine)
|
||||
{
|
||||
using std::snprintf;
|
||||
unsigned char strlDebug[sizeof(Str255) + 1];
|
||||
char *pszDebug = reinterpret_cast<char *>(&strlDebug[1]);
|
||||
strlDebug[0] = snprintf(pszDebug, sizeof(Str255), "assertion failed: \"%s\", %s, line %d", pszAssertion, pszFile, nLine);
|
||||
boost::threads::mac::dt_remote_call(DebugStr, static_cast<ConstStringPtr>(strlDebug));
|
||||
}
|
||||
128
src/mac/msl_replacements/console_io.cpp
Normal file
128
src/mac/msl_replacements/console_io.cpp
Normal file
@@ -0,0 +1,128 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
//
|
||||
// includes
|
||||
//
|
||||
|
||||
#include <abort_exit.h>
|
||||
#include <console.h>
|
||||
#include <console_io.h>
|
||||
#include <misc_io.h>
|
||||
#include <SIOUX.h>
|
||||
|
||||
#include "remote_calls.hpp"
|
||||
|
||||
|
||||
//
|
||||
// using declarations
|
||||
//
|
||||
|
||||
using std::__file_handle;
|
||||
using std::__idle_proc;
|
||||
using std::__io_error;
|
||||
using std::__no_io_error;
|
||||
using std::size_t;
|
||||
|
||||
using boost::threads::mac::st_remote_call;
|
||||
|
||||
|
||||
//
|
||||
// prototypes
|
||||
//
|
||||
|
||||
static bool check_console();
|
||||
static int do_read_console(__file_handle ulHandle, unsigned char *pBuffer, size_t *pCount, __idle_proc pfnIdleProc);
|
||||
static int do_write_console(__file_handle ulHandle, unsigned char *pBuffer, size_t *pCount, __idle_proc pfnIdleProc);
|
||||
|
||||
|
||||
//
|
||||
// MSL function replacements
|
||||
//
|
||||
|
||||
// these two functions are called by cin and cout, respectively, as well as by (all?)
|
||||
// other functions in MSL that do console I/O. All that they do is as the remote
|
||||
// call manager to ensure that their guts are called at system task time.
|
||||
int __read_console(__file_handle handle, unsigned char * buffer, size_t * count, __idle_proc idle_proc)
|
||||
{
|
||||
return(st_remote_call(do_read_console, handle, buffer, count, idle_proc));
|
||||
}
|
||||
|
||||
int __write_console(__file_handle handle, unsigned char * buffer, size_t * count, __idle_proc idle_proc)
|
||||
{
|
||||
return(st_remote_call(do_write_console, handle, buffer, count, idle_proc));
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// implementations
|
||||
//
|
||||
|
||||
static bool check_console()
|
||||
{
|
||||
static bool s_bHaveConsole(false);
|
||||
static bool s_bWontHaveConsole(false);
|
||||
|
||||
if(s_bHaveConsole)
|
||||
{
|
||||
return(true);
|
||||
}
|
||||
|
||||
if(s_bWontHaveConsole == false)
|
||||
{
|
||||
__stdio_atexit();
|
||||
|
||||
if(InstallConsole(0) != 0)
|
||||
{
|
||||
s_bWontHaveConsole = true;
|
||||
return(false);
|
||||
}
|
||||
__console_exit = RemoveConsole;
|
||||
s_bHaveConsole = true;
|
||||
return(true);
|
||||
}
|
||||
|
||||
return(false);
|
||||
}
|
||||
|
||||
|
||||
int do_read_console(__file_handle /*ulHandle*/, unsigned char *pBuffer, size_t *pCount, __idle_proc /*pfnIdleProc*/)
|
||||
{
|
||||
assert(pCount != NULL);
|
||||
assert(pBuffer != NULL || *pCount == 0UL);
|
||||
|
||||
if(check_console() == false)
|
||||
{
|
||||
return(__io_error);
|
||||
}
|
||||
std::fflush(stdout);
|
||||
long lCount = ReadCharsFromConsole(reinterpret_cast<char *>(pBuffer), static_cast<long>(*pCount));
|
||||
*pCount = static_cast<size_t>(lCount);
|
||||
if(lCount == -1L)
|
||||
{
|
||||
return(__io_error);
|
||||
}
|
||||
|
||||
return(__no_io_error);
|
||||
}
|
||||
|
||||
int do_write_console(__file_handle /*ulHandle*/, unsigned char *pBuffer, size_t *pCount, __idle_proc /*pfnIdleProc*/)
|
||||
{
|
||||
if(check_console() == false)
|
||||
{
|
||||
return(__io_error);
|
||||
}
|
||||
|
||||
long lCount = WriteCharsToConsole(reinterpret_cast<char *>(pBuffer), static_cast<long>(*pCount));
|
||||
*pCount = static_cast<size_t>(lCount);
|
||||
if(lCount == -1L)
|
||||
{
|
||||
return(__io_error);
|
||||
}
|
||||
|
||||
return(__no_io_error);
|
||||
}
|
||||
52
src/mac/msl_replacements/malloc.cpp
Normal file
52
src/mac/msl_replacements/malloc.cpp
Normal file
@@ -0,0 +1,52 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
//
|
||||
// includes
|
||||
//
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include <Multiprocessing.h>
|
||||
|
||||
|
||||
//
|
||||
// using declarations
|
||||
//
|
||||
|
||||
using std::size_t;
|
||||
|
||||
|
||||
extern "C" {
|
||||
|
||||
//
|
||||
// prototypes
|
||||
//
|
||||
|
||||
void *malloc(size_t ulSize);
|
||||
void free(void *pBlock);
|
||||
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// MSL function replacements
|
||||
//
|
||||
|
||||
// all allocation/deallocation currently goes through MPAllocateAligned/MPFree. This
|
||||
// solution is sub-optimal at best, but will have to do for now.
|
||||
void *malloc(size_t ulSize)
|
||||
{
|
||||
static bool bIgnored = MPLibraryIsLoaded();
|
||||
return(MPAllocateAligned(ulSize, kMPAllocateDefaultAligned, 0UL));
|
||||
}
|
||||
|
||||
void free(void *pBlock)
|
||||
{
|
||||
if(pBlock == NULL) return;
|
||||
MPFree(pBlock);
|
||||
}
|
||||
99
src/mac/msl_replacements/news_and_deletes.cpp
Normal file
99
src/mac/msl_replacements/news_and_deletes.cpp
Normal file
@@ -0,0 +1,99 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
//
|
||||
// includes
|
||||
//
|
||||
|
||||
#include <new>
|
||||
|
||||
#include <Multiprocessing.h>
|
||||
|
||||
|
||||
//
|
||||
// using declarations
|
||||
//
|
||||
|
||||
using std::size_t;
|
||||
using std::bad_alloc;
|
||||
using std::nothrow_t;
|
||||
using std::nothrow;
|
||||
|
||||
|
||||
//
|
||||
// local utility functions
|
||||
//
|
||||
|
||||
// all allocation/deallocation currently goes through MPAllocateAligned/MPFree. This
|
||||
// solution is sub-optimal at best, but will have to do for now.
|
||||
inline static void *allocate(size_t ulSize, const nothrow_t &)
|
||||
{
|
||||
static bool bIgnored = MPLibraryIsLoaded();
|
||||
return(MPAllocateAligned(ulSize, kMPAllocateDefaultAligned, 0UL));
|
||||
}
|
||||
|
||||
inline static void *allocate(size_t ulSize)
|
||||
{
|
||||
void *pBlock = allocate(ulSize, nothrow);
|
||||
if(pBlock == NULL)
|
||||
throw(bad_alloc());
|
||||
return(pBlock);
|
||||
}
|
||||
|
||||
inline static void deallocate(void *pBlock)
|
||||
{
|
||||
if(pBlock == NULL) return;
|
||||
MPFree(pBlock);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// global operators
|
||||
//
|
||||
|
||||
void *operator new(size_t ulSize)
|
||||
{
|
||||
return(allocate(ulSize));
|
||||
}
|
||||
|
||||
void *operator new[](size_t ulSize)
|
||||
{
|
||||
return(allocate(ulSize));
|
||||
}
|
||||
|
||||
|
||||
void *operator new(size_t ulSize, const nothrow_t &rNoThrow)
|
||||
{
|
||||
return(allocate(ulSize, rNoThrow));
|
||||
}
|
||||
|
||||
void *operator new[](size_t ulSize, const nothrow_t &rNoThrow)
|
||||
{
|
||||
return(allocate(ulSize, rNoThrow));
|
||||
}
|
||||
|
||||
|
||||
void operator delete(void *pBlock)
|
||||
{
|
||||
deallocate(pBlock);
|
||||
}
|
||||
|
||||
void operator delete[](void *pBlock)
|
||||
{
|
||||
deallocate(pBlock);
|
||||
}
|
||||
|
||||
|
||||
void operator delete(void *pBlock, const nothrow_t &)
|
||||
{
|
||||
deallocate(pBlock);
|
||||
}
|
||||
|
||||
void operator delete[](void *pBlock, const nothrow_t &)
|
||||
{
|
||||
deallocate(pBlock);
|
||||
}
|
||||
150
src/mac/msl_replacements/time.cpp
Normal file
150
src/mac/msl_replacements/time.cpp
Normal file
@@ -0,0 +1,150 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#include <cassert>
|
||||
// we include timesize.mac.h to get whether or not __TIMESIZE_DOUBLE__ is
|
||||
// defined. This is not safe, given that __TIMESIZE_DOUBLE__ affects MSL
|
||||
// at MSL's compile time, not ours, so be forgiving if you have changed it
|
||||
// since you have built MSL.
|
||||
#include <timesize.mac.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <boost/thread/detail/force_cast.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
|
||||
#include "execution_context.hpp"
|
||||
|
||||
#include <DriverServices.h>
|
||||
|
||||
|
||||
extern "C"
|
||||
{
|
||||
clock_t __get_clock();
|
||||
time_t __get_time();
|
||||
int __to_gm_time(time_t *pTime);
|
||||
int __is_dst();
|
||||
}
|
||||
|
||||
|
||||
static inline uint64_t get_nanoseconds()
|
||||
{
|
||||
using boost::detail::thread::force_cast;
|
||||
return(force_cast<uint64_t>(AbsoluteToNanoseconds(UpTime())));
|
||||
}
|
||||
|
||||
|
||||
#ifdef __TIMESIZE_DOUBLE__
|
||||
|
||||
// return number of microseconds since startup as a double
|
||||
clock_t __get_clock()
|
||||
{
|
||||
static const double k_dNanosecondsPerMicrosecond(1000.0);
|
||||
|
||||
return(get_nanoseconds() / k_dNanosecondsPerMicrosecond);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// return number of ticks (60th of a second) since startup as a long
|
||||
clock_t __get_clock()
|
||||
{
|
||||
static const uint64_t k_ullTicksPerSecond(60ULL);
|
||||
static const uint64_t k_ullNanosecondsPerSecond(1000ULL * 1000ULL * 1000ULL);
|
||||
static const uint64_t k_ullNanosecondsPerTick(k_ullNanosecondsPerSecond / k_ullTicksPerSecond);
|
||||
|
||||
return(get_nanoseconds() / k_ullNanosecondsPerTick);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// return number of seconds elapsed since Jan 1, 1970
|
||||
time_t __get_time()
|
||||
{
|
||||
boost::xtime sTime;
|
||||
int nType = boost::xtime_get(&sTime, boost::TIME_UTC);
|
||||
assert(nType == boost::TIME_UTC);
|
||||
return(static_cast<time_t>(sTime.sec));
|
||||
}
|
||||
|
||||
|
||||
static inline MachineLocation &read_location()
|
||||
{
|
||||
static MachineLocation s_sLocation;
|
||||
assert(boost::threads::mac::at_st());
|
||||
ReadLocation(&s_sLocation);
|
||||
return(s_sLocation);
|
||||
}
|
||||
|
||||
static inline MachineLocation &get_location()
|
||||
{
|
||||
static MachineLocation &s_rLocation(read_location());
|
||||
return(s_rLocation);
|
||||
}
|
||||
|
||||
|
||||
// force the machine location to be cached at static initlialization
|
||||
static MachineLocation &g_rIgnored(get_location());
|
||||
|
||||
static inline long calculate_delta()
|
||||
{
|
||||
MachineLocation &rLocation(get_location());
|
||||
|
||||
// gmtDelta is a 24-bit, signed integer. We need to strip out the lower 24 bits,
|
||||
// then sign-extend what we have.
|
||||
long lDelta = rLocation.u.gmtDelta & 0x00ffffffL;
|
||||
if((lDelta & 0x00800000L) != 0L)
|
||||
{
|
||||
lDelta |= 0xFF000000;
|
||||
}
|
||||
return(lDelta);
|
||||
}
|
||||
|
||||
static inline bool check_if_location_is_broken()
|
||||
{
|
||||
MachineLocation &rLocation(get_location());
|
||||
if(rLocation.latitude == 0 && rLocation.longitude == 0 && rLocation.u.gmtDelta == 0)
|
||||
return(true);
|
||||
return(false);
|
||||
}
|
||||
|
||||
static inline bool location_is_broken()
|
||||
{
|
||||
static bool s_bLocationIsBroken(check_if_location_is_broken());
|
||||
return(s_bLocationIsBroken);
|
||||
}
|
||||
|
||||
|
||||
// translate time to GMT
|
||||
int __to_gm_time(time_t *pTime)
|
||||
{
|
||||
if(location_is_broken())
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long s_lDelta(calculate_delta());
|
||||
*pTime -= s_lDelta;
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
static inline bool is_daylight_savings_time()
|
||||
{
|
||||
MachineLocation &rLocation(get_location());
|
||||
return(rLocation.u.dlsDelta != 0);
|
||||
}
|
||||
|
||||
// check if we're in daylight savings time
|
||||
int __is_dst()
|
||||
{
|
||||
if(location_is_broken())
|
||||
{
|
||||
return(-1);
|
||||
}
|
||||
static bool bIsDaylightSavingsTime(is_daylight_savings_time());
|
||||
return(static_cast<int>(bIsDaylightSavingsTime));
|
||||
}
|
||||
57
src/mac/os.cpp
Normal file
57
src/mac/os.cpp
Normal file
@@ -0,0 +1,57 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#include "os.hpp"
|
||||
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include <Gestalt.h>
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
namespace os {
|
||||
|
||||
|
||||
// read the OS version from Gestalt
|
||||
static inline long get_version()
|
||||
{
|
||||
long lVersion;
|
||||
OSErr nErr = Gestalt(gestaltSystemVersion, &lVersion);
|
||||
assert(nErr == noErr);
|
||||
return(lVersion);
|
||||
}
|
||||
|
||||
|
||||
// check if we're running under Mac OS X and cache that information
|
||||
bool x()
|
||||
{
|
||||
static bool bX = (version() >= 0x1000);
|
||||
return(bX);
|
||||
}
|
||||
|
||||
|
||||
// read the OS version and cache it
|
||||
long version()
|
||||
{
|
||||
static long lVersion = get_version();
|
||||
return(lVersion);
|
||||
}
|
||||
|
||||
|
||||
} // namespace os
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
37
src/mac/os.hpp
Normal file
37
src/mac/os.hpp
Normal file
@@ -0,0 +1,37 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#ifndef BOOST_OS_MJM012402_HPP
|
||||
#define BOOST_OS_MJM012402_HPP
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
namespace os {
|
||||
|
||||
|
||||
// functions to determine the OS environment. With namespaces, you get a cute call:
|
||||
// mac::os::x
|
||||
|
||||
bool x();
|
||||
long version();
|
||||
|
||||
|
||||
} // namespace os
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_OS_MJM012402_HPP
|
||||
46
src/mac/ot_context.cpp
Normal file
46
src/mac/ot_context.cpp
Normal file
@@ -0,0 +1,46 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#include "ot_context.hpp"
|
||||
|
||||
#include "execution_context.hpp"
|
||||
|
||||
|
||||
#include <cassert>
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
ot_context::ot_context()
|
||||
{
|
||||
assert(at_st());
|
||||
|
||||
OSStatus lStatus = InitOpenTransportInContext(0UL, &m_pContext);
|
||||
// TODO - throw on error
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
ot_context::~ot_context()
|
||||
{
|
||||
CloseOpenTransportInContext(m_pContext);
|
||||
}
|
||||
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
58
src/mac/ot_context.hpp
Normal file
58
src/mac/ot_context.hpp
Normal file
@@ -0,0 +1,58 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#ifndef BOOST_OT_CONTEXT_MJM012402_HPP
|
||||
#define BOOST_OT_CONTEXT_MJM012402_HPP
|
||||
|
||||
|
||||
#include <OpenTransport.h>
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
// class ot_context is intended to be used only as a singleton. All that this class
|
||||
// does is ask OpenTransport to create him an OTClientContextPtr, and then doles
|
||||
// this out to anyone who wants it. ot_context should only be instantiated at
|
||||
// system task time.
|
||||
|
||||
class ot_context: private noncopyable
|
||||
{
|
||||
protected:
|
||||
ot_context();
|
||||
~ot_context();
|
||||
|
||||
public:
|
||||
OTClientContextPtr get_context();
|
||||
|
||||
private:
|
||||
OTClientContextPtr m_pContext;
|
||||
};
|
||||
|
||||
|
||||
inline OTClientContextPtr ot_context::get_context()
|
||||
{ return(m_pContext); }
|
||||
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_OT_CONTEXT_MJM012402_HPP
|
||||
76
src/mac/package.hpp
Normal file
76
src/mac/package.hpp
Normal file
@@ -0,0 +1,76 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#ifndef BOOST_PACKAGE_MJM012402_HPP
|
||||
#define BOOST_PACKAGE_MJM012402_HPP
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
class base_package: private noncopyable
|
||||
{
|
||||
public:
|
||||
virtual void accept() = 0;
|
||||
};
|
||||
|
||||
template<class R>
|
||||
class package: public base_package
|
||||
{
|
||||
public:
|
||||
inline package(function<R> &rFunctor):
|
||||
m_rFunctor(rFunctor)
|
||||
{ /* no-op */ }
|
||||
inline ~package()
|
||||
{ /* no-op */ }
|
||||
|
||||
virtual void accept()
|
||||
{ m_oR = m_rFunctor(); }
|
||||
inline R return_value()
|
||||
{ return(m_oR); }
|
||||
|
||||
private:
|
||||
function<R> &m_rFunctor;
|
||||
R m_oR;
|
||||
};
|
||||
|
||||
template<>
|
||||
class package<void>: public base_package
|
||||
{
|
||||
public:
|
||||
inline package(function<void> &rFunctor):
|
||||
m_rFunctor(rFunctor)
|
||||
{ /* no-op */ }
|
||||
inline ~package()
|
||||
{ /* no-op */ }
|
||||
|
||||
virtual void accept()
|
||||
{ m_rFunctor(); }
|
||||
inline void return_value()
|
||||
{ return; }
|
||||
|
||||
private:
|
||||
function<void> &m_rFunctor;
|
||||
};
|
||||
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_PACKAGE_MJM012402_HPP
|
||||
97
src/mac/periodical.hpp
Normal file
97
src/mac/periodical.hpp
Normal file
@@ -0,0 +1,97 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#ifndef BOOST_PERIODICAL_MJM012402_HPP
|
||||
#define BOOST_PERIODICAL_MJM012402_HPP
|
||||
|
||||
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/utility.hpp>
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
// class periodical inherits from its template parameter, which should follow the
|
||||
// pattern set by classes dt_scheduler and st_scheduler. periodical knows how to
|
||||
// call a boost::function, where the xx_scheduler classes only know to to call a
|
||||
// member periodically.
|
||||
|
||||
template<class Scheduler>
|
||||
class periodical: private noncopyable, private Scheduler
|
||||
{
|
||||
public:
|
||||
periodical(function<void> &rFunction);
|
||||
~periodical();
|
||||
|
||||
public:
|
||||
void start();
|
||||
void stop();
|
||||
|
||||
protected:
|
||||
virtual void periodic_function();
|
||||
|
||||
private:
|
||||
function<void> m_oFunction;
|
||||
};
|
||||
|
||||
|
||||
template<class Scheduler>
|
||||
periodical<Scheduler>::periodical(function<void> &rFunction):
|
||||
m_oFunction(rFunction)
|
||||
{
|
||||
// no-op
|
||||
}
|
||||
|
||||
template<class Scheduler>
|
||||
periodical<Scheduler>::~periodical()
|
||||
{
|
||||
stop();
|
||||
}
|
||||
|
||||
template<class Scheduler>
|
||||
void periodical<Scheduler>::start()
|
||||
{
|
||||
start_polling();
|
||||
}
|
||||
|
||||
template<class Scheduler>
|
||||
void periodical<Scheduler>::stop()
|
||||
{
|
||||
stop_polling();
|
||||
}
|
||||
|
||||
|
||||
template<class Scheduler>
|
||||
inline void periodical<Scheduler>::periodic_function()
|
||||
{
|
||||
try
|
||||
{
|
||||
m_oFunction();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_PERIODICAL_MJM012402_HPP
|
||||
9
src/mac/prefix.hpp
Normal file
9
src/mac/prefix.hpp
Normal file
@@ -0,0 +1,9 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#define NDEBUG
|
||||
#define TARGET_CARBON 1
|
||||
48
src/mac/remote_call_manager.cpp
Normal file
48
src/mac/remote_call_manager.cpp
Normal file
@@ -0,0 +1,48 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#include "remote_call_manager.hpp"
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
using detail::delivery_man;
|
||||
|
||||
|
||||
remote_call_manager::remote_call_manager():
|
||||
m_oDTDeliveryMan(),
|
||||
m_oSTDeliveryMan(),
|
||||
m_oDTFunction(bind(&delivery_man::accept_deliveries, &m_oDTDeliveryMan)),
|
||||
m_oSTFunction(bind(&delivery_man::accept_deliveries, &m_oSTDeliveryMan)),
|
||||
m_oDTPeriodical(m_oDTFunction),
|
||||
m_oSTPeriodical(m_oSTFunction)
|
||||
{
|
||||
m_oDTPeriodical.start();
|
||||
m_oSTPeriodical.start();
|
||||
}
|
||||
|
||||
remote_call_manager::~remote_call_manager()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
102
src/mac/remote_call_manager.hpp
Normal file
102
src/mac/remote_call_manager.hpp
Normal file
@@ -0,0 +1,102 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#ifndef BOOST_REMOTE_CALL_MANAGER_MJM012402_HPP
|
||||
#define BOOST_REMOTE_CALL_MANAGER_MJM012402_HPP
|
||||
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
|
||||
#include "delivery_man.hpp"
|
||||
#include "dt_scheduler.hpp"
|
||||
#include "periodical.hpp"
|
||||
#include "execution_context.hpp"
|
||||
#include "st_scheduler.hpp"
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
// class remote_call_manager is used by the remote call functions (dt_remote_call and
|
||||
// st_remote_call) to execute functions in non-MP contexts.
|
||||
|
||||
class remote_call_manager: private noncopyable
|
||||
{
|
||||
protected:
|
||||
remote_call_manager();
|
||||
~remote_call_manager();
|
||||
|
||||
public:
|
||||
template<class R>
|
||||
R execute_at_dt(function<R> &rFunctor);
|
||||
template<class R>
|
||||
R execute_at_st(function<R> &rFunctor);
|
||||
|
||||
private:
|
||||
template<class R>
|
||||
static R execute_now(function<R> &rFunctor);
|
||||
|
||||
private:
|
||||
delivery_man m_oDTDeliveryMan;
|
||||
delivery_man m_oSTDeliveryMan;
|
||||
function<void> m_oDTFunction;
|
||||
function<void> m_oSTFunction;
|
||||
periodical<dt_scheduler> m_oDTPeriodical;
|
||||
periodical<st_scheduler> m_oSTPeriodical;
|
||||
};
|
||||
|
||||
|
||||
template<class R>
|
||||
/*static*/ inline R remote_call_manager::execute_now(function<R> &rFunctor)
|
||||
{
|
||||
return(rFunctor());
|
||||
}
|
||||
template<>
|
||||
/*static*/ inline void remote_call_manager::execute_now<void>(function<void> &rFunctor)
|
||||
{
|
||||
rFunctor();
|
||||
}
|
||||
|
||||
|
||||
template<class R>
|
||||
inline R remote_call_manager::execute_at_dt(function<R> &rFunctor)
|
||||
{
|
||||
if(at_mp())
|
||||
{
|
||||
return(m_oDTDeliveryMan.deliver(rFunctor));
|
||||
}
|
||||
return(execute_now(rFunctor));
|
||||
}
|
||||
|
||||
template<class R>
|
||||
inline R remote_call_manager::execute_at_st(function<R> &rFunctor)
|
||||
{
|
||||
if(at_mp())
|
||||
{
|
||||
return(m_oSTDeliveryMan.deliver(rFunctor));
|
||||
}
|
||||
assert(at_st());
|
||||
return(execute_now(rFunctor));
|
||||
}
|
||||
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_REMOTE_CALL_MANAGER_MJM012402_HPP
|
||||
157
src/mac/remote_calls.hpp
Normal file
157
src/mac/remote_calls.hpp
Normal file
@@ -0,0 +1,157 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#ifndef BOOST_REMOTE_CALLS_MJM012402_HPP
|
||||
#define BOOST_REMOTE_CALLS_MJM012402_HPP
|
||||
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
#include "remote_call_manager.hpp"
|
||||
#include <boost/thread/detail/singleton.hpp>
|
||||
|
||||
|
||||
// this file contains macros to generate functions with the signatures:
|
||||
// ReturnType st_remote_call([pascal] ReturnType (*pfnFunction)(
|
||||
// [Argument1Type[, Argument2Type[...]]])
|
||||
// [, Argument1Type oArgument1[, Argument2Type oArgument2[...]]])
|
||||
// and
|
||||
// ReturnType dt_remote_call([pascal] ReturnType (*pfnFunction)(
|
||||
// [Argument1Type[, Argument2Type[...]]])
|
||||
// [, Argument1Type oArgument1[, Argument2Type oArgument2[...]]])
|
||||
// in other words, identical to the function pointer versions of boost::bind, but
|
||||
// with the return type returned. The purpose of these functions is to be able to
|
||||
// request that a function be called at system task time or deferred task time, then
|
||||
// sleep until it is called, and finally get back its return value.
|
||||
|
||||
#define BOOST_REMOTE_CALL_CLASS_LIST_0
|
||||
#define BOOST_REMOTE_CALL_CLASS_LIST_1 BOOST_REMOTE_CALL_CLASS_LIST_0, class A1
|
||||
#define BOOST_REMOTE_CALL_CLASS_LIST_2 BOOST_REMOTE_CALL_CLASS_LIST_1, class A2
|
||||
#define BOOST_REMOTE_CALL_CLASS_LIST_3 BOOST_REMOTE_CALL_CLASS_LIST_2, class A3
|
||||
#define BOOST_REMOTE_CALL_CLASS_LIST_4 BOOST_REMOTE_CALL_CLASS_LIST_3, class A4
|
||||
#define BOOST_REMOTE_CALL_CLASS_LIST_5 BOOST_REMOTE_CALL_CLASS_LIST_4, class A5
|
||||
#define BOOST_REMOTE_CALL_CLASS_LIST_6 BOOST_REMOTE_CALL_CLASS_LIST_5, class A6
|
||||
#define BOOST_REMOTE_CALL_CLASS_LIST_7 BOOST_REMOTE_CALL_CLASS_LIST_6, class A7
|
||||
#define BOOST_REMOTE_CALL_CLASS_LIST_8 BOOST_REMOTE_CALL_CLASS_LIST_7, class A8
|
||||
#define BOOST_REMOTE_CALL_CLASS_LIST_9 BOOST_REMOTE_CALL_CLASS_LIST_8, class A9
|
||||
|
||||
|
||||
#define BOOST_REMOTE_CALL_ARGUMENT_LIST_0
|
||||
#define BOOST_REMOTE_CALL_ARGUMENT_LIST_1 BOOST_REMOTE_CALL_ARGUMENT_LIST_0 A1 oA1
|
||||
#define BOOST_REMOTE_CALL_ARGUMENT_LIST_2 BOOST_REMOTE_CALL_ARGUMENT_LIST_1, A2 oA2
|
||||
#define BOOST_REMOTE_CALL_ARGUMENT_LIST_3 BOOST_REMOTE_CALL_ARGUMENT_LIST_2, A3 oA3
|
||||
#define BOOST_REMOTE_CALL_ARGUMENT_LIST_4 BOOST_REMOTE_CALL_ARGUMENT_LIST_3, A4 oA4
|
||||
#define BOOST_REMOTE_CALL_ARGUMENT_LIST_5 BOOST_REMOTE_CALL_ARGUMENT_LIST_4, A5 oA5
|
||||
#define BOOST_REMOTE_CALL_ARGUMENT_LIST_6 BOOST_REMOTE_CALL_ARGUMENT_LIST_5, A6 oA6
|
||||
#define BOOST_REMOTE_CALL_ARGUMENT_LIST_7 BOOST_REMOTE_CALL_ARGUMENT_LIST_6, A7 oA7
|
||||
#define BOOST_REMOTE_CALL_ARGUMENT_LIST_8 BOOST_REMOTE_CALL_ARGUMENT_LIST_7, A8 oA8
|
||||
#define BOOST_REMOTE_CALL_ARGUMENT_LIST_9 BOOST_REMOTE_CALL_ARGUMENT_LIST_8, A9 oA9
|
||||
|
||||
|
||||
#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_0
|
||||
#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_1 BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_0, oA1
|
||||
#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_2 BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_1, oA2
|
||||
#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_3 BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_2, oA3
|
||||
#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_4 BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_3, oA4
|
||||
#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_5 BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_4, oA5
|
||||
#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_6 BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_5, oA6
|
||||
#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_7 BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_6, oA7
|
||||
#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_8 BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_7, oA8
|
||||
#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_9 BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_8, oA9
|
||||
|
||||
|
||||
#define BOOST_REMOTE_CALL_COMMA_0
|
||||
#define BOOST_REMOTE_CALL_COMMA_1 ,
|
||||
#define BOOST_REMOTE_CALL_COMMA_2 ,
|
||||
#define BOOST_REMOTE_CALL_COMMA_3 ,
|
||||
#define BOOST_REMOTE_CALL_COMMA_4 ,
|
||||
#define BOOST_REMOTE_CALL_COMMA_5 ,
|
||||
#define BOOST_REMOTE_CALL_COMMA_6 ,
|
||||
#define BOOST_REMOTE_CALL_COMMA_7 ,
|
||||
#define BOOST_REMOTE_CALL_COMMA_8 ,
|
||||
#define BOOST_REMOTE_CALL_COMMA_9 ,
|
||||
|
||||
|
||||
// this is the macro that ties it all together. From here, we generate all forms of
|
||||
// dt_remote_call and st_remote_call.
|
||||
|
||||
#define BOOST_REMOTE_CALL(context, stack, n) \
|
||||
template<class R BOOST_REMOTE_CALL_CLASS_LIST_ ## n> \
|
||||
inline R context ## _remote_call(stack R (*pfnF)( \
|
||||
BOOST_REMOTE_CALL_ARGUMENT_LIST_ ## n) \
|
||||
BOOST_REMOTE_CALL_COMMA_ ## n \
|
||||
BOOST_REMOTE_CALL_ARGUMENT_LIST_ ## n) \
|
||||
{ \
|
||||
using ::boost::detail::thread::singleton; \
|
||||
using detail::remote_call_manager; \
|
||||
function<R> oFunc(bind(pfnF BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_ ## n)); \
|
||||
remote_call_manager &rManager(singleton<remote_call_manager>::instance()); \
|
||||
return(rManager.execute_at_ ## context(oFunc)); \
|
||||
}
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
|
||||
BOOST_REMOTE_CALL(st, , 0)
|
||||
BOOST_REMOTE_CALL(st, , 1)
|
||||
BOOST_REMOTE_CALL(st, , 2)
|
||||
BOOST_REMOTE_CALL(st, , 3)
|
||||
BOOST_REMOTE_CALL(st, , 4)
|
||||
BOOST_REMOTE_CALL(st, , 5)
|
||||
BOOST_REMOTE_CALL(st, , 6)
|
||||
BOOST_REMOTE_CALL(st, , 7)
|
||||
BOOST_REMOTE_CALL(st, , 8)
|
||||
BOOST_REMOTE_CALL(st, , 9)
|
||||
|
||||
BOOST_REMOTE_CALL(dt, , 0)
|
||||
BOOST_REMOTE_CALL(dt, , 1)
|
||||
BOOST_REMOTE_CALL(dt, , 2)
|
||||
BOOST_REMOTE_CALL(dt, , 3)
|
||||
BOOST_REMOTE_CALL(dt, , 4)
|
||||
BOOST_REMOTE_CALL(dt, , 5)
|
||||
BOOST_REMOTE_CALL(dt, , 6)
|
||||
BOOST_REMOTE_CALL(dt, , 7)
|
||||
BOOST_REMOTE_CALL(dt, , 8)
|
||||
BOOST_REMOTE_CALL(dt, , 9)
|
||||
|
||||
|
||||
BOOST_REMOTE_CALL(st, pascal, 0)
|
||||
BOOST_REMOTE_CALL(st, pascal, 1)
|
||||
BOOST_REMOTE_CALL(st, pascal, 2)
|
||||
BOOST_REMOTE_CALL(st, pascal, 3)
|
||||
BOOST_REMOTE_CALL(st, pascal, 4)
|
||||
BOOST_REMOTE_CALL(st, pascal, 5)
|
||||
BOOST_REMOTE_CALL(st, pascal, 6)
|
||||
BOOST_REMOTE_CALL(st, pascal, 7)
|
||||
BOOST_REMOTE_CALL(st, pascal, 8)
|
||||
BOOST_REMOTE_CALL(st, pascal, 9)
|
||||
|
||||
BOOST_REMOTE_CALL(dt, pascal, 0)
|
||||
BOOST_REMOTE_CALL(dt, pascal, 1)
|
||||
BOOST_REMOTE_CALL(dt, pascal, 2)
|
||||
BOOST_REMOTE_CALL(dt, pascal, 3)
|
||||
BOOST_REMOTE_CALL(dt, pascal, 4)
|
||||
BOOST_REMOTE_CALL(dt, pascal, 5)
|
||||
BOOST_REMOTE_CALL(dt, pascal, 6)
|
||||
BOOST_REMOTE_CALL(dt, pascal, 7)
|
||||
BOOST_REMOTE_CALL(dt, pascal, 8)
|
||||
BOOST_REMOTE_CALL(dt, pascal, 9)
|
||||
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_REMOTE_CALLS_MJM012402_HPP
|
||||
210
src/mac/safe.cpp
Normal file
210
src/mac/safe.cpp
Normal file
@@ -0,0 +1,210 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#include <DriverServices.h>
|
||||
#include <Events.h>
|
||||
#include <Multiprocessing.h>
|
||||
#include <Threads.h>
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/function.hpp>
|
||||
|
||||
#include <boost/thread/detail/force_cast.hpp>
|
||||
#include <limits>
|
||||
#include "execution_context.hpp"
|
||||
|
||||
|
||||
using boost::detail::thread::force_cast;
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
static OSStatus safe_wait(function<OSStatus, Duration> &rFunction, Duration lDuration);
|
||||
|
||||
|
||||
// we call WNE to allow tasks that own the resource the blue is waiting on system
|
||||
// task time, in case they are blocked on an ST remote call (or a memory allocation
|
||||
// for that matter).
|
||||
static void idle()
|
||||
{
|
||||
if(at_st())
|
||||
{
|
||||
EventRecord sEvent;
|
||||
bool bEvent = WaitNextEvent(0U, &sEvent, 0UL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
OSStatus safe_wait_on_semaphore(MPSemaphoreID pSemaphoreID, Duration lDuration)
|
||||
{
|
||||
function<OSStatus, Duration> oWaitOnSemaphore;
|
||||
oWaitOnSemaphore = bind(MPWaitOnSemaphore, pSemaphoreID, _1);
|
||||
return(safe_wait(oWaitOnSemaphore, lDuration));
|
||||
}
|
||||
|
||||
|
||||
OSStatus safe_enter_critical_region(MPCriticalRegionID pCriticalRegionID, Duration lDuration, MPCriticalRegionID pCriticalRegionCriticalRegionID/* = kInvalidID*/)
|
||||
{
|
||||
if(pCriticalRegionCriticalRegionID != kInvalidID)
|
||||
{
|
||||
if(at_mp())
|
||||
{
|
||||
// enter the critical region's critical region
|
||||
OSStatus lStatus = noErr;
|
||||
AbsoluteTime sExpiration;
|
||||
if(lDuration != kDurationImmediate && lDuration != kDurationForever)
|
||||
{
|
||||
sExpiration = AddDurationToAbsolute(lDuration, UpTime());
|
||||
}
|
||||
lStatus = MPEnterCriticalRegion(pCriticalRegionCriticalRegionID, lDuration);
|
||||
assert(lStatus == noErr || lStatus == kMPTimeoutErr);
|
||||
if(lStatus == noErr)
|
||||
{
|
||||
// calculate a new duration
|
||||
if(lDuration != kDurationImmediate && lDuration != kDurationForever)
|
||||
{
|
||||
// check if we have any time left
|
||||
AbsoluteTime sUpTime(UpTime());
|
||||
if(force_cast<uint64_t>(sExpiration) > force_cast<uint64_t>(sUpTime))
|
||||
{
|
||||
// reset our duration to our remaining time
|
||||
lDuration = AbsoluteDeltaToDuration(sExpiration, sUpTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
// no time left
|
||||
lDuration = kDurationImmediate;
|
||||
}
|
||||
}
|
||||
// if we entered the critical region, exit it again
|
||||
lStatus = MPExitCriticalRegion(pCriticalRegionCriticalRegionID);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
else
|
||||
{
|
||||
// otherwise, give up
|
||||
return(lStatus);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// if we're at system task time, try to enter the critical region's critical
|
||||
// region until we succeed. MP tasks will block on this until we let it go.
|
||||
OSStatus lStatus;
|
||||
do
|
||||
{
|
||||
lStatus = MPEnterCriticalRegion(pCriticalRegionCriticalRegionID, kDurationImmediate);
|
||||
} while(lStatus == kMPTimeoutErr);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
}
|
||||
|
||||
// try to enter the critical region
|
||||
function<OSStatus, Duration> oEnterCriticalRegion;
|
||||
oEnterCriticalRegion = bind(MPEnterCriticalRegion, pCriticalRegionID, _1);
|
||||
OSStatus lStatus = safe_wait(oEnterCriticalRegion, lDuration);
|
||||
|
||||
// if we entered the critical region's critical region to get the critical region,
|
||||
// exit the critical region's critical region.
|
||||
if(pCriticalRegionCriticalRegionID != kInvalidID && at_mp() == false)
|
||||
{
|
||||
lStatus = MPExitCriticalRegion(pCriticalRegionCriticalRegionID);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
return(lStatus);
|
||||
}
|
||||
|
||||
OSStatus safe_wait_on_queue(MPQueueID pQueueID, void **pParam1, void **pParam2, void **pParam3, Duration lDuration)
|
||||
{
|
||||
function<OSStatus, Duration> oWaitOnQueue;
|
||||
oWaitOnQueue = bind(MPWaitOnQueue, pQueueID, pParam1, pParam2, pParam3, _1);
|
||||
return(safe_wait(oWaitOnQueue, lDuration));
|
||||
}
|
||||
|
||||
OSStatus safe_delay_until(AbsoluteTime *pWakeUpTime)
|
||||
{
|
||||
if(execution_context() == k_eExecutionContextMPTask)
|
||||
{
|
||||
return(MPDelayUntil(pWakeUpTime));
|
||||
}
|
||||
else
|
||||
{
|
||||
uint64_t ullWakeUpTime = force_cast<uint64_t>(*pWakeUpTime);
|
||||
|
||||
while(force_cast<uint64_t>(UpTime()) < ullWakeUpTime)
|
||||
{
|
||||
idle();
|
||||
}
|
||||
|
||||
return(noErr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
OSStatus safe_wait(function<OSStatus, Duration> &rFunction, Duration lDuration)
|
||||
{
|
||||
if(execution_context() == k_eExecutionContextMPTask)
|
||||
{
|
||||
return(rFunction(lDuration));
|
||||
}
|
||||
else
|
||||
{
|
||||
uint64_t ullExpiration = 0ULL;
|
||||
|
||||
// get the expiration time in UpTime units
|
||||
if(lDuration == kDurationForever)
|
||||
{
|
||||
ullExpiration = (::std::numeric_limits<uint64_t>::max)();
|
||||
}
|
||||
else if(lDuration == kDurationImmediate)
|
||||
{
|
||||
ullExpiration = force_cast<uint64_t>(UpTime());
|
||||
}
|
||||
else
|
||||
{
|
||||
AbsoluteTime sExpiration = AddDurationToAbsolute(lDuration, UpTime());
|
||||
ullExpiration = force_cast<uint64_t>(sExpiration);
|
||||
}
|
||||
|
||||
OSStatus lStatus;
|
||||
bool bExpired = false;
|
||||
|
||||
do
|
||||
{
|
||||
lStatus = rFunction(kDurationImmediate);
|
||||
// mm - "if" #if 0'd out to allow task time to threads blocked on I/O
|
||||
#if 0
|
||||
if(lStatus == kMPTimeoutErr)
|
||||
#endif
|
||||
{
|
||||
idle();
|
||||
}
|
||||
if(lDuration != kDurationForever)
|
||||
{
|
||||
bExpired = (force_cast<uint64_t>(UpTime()) < ullExpiration);
|
||||
}
|
||||
} while(lStatus == kMPTimeoutErr && bExpired == false);
|
||||
|
||||
return(lStatus);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
41
src/mac/safe.hpp
Normal file
41
src/mac/safe.hpp
Normal file
@@ -0,0 +1,41 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#ifndef BOOST_SAFE_MJM012402_HPP
|
||||
#define BOOST_SAFE_MJM012402_HPP
|
||||
|
||||
|
||||
#include <Multiprocessing.h>
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
// these functions are used to wain in an execution context-independent manor. All of these
|
||||
// functions are both MP- and ST-safe.
|
||||
|
||||
OSStatus safe_wait_on_semaphore(MPSemaphoreID pSemaphoreID, Duration lDuration);
|
||||
OSStatus safe_enter_critical_region(MPCriticalRegionID pCriticalRegionID, Duration lDuration, MPCriticalRegionID pCriticalRegionCriticalRegionID = kInvalidID);
|
||||
OSStatus safe_wait_on_queue(MPQueueID pQueueID, void **pParam1, void **pParam2, void **pParam3, Duration lDuration);
|
||||
OSStatus safe_delay_until(AbsoluteTime *pWakeUpTime);
|
||||
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_SAFE_MJM012402_HPP
|
||||
47
src/mac/scoped_critical_region.cpp
Normal file
47
src/mac/scoped_critical_region.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#include "scoped_critical_region.hpp"
|
||||
|
||||
#include "init.hpp"
|
||||
|
||||
|
||||
#include <cassert>
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
scoped_critical_region::scoped_critical_region():
|
||||
m_pCriticalRegionID(kInvalidID)
|
||||
{
|
||||
static bool bIgnored = thread_init();
|
||||
OSStatus lStatus = MPCreateCriticalRegion(&m_pCriticalRegionID);
|
||||
if(lStatus != noErr || m_pCriticalRegionID == kInvalidID)
|
||||
throw(thread_resource_error());
|
||||
}
|
||||
|
||||
scoped_critical_region::~scoped_critical_region()
|
||||
{
|
||||
OSStatus lStatus = MPDeleteCriticalRegion(m_pCriticalRegionID);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
63
src/mac/scoped_critical_region.hpp
Normal file
63
src/mac/scoped_critical_region.hpp
Normal file
@@ -0,0 +1,63 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#ifndef BOOST_SCOPED_CRITICAL_REGION_MJM012402_HPP
|
||||
#define BOOST_SCOPED_CRITICAL_REGION_MJM012402_HPP
|
||||
|
||||
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
|
||||
#include <Multiprocessing.h>
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
// class scoped_critical_region probably needs a new name. Although the current name
|
||||
// is accurate, it can be read to mean that a critical region is entered for the
|
||||
// current scope. In reality, a critical region is _created_ for the current scope.
|
||||
// This class is intended as a replacement for MPCriticalRegionID that will
|
||||
// automatically create and dispose of itself.
|
||||
|
||||
class scoped_critical_region
|
||||
{
|
||||
public:
|
||||
scoped_critical_region();
|
||||
~scoped_critical_region();
|
||||
|
||||
public:
|
||||
operator const MPCriticalRegionID &() const;
|
||||
const MPCriticalRegionID &get() const;
|
||||
|
||||
private:
|
||||
MPCriticalRegionID m_pCriticalRegionID;
|
||||
};
|
||||
|
||||
|
||||
// these are inlined for speed.
|
||||
inline scoped_critical_region::operator const MPCriticalRegionID &() const
|
||||
{ return(m_pCriticalRegionID); }
|
||||
inline const MPCriticalRegionID &scoped_critical_region::get() const
|
||||
{ return(m_pCriticalRegionID); }
|
||||
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_SCOPED_CRITICAL_REGION_MJM012402_HPP
|
||||
85
src/mac/st_scheduler.cpp
Normal file
85
src/mac/st_scheduler.cpp
Normal file
@@ -0,0 +1,85 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#include "st_scheduler.hpp"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
#if TARGET_CARBON
|
||||
|
||||
st_scheduler::st_scheduler():
|
||||
m_uppTask(NULL),
|
||||
m_pTimer(NULL)
|
||||
{
|
||||
m_uppTask = NewEventLoopTimerUPP(task_entry);
|
||||
// TODO - throw on error
|
||||
assert(m_uppTask != NULL);
|
||||
}
|
||||
|
||||
st_scheduler::~st_scheduler()
|
||||
{
|
||||
DisposeEventLoopTimerUPP(m_uppTask);
|
||||
m_uppTask = NULL;
|
||||
}
|
||||
|
||||
|
||||
void st_scheduler::start_polling()
|
||||
{
|
||||
assert(m_pTimer == NULL);
|
||||
OSStatus lStatus = InstallEventLoopTimer(GetMainEventLoop(),
|
||||
0 * kEventDurationSecond,
|
||||
kEventDurationMillisecond,
|
||||
m_uppTask,
|
||||
this,
|
||||
&m_pTimer);
|
||||
// TODO - throw on error
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
void st_scheduler::stop_polling()
|
||||
{
|
||||
assert(m_pTimer != NULL);
|
||||
OSStatus lStatus = RemoveEventLoopTimer(m_pTimer);
|
||||
assert(lStatus == noErr);
|
||||
m_pTimer = NULL;
|
||||
}
|
||||
|
||||
|
||||
/*static*/ pascal void st_scheduler::task_entry(EventLoopTimerRef /*pTimer*/, void *pRefCon)
|
||||
{
|
||||
st_scheduler *pThis = reinterpret_cast<st_scheduler *>(pRefCon);
|
||||
assert(pThis != NULL);
|
||||
pThis->task();
|
||||
}
|
||||
|
||||
void st_scheduler::task()
|
||||
{
|
||||
periodic_function();
|
||||
}
|
||||
|
||||
#else
|
||||
# error st_scheduler unimplemented!
|
||||
#endif
|
||||
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
67
src/mac/st_scheduler.hpp
Normal file
67
src/mac/st_scheduler.hpp
Normal file
@@ -0,0 +1,67 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#ifndef BOOST_ST_SCHEDULER_MJM012402_HPP
|
||||
#define BOOST_ST_SCHEDULER_MJM012402_HPP
|
||||
|
||||
|
||||
#include <CarbonEvents.h>
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
// class st_scheduler calls its pure-virtual periodic_function method periodically at
|
||||
// system task time. This is generally 40Hz under Mac OS 9.
|
||||
|
||||
class st_scheduler
|
||||
{
|
||||
public:
|
||||
st_scheduler();
|
||||
virtual ~st_scheduler();
|
||||
|
||||
protected:
|
||||
void start_polling();
|
||||
void stop_polling();
|
||||
|
||||
private:
|
||||
virtual void periodic_function() = 0;
|
||||
|
||||
#if TARGET_CARBON
|
||||
// use event loop timers under Carbon
|
||||
private:
|
||||
static pascal void task_entry(EventLoopTimerRef pTimer, void *pRefCon);
|
||||
void task();
|
||||
|
||||
private:
|
||||
EventLoopTimerUPP m_uppTask;
|
||||
EventLoopTimerRef m_pTimer;
|
||||
#else
|
||||
// this can be implemented using OT system tasks. This would be mostly a copy-and-
|
||||
// paste of the dt_scheduler code, replacing DeferredTask with SystemTask and DT
|
||||
// with ST.
|
||||
# error st_scheduler unimplemented!
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_ST_SCHEDULER_MJM012402_HPP
|
||||
56
src/mac/thread_cleanup.cpp
Normal file
56
src/mac/thread_cleanup.cpp
Normal file
@@ -0,0 +1,56 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#include "thread_cleanup.hpp"
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
TaskStorageIndex g_ulIndex(0UL);
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
void do_thread_startup()
|
||||
{
|
||||
if(g_ulIndex == 0UL)
|
||||
{
|
||||
OSStatus lStatus = MPAllocateTaskStorageIndex(&g_ulIndex);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
set_thread_cleanup_task(NULL);
|
||||
}
|
||||
|
||||
void do_thread_cleanup()
|
||||
{
|
||||
void (*pfnTask)() = MPGetTaskValue(g_ulIndex)
|
||||
}
|
||||
|
||||
|
||||
void set_thread_cleanup_task(void (*pfnTask)())
|
||||
{
|
||||
lStatus = MPSetTaskValue(g_ulIndex, reinterpret_cast<TaskStorageValue>(pfnTask));
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
36
src/mac/thread_cleanup.hpp
Normal file
36
src/mac/thread_cleanup.hpp
Normal file
@@ -0,0 +1,36 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#ifndef BOOST_THREAD_CLEANUP_MJM012402_HPP
|
||||
#define BOOST_THREAD_CLEANUP_MJM012402_HPP
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
void do_thread_startup();
|
||||
void do_thread_cleanup();
|
||||
|
||||
void set_thread_cleanup_task();
|
||||
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_THREAD_CLEANUP_MJM012402_HPP
|
||||
561
src/mutex.cpp
Normal file
561
src/mutex.cpp
Normal file
@@ -0,0 +1,561 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/limits.hpp>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <cassert>
|
||||
#include "timeconv.inl"
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
# include <new>
|
||||
# include <boost/thread/once.hpp>
|
||||
# include <windows.h>
|
||||
# include <time.h>
|
||||
# include "mutex.inl"
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
# include <errno.h>
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
# include <MacErrors.h>
|
||||
# include "mac/init.hpp"
|
||||
# include "mac/safe.hpp"
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
|
||||
mutex::mutex()
|
||||
: m_mutex(0)
|
||||
, m_critical_section(false)
|
||||
{
|
||||
m_critical_section = true;
|
||||
if (m_critical_section)
|
||||
m_mutex = new_critical_section();
|
||||
else
|
||||
m_mutex = new_mutex(0);
|
||||
}
|
||||
|
||||
mutex::~mutex()
|
||||
{
|
||||
if (m_critical_section)
|
||||
delete_critical_section(m_mutex);
|
||||
else
|
||||
delete_mutex(m_mutex);
|
||||
}
|
||||
|
||||
void mutex::do_lock()
|
||||
{
|
||||
if (m_critical_section)
|
||||
wait_critical_section_infinite(m_mutex);
|
||||
else
|
||||
wait_mutex(m_mutex, INFINITE);
|
||||
}
|
||||
|
||||
void mutex::do_unlock()
|
||||
{
|
||||
if (m_critical_section)
|
||||
release_critical_section(m_mutex);
|
||||
else
|
||||
release_mutex(m_mutex);
|
||||
}
|
||||
|
||||
void mutex::do_lock(cv_state&)
|
||||
{
|
||||
do_lock();
|
||||
}
|
||||
|
||||
void mutex::do_unlock(cv_state&)
|
||||
{
|
||||
do_unlock();
|
||||
}
|
||||
|
||||
try_mutex::try_mutex()
|
||||
: m_mutex(0)
|
||||
, m_critical_section(false)
|
||||
{
|
||||
m_critical_section = has_TryEnterCriticalSection();
|
||||
if (m_critical_section)
|
||||
m_mutex = new_critical_section();
|
||||
else
|
||||
m_mutex = new_mutex(0);
|
||||
}
|
||||
|
||||
try_mutex::~try_mutex()
|
||||
{
|
||||
if (m_critical_section)
|
||||
delete_critical_section(m_mutex);
|
||||
else
|
||||
delete_mutex(m_mutex);
|
||||
}
|
||||
|
||||
void try_mutex::do_lock()
|
||||
{
|
||||
if (m_critical_section)
|
||||
wait_critical_section_infinite(m_mutex);
|
||||
else
|
||||
wait_mutex(m_mutex, INFINITE);
|
||||
}
|
||||
|
||||
bool try_mutex::do_trylock()
|
||||
{
|
||||
if (m_critical_section)
|
||||
return wait_critical_section_try(m_mutex);
|
||||
else
|
||||
return wait_mutex(m_mutex, 0) == WAIT_OBJECT_0;
|
||||
}
|
||||
|
||||
void try_mutex::do_unlock()
|
||||
{
|
||||
if (m_critical_section)
|
||||
release_critical_section(m_mutex);
|
||||
else
|
||||
release_mutex(m_mutex);
|
||||
}
|
||||
|
||||
void try_mutex::do_lock(cv_state&)
|
||||
{
|
||||
do_lock();
|
||||
}
|
||||
|
||||
void try_mutex::do_unlock(cv_state&)
|
||||
{
|
||||
do_unlock();
|
||||
}
|
||||
|
||||
timed_mutex::timed_mutex()
|
||||
: m_mutex(0)
|
||||
{
|
||||
m_mutex = new_mutex(0);
|
||||
}
|
||||
|
||||
timed_mutex::~timed_mutex()
|
||||
{
|
||||
delete_mutex(m_mutex);
|
||||
}
|
||||
|
||||
void timed_mutex::do_lock()
|
||||
{
|
||||
wait_mutex(m_mutex, INFINITE);
|
||||
}
|
||||
|
||||
bool timed_mutex::do_trylock()
|
||||
{
|
||||
return wait_mutex(m_mutex, 0) == WAIT_OBJECT_0;
|
||||
}
|
||||
|
||||
bool timed_mutex::do_timedlock(const xtime& xt)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
int milliseconds;
|
||||
to_duration(xt, milliseconds);
|
||||
|
||||
int res = wait_mutex(m_mutex, milliseconds);
|
||||
|
||||
if (res == WAIT_TIMEOUT)
|
||||
{
|
||||
boost::xtime cur;
|
||||
boost::xtime_get(&cur, boost::TIME_UTC);
|
||||
if (boost::xtime_cmp(xt, cur) > 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
return res == WAIT_OBJECT_0;
|
||||
}
|
||||
}
|
||||
|
||||
void timed_mutex::do_unlock()
|
||||
{
|
||||
release_mutex(m_mutex);
|
||||
}
|
||||
|
||||
void timed_mutex::do_lock(cv_state&)
|
||||
{
|
||||
do_lock();
|
||||
}
|
||||
|
||||
void timed_mutex::do_unlock(cv_state&)
|
||||
{
|
||||
do_unlock();
|
||||
}
|
||||
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
|
||||
mutex::mutex()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_init(&m_mutex, 0);
|
||||
if (res != 0)
|
||||
throw thread_resource_error();
|
||||
}
|
||||
|
||||
mutex::~mutex()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_destroy(&m_mutex);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
void mutex::do_lock()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_lock(&m_mutex);
|
||||
if (res == EDEADLK) throw lock_error();
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
void mutex::do_unlock()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_unlock(&m_mutex);
|
||||
if (res == EPERM) throw lock_error();
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
void mutex::do_lock(cv_state&)
|
||||
{
|
||||
}
|
||||
|
||||
void mutex::do_unlock(cv_state& state)
|
||||
{
|
||||
state.pmutex = &m_mutex;
|
||||
}
|
||||
|
||||
try_mutex::try_mutex()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_init(&m_mutex, 0);
|
||||
if (res != 0)
|
||||
throw thread_resource_error();
|
||||
}
|
||||
|
||||
try_mutex::~try_mutex()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_destroy(&m_mutex);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
void try_mutex::do_lock()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_lock(&m_mutex);
|
||||
if (res == EDEADLK) throw lock_error();
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
bool try_mutex::do_trylock()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_trylock(&m_mutex);
|
||||
if (res == EDEADLK) throw lock_error();
|
||||
assert(res == 0 || res == EBUSY);
|
||||
return res == 0;
|
||||
}
|
||||
|
||||
void try_mutex::do_unlock()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_unlock(&m_mutex);
|
||||
if (res == EPERM) throw lock_error();
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
void try_mutex::do_lock(cv_state&)
|
||||
{
|
||||
}
|
||||
|
||||
void try_mutex::do_unlock(cv_state& state)
|
||||
{
|
||||
state.pmutex = &m_mutex;
|
||||
}
|
||||
|
||||
timed_mutex::timed_mutex()
|
||||
: m_locked(false)
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_init(&m_mutex, 0);
|
||||
if (res != 0)
|
||||
throw thread_resource_error();
|
||||
|
||||
res = pthread_cond_init(&m_condition, 0);
|
||||
if (res != 0)
|
||||
{
|
||||
pthread_mutex_destroy(&m_mutex);
|
||||
throw thread_resource_error();
|
||||
}
|
||||
}
|
||||
|
||||
timed_mutex::~timed_mutex()
|
||||
{
|
||||
assert(!m_locked);
|
||||
int res = 0;
|
||||
res = pthread_mutex_destroy(&m_mutex);
|
||||
assert(res == 0);
|
||||
|
||||
res = pthread_cond_destroy(&m_condition);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
void timed_mutex::do_lock()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_lock(&m_mutex);
|
||||
assert(res == 0);
|
||||
|
||||
while (m_locked)
|
||||
{
|
||||
res = pthread_cond_wait(&m_condition, &m_mutex);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
assert(!m_locked);
|
||||
m_locked = true;
|
||||
|
||||
res = pthread_mutex_unlock(&m_mutex);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
bool timed_mutex::do_trylock()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_lock(&m_mutex);
|
||||
assert(res == 0);
|
||||
|
||||
bool ret = false;
|
||||
if (!m_locked)
|
||||
{
|
||||
m_locked = true;
|
||||
ret = true;
|
||||
}
|
||||
|
||||
res = pthread_mutex_unlock(&m_mutex);
|
||||
assert(res == 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool timed_mutex::do_timedlock(const xtime& xt)
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_lock(&m_mutex);
|
||||
assert(res == 0);
|
||||
|
||||
timespec ts;
|
||||
to_timespec(xt, ts);
|
||||
|
||||
while (m_locked)
|
||||
{
|
||||
res = pthread_cond_timedwait(&m_condition, &m_mutex, &ts);
|
||||
assert(res == 0 || res == ETIMEDOUT);
|
||||
|
||||
if (res == ETIMEDOUT)
|
||||
break;
|
||||
}
|
||||
|
||||
bool ret = false;
|
||||
if (!m_locked)
|
||||
{
|
||||
m_locked = true;
|
||||
ret = true;
|
||||
}
|
||||
|
||||
res = pthread_mutex_unlock(&m_mutex);
|
||||
assert(res == 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void timed_mutex::do_unlock()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_lock(&m_mutex);
|
||||
assert(res == 0);
|
||||
|
||||
assert(m_locked);
|
||||
m_locked = false;
|
||||
|
||||
res = pthread_cond_signal(&m_condition);
|
||||
assert(res == 0);
|
||||
|
||||
res = pthread_mutex_unlock(&m_mutex);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
void timed_mutex::do_lock(cv_state&)
|
||||
{
|
||||
int res = 0;
|
||||
while (m_locked)
|
||||
{
|
||||
res = pthread_cond_wait(&m_condition, &m_mutex);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
assert(!m_locked);
|
||||
m_locked = true;
|
||||
|
||||
res = pthread_mutex_unlock(&m_mutex);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
void timed_mutex::do_unlock(cv_state& state)
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_lock(&m_mutex);
|
||||
assert(res == 0);
|
||||
|
||||
assert(m_locked);
|
||||
m_locked = false;
|
||||
|
||||
res = pthread_cond_signal(&m_condition);
|
||||
assert(res == 0);
|
||||
|
||||
state.pmutex = &m_mutex;
|
||||
}
|
||||
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
|
||||
using threads::mac::detail::safe_enter_critical_region;
|
||||
|
||||
mutex::mutex()
|
||||
{
|
||||
}
|
||||
|
||||
mutex::~mutex()
|
||||
{
|
||||
}
|
||||
|
||||
void mutex::do_lock()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||
m_mutex_mutex);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
void mutex::do_unlock()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = MPExitCriticalRegion(m_mutex);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
void mutex::do_lock(cv_state& /*state*/)
|
||||
{
|
||||
do_lock();
|
||||
}
|
||||
|
||||
void mutex::do_unlock(cv_state& /*state*/)
|
||||
{
|
||||
do_unlock();
|
||||
}
|
||||
|
||||
try_mutex::try_mutex()
|
||||
{
|
||||
}
|
||||
|
||||
try_mutex::~try_mutex()
|
||||
{
|
||||
}
|
||||
|
||||
void try_mutex::do_lock()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||
m_mutex_mutex);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
bool try_mutex::do_trylock()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = MPEnterCriticalRegion(m_mutex, kDurationImmediate);
|
||||
assert(lStatus == noErr || lStatus == kMPTimeoutErr);
|
||||
return lStatus == noErr;
|
||||
}
|
||||
|
||||
void try_mutex::do_unlock()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = MPExitCriticalRegion(m_mutex);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
void try_mutex::do_lock(cv_state& /*state*/)
|
||||
{
|
||||
do_lock();
|
||||
}
|
||||
|
||||
void try_mutex::do_unlock(cv_state& /*state*/)
|
||||
{
|
||||
do_unlock();
|
||||
}
|
||||
|
||||
timed_mutex::timed_mutex()
|
||||
{
|
||||
}
|
||||
|
||||
timed_mutex::~timed_mutex()
|
||||
{
|
||||
}
|
||||
|
||||
void timed_mutex::do_lock()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||
m_mutex_mutex);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
bool timed_mutex::do_trylock()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = MPEnterCriticalRegion(m_mutex, kDurationImmediate);
|
||||
assert(lStatus == noErr || lStatus == kMPTimeoutErr);
|
||||
return(lStatus == noErr);
|
||||
}
|
||||
|
||||
bool timed_mutex::do_timedlock(const xtime& xt)
|
||||
{
|
||||
int microseconds;
|
||||
to_microduration(xt, microseconds);
|
||||
Duration lDuration = kDurationMicrosecond * microseconds;
|
||||
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = safe_enter_critical_region(m_mutex, lDuration, m_mutex_mutex);
|
||||
assert(lStatus == noErr || lStatus == kMPTimeoutErr);
|
||||
|
||||
return(lStatus == noErr);
|
||||
}
|
||||
|
||||
void timed_mutex::do_unlock()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = MPExitCriticalRegion(m_mutex);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
void timed_mutex::do_lock(cv_state& /*state*/)
|
||||
{
|
||||
do_lock();
|
||||
}
|
||||
|
||||
void timed_mutex::do_unlock(cv_state& /*state*/)
|
||||
{
|
||||
do_unlock();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace boost
|
||||
|
||||
// Change Log:
|
||||
// 8 Feb 01 WEKEMPF Initial version.
|
||||
120
src/mutex.inl
Normal file
120
src/mutex.inl
Normal file
@@ -0,0 +1,120 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
// boostinspect:nounnamed
|
||||
|
||||
namespace {
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
//:PREVENT THIS FROM BEING DUPLICATED
|
||||
typedef BOOL (WINAPI* TryEnterCriticalSection_type)(LPCRITICAL_SECTION lpCriticalSection);
|
||||
TryEnterCriticalSection_type g_TryEnterCriticalSection = 0;
|
||||
boost::once_flag once_init_TryEnterCriticalSection = BOOST_ONCE_INIT;
|
||||
|
||||
void init_TryEnterCriticalSection()
|
||||
{
|
||||
//TryEnterCriticalSection is only available on WinNT 4.0 or later;
|
||||
//it is not available on Win9x.
|
||||
|
||||
OSVERSIONINFO version_info = {sizeof(OSVERSIONINFO)};
|
||||
::GetVersionEx(&version_info);
|
||||
if (version_info.dwPlatformId == VER_PLATFORM_WIN32_NT &&
|
||||
version_info.dwMajorVersion >= 4)
|
||||
{
|
||||
if (HMODULE kernel_module = GetModuleHandle(TEXT("KERNEL32.DLL")))
|
||||
g_TryEnterCriticalSection = reinterpret_cast<TryEnterCriticalSection_type>(GetProcAddress(kernel_module, TEXT("TryEnterCriticalSection")));
|
||||
}
|
||||
}
|
||||
|
||||
inline bool has_TryEnterCriticalSection()
|
||||
{
|
||||
boost::call_once(init_TryEnterCriticalSection, once_init_TryEnterCriticalSection);
|
||||
return g_TryEnterCriticalSection != 0;
|
||||
}
|
||||
|
||||
inline HANDLE mutex_cast(void* p)
|
||||
{
|
||||
return reinterpret_cast<HANDLE>(p);
|
||||
}
|
||||
|
||||
inline LPCRITICAL_SECTION critical_section_cast(void* p)
|
||||
{
|
||||
return reinterpret_cast<LPCRITICAL_SECTION>(p);
|
||||
}
|
||||
|
||||
inline void* new_critical_section()
|
||||
{
|
||||
try
|
||||
{
|
||||
LPCRITICAL_SECTION critical_section = new CRITICAL_SECTION;
|
||||
if (critical_section == 0) throw boost::thread_resource_error();
|
||||
InitializeCriticalSection(critical_section);
|
||||
return critical_section;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
throw boost::thread_resource_error();
|
||||
}
|
||||
}
|
||||
|
||||
inline void* new_mutex(const char* name)
|
||||
{
|
||||
#if defined(BOOST_NO_ANSI_APIS)
|
||||
USES_CONVERSION;
|
||||
HANDLE mutex = CreateMutexW(0, 0, A2CW(name));
|
||||
#else
|
||||
HANDLE mutex = CreateMutexA(0, 0, name);
|
||||
#endif
|
||||
if (mutex == 0 || mutex == INVALID_HANDLE_VALUE) //:xxx (check for both values?)
|
||||
throw boost::thread_resource_error();
|
||||
return reinterpret_cast<void*>(mutex);
|
||||
}
|
||||
|
||||
inline void delete_critical_section(void* mutex)
|
||||
{
|
||||
DeleteCriticalSection(critical_section_cast(mutex));
|
||||
delete critical_section_cast(mutex);
|
||||
}
|
||||
|
||||
inline void delete_mutex(void* mutex)
|
||||
{
|
||||
int res = 0;
|
||||
res = CloseHandle(mutex_cast(mutex));
|
||||
assert(res);
|
||||
}
|
||||
|
||||
inline void wait_critical_section_infinite(void* mutex)
|
||||
{
|
||||
EnterCriticalSection(critical_section_cast(mutex)); //:xxx Can throw an exception under low memory conditions
|
||||
}
|
||||
|
||||
inline bool wait_critical_section_try(void* mutex)
|
||||
{
|
||||
BOOL res = g_TryEnterCriticalSection(critical_section_cast(mutex));
|
||||
return res != 0;
|
||||
}
|
||||
|
||||
inline int wait_mutex(void* mutex, int time)
|
||||
{
|
||||
unsigned int res = 0;
|
||||
res = WaitForSingleObject(mutex_cast(mutex), time);
|
||||
//:xxx assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
|
||||
return res;
|
||||
}
|
||||
|
||||
inline void release_critical_section(void* mutex)
|
||||
{
|
||||
LeaveCriticalSection(critical_section_cast(mutex));
|
||||
}
|
||||
|
||||
inline void release_mutex(void* mutex)
|
||||
{
|
||||
BOOL res = FALSE;
|
||||
res = ReleaseMutex(mutex_cast(mutex));
|
||||
assert(res);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
213
src/once.cpp
Normal file
213
src/once.cpp
Normal file
@@ -0,0 +1,213 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/detail/workaround.hpp>
|
||||
|
||||
#include <boost/thread/once.hpp>
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
# if BOOST_WORKAROUND(__BORLANDC__,<= 0x551)
|
||||
using std::size_t;
|
||||
# endif
|
||||
# include <windows.h>
|
||||
# if defined(BOOST_NO_STRINGSTREAM)
|
||||
# include <strstream>
|
||||
|
||||
class unfreezer
|
||||
{
|
||||
public:
|
||||
unfreezer(std::ostrstream& s) : m_stream(s) {}
|
||||
~unfreezer() { m_stream.freeze(false); }
|
||||
private:
|
||||
std::ostrstream& m_stream;
|
||||
};
|
||||
|
||||
# else
|
||||
# include <sstream>
|
||||
# endif
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
# include <Multiprocessing.h>
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_NO_STDC_NAMESPACE
|
||||
namespace std { using ::sprintf; }
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
namespace {
|
||||
pthread_key_t key;
|
||||
pthread_once_t once = PTHREAD_ONCE_INIT;
|
||||
|
||||
typedef void (*once_callback)();
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
static void key_init()
|
||||
{
|
||||
pthread_key_create(&key, 0);
|
||||
}
|
||||
|
||||
static void do_once()
|
||||
{
|
||||
once_callback* cb = reinterpret_cast<once_callback*>(
|
||||
pthread_getspecific(key));
|
||||
(**cb)();
|
||||
}
|
||||
|
||||
}
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
namespace {
|
||||
void *remote_call_proxy(void *pData)
|
||||
{
|
||||
std::pair<void (*)(), boost::once_flag *> &rData(
|
||||
*reinterpret_cast<std::pair<void (*)(), boost::once_flag *> *>(pData));
|
||||
|
||||
if(*rData.second == false)
|
||||
{
|
||||
rData.first();
|
||||
*rData.second = true;
|
||||
}
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(BOOST_HAS_WINTHREADS)
|
||||
namespace {
|
||||
// The signature for InterlockedCompareExchange has changed with the
|
||||
// addition of Win64 support. I can't determine any (consistent and
|
||||
// portable) way of using conditional compilation to detect this, so
|
||||
// we use these type wrappers. Unfortunately, the various vendors
|
||||
// use different calling conventions and other signature anamolies,
|
||||
// and thus have unique types as well. This is known to work on VC6,
|
||||
// VC7, Borland 5.5.2 and gcc 3.2. Are there other signatures for
|
||||
// other platforms?
|
||||
inline LONG ice_wrapper(LONG (__stdcall *ice)(LONG*, LONG, LONG),
|
||||
volatile LONG* dest, LONG exch, LONG cmp)
|
||||
{
|
||||
return (*ice)(const_cast<LONG*>(dest), exch, cmp);
|
||||
}
|
||||
|
||||
inline LONG ice_wrapper(LONG (__stdcall *ice)(volatile LONG*, LONG, LONG),
|
||||
volatile LONG* dest, LONG exch, LONG cmp)
|
||||
{
|
||||
return (*ice)(dest, exch, cmp);
|
||||
}
|
||||
|
||||
inline LONG ice_wrapper(LPVOID (__stdcall *ice)(LPVOID*, LPVOID, LPVOID),
|
||||
volatile LONG* dest, LONG exch, LONG cmp)
|
||||
{
|
||||
return (LONG)(*ice)((LPVOID*)dest, (LPVOID)exch, (LPVOID)cmp);
|
||||
}
|
||||
|
||||
// The friendly form of InterlockedCompareExchange that defers
|
||||
// according to the above function type wrappers.
|
||||
inline LONG compare_exchange(volatile LPLONG dest, LONG exch, LONG cmp)
|
||||
{
|
||||
#ifdef _WIN64
|
||||
// Original patch from Anthony Williams.
|
||||
// I (Roland Schwarz) am trying this for RC_1_34_0, since x64 regressions are
|
||||
// currently not run on x64 platforms for HEAD
|
||||
return InterlockedCompareExchange(dest, exch,cmp);
|
||||
#else
|
||||
return ice_wrapper(&InterlockedCompareExchange, dest, exch, cmp);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
void call_once(void (*func)(), once_flag& flag)
|
||||
{
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
if (compare_exchange(&flag, 1, 1) == 0)
|
||||
{
|
||||
#if defined(BOOST_NO_STRINGSTREAM)
|
||||
std::ostrstream strm;
|
||||
strm << "2AC1A572DB6944B0A65C38C4140AF2F4"
|
||||
<< std::hex
|
||||
<< GetCurrentProcessId()
|
||||
<< &flag
|
||||
<< std::ends;
|
||||
unfreezer unfreeze(strm);
|
||||
# if defined (BOOST_NO_ANSI_APIS)
|
||||
USES_CONVERSION;
|
||||
HANDLE mutex = CreateMutexW(NULL, FALSE, A2CW(strm.str()));
|
||||
# else
|
||||
HANDLE mutex = CreateMutexA(NULL, FALSE, strm.str());
|
||||
# endif
|
||||
#else
|
||||
# if defined (BOOST_NO_ANSI_APIS)
|
||||
std::wostringstream strm;
|
||||
strm << L"2AC1A572DB6944B0A65C38C4140AF2F4"
|
||||
<< std::hex
|
||||
<< GetCurrentProcessId()
|
||||
<< &flag;
|
||||
HANDLE mutex = CreateMutexW(NULL, FALSE, strm.str().c_str());
|
||||
# else
|
||||
std::ostringstream strm;
|
||||
strm << "2AC1A572DB6944B0A65C38C4140AF2F4"
|
||||
<< std::hex
|
||||
<< GetCurrentProcessId()
|
||||
<< &flag;
|
||||
HANDLE mutex = CreateMutexA(NULL, FALSE, strm.str().c_str());
|
||||
# endif
|
||||
#endif
|
||||
assert(mutex != NULL);
|
||||
|
||||
int res = 0;
|
||||
res = WaitForSingleObject(mutex, INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
|
||||
if (compare_exchange(&flag, 1, 1) == 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
func();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
res = ReleaseMutex(mutex);
|
||||
assert(res);
|
||||
res = CloseHandle(mutex);
|
||||
assert(res);
|
||||
throw;
|
||||
}
|
||||
InterlockedExchange(&flag, 1);
|
||||
}
|
||||
|
||||
res = ReleaseMutex(mutex);
|
||||
assert(res);
|
||||
res = CloseHandle(mutex);
|
||||
assert(res);
|
||||
}
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
pthread_once(&once, &key_init);
|
||||
pthread_setspecific(key, &func);
|
||||
pthread_once(&flag, do_once);
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
if(flag == false)
|
||||
{
|
||||
// all we do here is make a remote call to blue, as blue is not
|
||||
// reentrant.
|
||||
std::pair<void (*)(), once_flag *> sData(func, &flag);
|
||||
MPRemoteCall(remote_call_proxy, &sData, kMPOwningProcessRemoteContext);
|
||||
assert(flag == true);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Change Log:
|
||||
// 1 Aug 01 WEKEMPF Initial version.
|
||||
1738
src/read_write_mutex.cpp
Normal file
1738
src/read_write_mutex.cpp
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user