2
0
mirror of https://github.com/boostorg/thread.git synced 2026-02-12 12:32:10 +00:00

Compare commits

...

28 Commits

Author SHA1 Message Date
nobody
4c5073b43d This commit was manufactured by cvs2svn to create tag
'Version_1_30_2'.

[SVN r19685]
2003-08-18 18:40:31 +00:00
William E. Kempf
7a982cb083 Fixed typo: conditin.hpp.
[SVN r17798]
2003-03-10 15:30:29 +00:00
nobody
215ae5dd53 This commit was manufactured by cvs2svn to create branch 'RC_1_30_0'.
[SVN r17693]
2003-03-01 19:43:06 +00:00
William E. Kempf
45b0396355 Removed Borland warnings.
[SVN r17605]
2003-02-23 17:38:11 +00:00
William E. Kempf
1df2169e48 Removed new(nothrow) calls.
[SVN r17586]
2003-02-22 04:54:19 +00:00
William E. Kempf
2c056b3621 Added acknowledgement for Martin Johnson's help with shared library implementation
[SVN r17510]
2003-02-18 17:02:29 +00:00
William E. Kempf
680119006c Unlocked mutex in all control paths in notify_all
[SVN r17509]
2003-02-18 16:59:03 +00:00
Björn Karlsson
c4ac4b7538 Added copyright statement
[SVN r17222]
2003-02-05 08:38:32 +00:00
William E. Kempf
ff5d3b49ca Updated format (removed tabs) and added missing copyrights
[SVN r17214]
2003-02-04 23:23:02 +00:00
William E. Kempf
e101c878f0 Updated format (removed tabs) and added missing copyrights
[SVN r17213]
2003-02-04 23:08:28 +00:00
William E. Kempf
125193dcfa Turned all tests into 'timed_test's.
[SVN r17053]
2003-01-27 22:44:06 +00:00
Beman Dawes
77efa9810d Local include util.inl
[SVN r17041]
2003-01-25 14:23:36 +00:00
William E. Kempf
7f03d1917b Removed accidental sleep
[SVN r17035]
2003-01-24 18:15:22 +00:00
William E. Kempf
55b4ca9350 Added 'timed_test' support to prevent deadlocks in tests
[SVN r17032]
2003-01-24 16:51:13 +00:00
William E. Kempf
7196a0f9d2 Updated build files
[SVN r17021]
2003-01-23 23:23:36 +00:00
William E. Kempf
2caabde5ca Updated Jamfile to use test-suite
[SVN r17014]
2003-01-23 19:47:29 +00:00
Vladimir Prus
137d7663c1 Change use-requirements to usage-requirements in some library Jamfiles.
[SVN r16884]
2003-01-13 12:31:12 +00:00
Vladimir Prus
508b71a921 Update V2 Jamfile for Boost.
[SVN r16882]
2003-01-13 10:05:01 +00:00
Beman Dawes
5d90820005 fix bookmarks
[SVN r16827]
2003-01-09 13:37:41 +00:00
Beman Dawes
84727e90b1 fix invalid bookmarks
[SVN r16825]
2003-01-09 13:22:04 +00:00
William E. Kempf
9a1e3d3320 Added <boost/thread.hpp>.
[SVN r16796]
2003-01-08 15:08:32 +00:00
William E. Kempf
d33e0c8ee1 Fixed Unicode problem (CreateMutex - CreateMutexA)
[SVN r16770]
2003-01-06 16:06:37 +00:00
William E. Kempf
3332649480 Fixed bug in to_duration.
[SVN r16769]
2003-01-06 15:55:57 +00:00
William E. Kempf
c918b66199 Switched to a DLL implementation
[SVN r16742]
2003-01-03 21:03:43 +00:00
William E. Kempf
dbbf56e17a Updated to new test library name
[SVN r16732]
2003-01-02 16:26:03 +00:00
William E. Kempf
c77500c15a Updated Jamfile to remove unused code
[SVN r16725]
2002-12-30 23:14:30 +00:00
Dave Abrahams
75084aaa96 HP aCC workarounds
[SVN r16518]
2002-12-04 17:56:59 +00:00
William E. Kempf
35714c8f1c Added new tutorials
[SVN r16007]
2002-10-28 14:17:49 +00:00
67 changed files with 2405 additions and 1556 deletions

View File

@@ -1,17 +1,11 @@
# (C) Copyright William E. Kempf 2001. Permission to copy, use, modify, sell and # (C) Copyright William E. Kempf 2001. Permission to copy, use, modify,
# distribute this software is granted provided this copyright notice appears # sell and distribute this software is granted provided this copyright
# in all copies. This software is provided "as is" without express or implied # notice appears in all copies. This software is provided "as is" without
# warranty, and with no claim as to its suitability for any purpose. # express or implied warranty, and with no claim as to its suitability for
# any purpose.
# #
# Boost.Threads build Jamfile # Boost.Threads build Jamfile
# #
# Declares the following targets:
# 1. libboost_thread, a static link library.
# 1a. On Win32 (when PTW32 is not defined), a dynamic link library
# boost_threadmon, which must be used in conjunction with
# libboost_thread. Note that this DLL *must* be used through static
# linking to the import library. Dynamic loading will cause undefined
# behavior.
# Additional configuration variables used: # Additional configuration variables used:
# 1. PTW32 may be used on Win32 platforms to specify that the pthreads-win32 # 1. PTW32 may be used on Win32 platforms to specify that the pthreads-win32
# library should be used instead of "native" threads. This feature is # library should be used instead of "native" threads. This feature is
@@ -31,37 +25,29 @@ subproject libs/thread/build ;
SEARCH on <module@>threads.jam = $(SUBDIR) ; SEARCH on <module@>threads.jam = $(SUBDIR) ;
include <module@>threads.jam ; include <module@>threads.jam ;
template thread_libs
## sources ##
: <template>thread_base
## requirements ##
:
## default build ##
: debug release <runtime-link>static/dynamic
;
#######################
# Conditionally declare the Boost.Threads dynamic link library boost_threadmon.
if $(NT) && ! $(PTW32)
{ {
dll boost_threadmon : <template>thread_libs ../src/threadmon.cpp ; template thread_libs
## sources ##
: <template>thread_base
## requirements ##
:
## default build ##
: debug release
;
# Base names of the source files for libboost_thread.
CPP_SOURCES = condition mutex recursive_mutex thread tss xtime once
exceptions threadmon ;
dll boost_thread
: <template>thread_libs ../src/$(CPP_SOURCES).cpp
: <define>BOOST_THREAD_BUILD_DLL=1
;
stage bin-stage
: <dll>boost_thread
: #<tag><runtime-link-static>"s"
<tag><debug>"d"
: debug release
;
} }
#######################
# Declare the Boost.Threads static link library libboost_thread.
# Base names of the source files for libboost_thread.
CPP_SOURCES = condition mutex recursive_mutex thread tss xtime once exceptions ;
lib boost_thread : <template>thread_libs ../src/$(CPP_SOURCES).cpp ;
#######################
# Stage the generated targets.
#stage bin-stage
# : <lib>boost_thread $(threadmon)
# : <tag><runtime-link-static>"s"
# <tag><debug>"d"
# : debug release <runtime-link>static/dynamic
#;

View File

@@ -1,7 +1,10 @@
# Declare the uses system library
lib pthread : : <name>pthread ;
project boost/thread project boost/thread
: source-location ../src : source-location ../src
: use-requirements <find-library>pthread : usage-requirements <library>pthread
; ;
CPP_SOURCES = condition mutex recursive_mutex thread tss xtime once exceptions ; CPP_SOURCES = condition mutex recursive_mutex thread tss xtime once exceptions ;

View File

@@ -1,32 +1,29 @@
# Do some OS-specific setup # Do some OS-specific setup
threadmon = ;
pthreads-win32 = ;
if $(NT)
{ {
if $(PTW32) pthreads-win32 = ;
{
local install-path = $(PTW32[1]) ;
local lib = $(PTW32[2]) ;
pthreads-win32 =
<define>BOOST_HAS_PTHREADS
<define>PtW32NoCatchWarn
<include>$(install-path)/pre-built/include
<library-file>$(install-path)/pre-built/lib/$(lib)
;
}
else
{
threadmon = <dll>../build/boost_threadmon ;
}
}
template thread_base if $(NT)
## sources ## {
: if $(PTW32)
## requirements ## {
: <sysinclude>$(BOOST_ROOT) <threading>multi $(pthreads-win32) local install-path = $(PTW32[1]) ;
## default build ## local lib = $(PTW32[2]) ;
: pthreads-win32 =
; <define>BOOST_HAS_PTHREADS
<define>PtW32NoCatchWarn
<include>$(install-path)/pre-built/include
<library-file>$(install-path)/pre-built/lib/$(lib)
;
}
}
template thread_base
## sources ##
:
## requirements ##
: <sysinclude>$(BOOST_ROOT) <threading>multi $(pthreads-win32)
<borland><*><cxxflags>-w-8004
## default build ##
:
;
}

View File

@@ -27,8 +27,8 @@
Win32 implementation, especially in regards to boost::condition, as well as 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), 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 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 build to work on other platforms), Kevin S. Van Horn (for several updates/corrections
to the documentation).</p> to the documentation), and Martin Johnson (shared library implementation).</p>
<p>The documentation was written by William E. Kempf. Beman Dawes provided additional <p>The documentation was written by William E. Kempf. Beman Dawes provided additional
documentation material and editing.</p> documentation material and editing.</p>
<p>Discussions on the boost.org mailing list were essential in the development <p>Discussions on the boost.org mailing list were essential in the development

View File

@@ -61,10 +61,9 @@
states <a href="definitions.html#state"> blocked</a> and <a href="definitions.html#state">ready</a>. states <a href="definitions.html#state"> blocked</a> and <a href="definitions.html#state">ready</a>.
Note that &quot;waiting&quot; is a synonym for blocked.</p> Note that &quot;waiting&quot; is a synonym for blocked.</p>
<h4><a name="class-condition-synopsis"></a>Class <code>condition</code> synopsis</h4> <h4><a name="class-condition-synopsis"></a>Class <code>condition</code> synopsis</h4>
<pre> <pre>namespace boost
namespace boost
{ {
class condition : private <a href="../../utility/utility.htm#Class noncopyable">boost::noncopyable</a> // Exposition only. class condition : private <a href="../../utility/utility.htm#Class_noncopyable">boost::noncopyable</a> // Exposition only.
// Class condition meets the <a href="overview.html#non-copyable">NonCopyable</a> requirement. // Class condition meets the <a href="overview.html#non-copyable">NonCopyable</a> requirement.
{ {
public: public:
@@ -86,22 +85,19 @@ namespace boost
</pre> </pre>
<h4><a name="class-condition-ctors"></a>Class <code>condition</code> constructors <h4><a name="class-condition-ctors"></a>Class <code>condition</code> constructors
and destructor</h4> and destructor</h4>
<pre> <pre>condition();
condition();
</pre> </pre>
<dl class="function-semantics"> <dl class="function-semantics">
<dt><b>Effects:</b> Constructs a <code>condition</code> object.</dt> <dt><b>Effects:</b> Constructs a <code>condition</code> object.</dt>
</dl> </dl>
<pre> <pre>~condition();
~condition();
</pre> </pre>
<dl class="function-semantics"> <dl class="function-semantics">
<dt><b>Effects:</b> Destroys <code>*this</code>.</dt> <dt><b>Effects:</b> Destroys <code>*this</code>.</dt>
</dl> </dl>
<h4><a name="class-condition-modifiers"></a>Class <code>condition</code> modifier <h4><a name="class-condition-modifiers"></a>Class <code>condition</code> modifier
functions</h4> functions</h4>
<pre> <pre>void notify_one();
void notify_one();
</pre> </pre>
<dl class="function-semantics"> <dl class="function-semantics">
<dt><b>Effects:</b> If there is a thread waiting on <code>*this</code>, change <dt><b>Effects:</b> If there is a thread waiting on <code>*this</code>, change
@@ -111,16 +107,14 @@ void notify_one();
thread must still acquire the mutex again (which occurs within the call to thread must still acquire the mutex again (which occurs within the call to
one of the <code>condition</code> object's wait functions).</dt> one of the <code>condition</code> object's wait functions).</dt>
</dl> </dl>
<pre> <pre>void notify_all();
void notify_all();
</pre> </pre>
<dl class="function-semantics"> <dl class="function-semantics">
<dt><b>Effects:</b> Change the state of all threads waiting on <code> *this</code> <dt><b>Effects:</b> Change the state of all threads waiting on <code> *this</code>
to ready. If there are no waiting threads, <code> notify_all()</code> has to ready. If there are no waiting threads, <code> notify_all()</code> has
no effect.</dt> no effect.</dt>
</dl> </dl>
<pre> <pre>template &lt;typename ScopedLock&gt;
template &lt;typename ScopedLock&gt;
void wait(ScopedLock&amp; lock); void wait(ScopedLock&amp; lock);
</pre> </pre>
<dl class="function-semantics"> <dl class="function-semantics">
@@ -138,8 +132,7 @@ template &lt;typename ScopedLock&gt;
wake ups&quot;. The second version encapsulates this loop idiom internally wake ups&quot;. The second version encapsulates this loop idiom internally
and is generally the preferred method.</dt> and is generally the preferred method.</dt>
</dl> </dl>
<pre> <pre>Template&lt;typename ScopedLock, typename Pr&gt;
Template&lt;typename ScopedLock, typename Pr&gt;
void wait(ScopedLock&amp; lock, Pr pred); void wait(ScopedLock&amp; lock, Pr pred);
</pre> </pre>
<dl class="function-semantics"> <dl class="function-semantics">
@@ -149,8 +142,7 @@ Template&lt;typename ScopedLock, typename Pr&gt;
<dt><b>Throws:</b> <code><a href="exceptions.html#class-lock_error">lock_error</a></code> <dt><b>Throws:</b> <code><a href="exceptions.html#class-lock_error">lock_error</a></code>
if <code>!lock.locked()</code></dt> if <code>!lock.locked()</code></dt>
</dl> </dl>
<pre> <pre>template &lt;typename ScopedLock&gt;
template &lt;typename ScopedLock&gt;
bool timed_wait(ScopedLock&amp; lock, const <a href="xtime.html">xtime</a>&amp; XT); bool timed_wait(ScopedLock&amp; lock, const <a href="xtime.html">xtime</a>&amp; XT);
</pre> </pre>
<dl class="function-semantics"> <dl class="function-semantics">
@@ -171,16 +163,14 @@ template &lt;typename ScopedLock&gt;
ups&quot;. The second version encapsulates this loop idiom internally and ups&quot;. The second version encapsulates this loop idiom internally and
is generally the preferred method.</dt> is generally the preferred method.</dt>
</dl> </dl>
<pre> <pre>Template&lt;typename ScopedLock, typename Pr&gt;
Template&lt;typename ScopedLock, typename Pr&gt;
bool timed_wait(ScopedLock&amp; lock, const <a href="xtime.html">xtime</a>&amp; XT, Pr pred); bool timed_wait(ScopedLock&amp; lock, const <a href="xtime.html">xtime</a>&amp; XT, Pr pred);
</pre> </pre>
<dl class="function-semantics"> <dl class="function-semantics">
<dt><b>Requires:</b> <code>ScopedLock</code> meets the <a href="lock_concept.html#ScopedLock">ScopedLock</a> <dt><b>Requires:</b> <code>ScopedLock</code> meets the <a href="lock_concept.html#ScopedLock">ScopedLock</a>
requirements, return from <code>pred()</code> convertible to bool.</dt> requirements, return from <code>pred()</code> convertible to bool.</dt>
<dt><b>Effects:</b> As if:<br> <dt><b>Effects:</b> As if:<br>
<pre> <pre>while (!pred())
while (!pred())
{ {
if (!timed_wait(lock, XT)) if (!timed_wait(lock, XT))
return false; return false;
@@ -196,8 +186,7 @@ return true;
<h2><a name="examples"></a>Example(s)</h2> <h2><a name="examples"></a>Example(s)</h2>
<p><a href="../example/condition.cpp">libs/thread/example/condition.cpp</a></p> <p><a href="../example/condition.cpp">libs/thread/example/condition.cpp</a></p>
<p>Typical output (dependent on scheduling policies) is:</p> <p>Typical output (dependent on scheduling policies) is:</p>
<pre> <pre>sent: 0
sent: 0
sent: 1 sent: 1
received: 0 received: 0
received: 1 received: 1
@@ -209,9 +198,7 @@ sent: 4
received: 4 received: 4
</pre> </pre>
<p>Revised <p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->09 January, 2003<!--webbot bot="Timestamp" endspan i-checksum="38582" -->
05 November, 2001
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p> </p>
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002. <p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
All Rights Reserved.</i></p> All Rights Reserved.</i></p>
@@ -222,4 +209,4 @@ received: 4
makes no representations about the suitability of this software for any purpose. makes no representations about the suitability of this software for any purpose.
It is provided &quot;as is&quot; without express or implied warranty.</p> It is provided &quot;as is&quot; without express or implied warranty.</p>
</body> </body>
</html> </html>

View File

@@ -86,8 +86,7 @@
"definitions.html#Thread-safe">thread-safe</a>. The following is a simple "definitions.html#Thread-safe">thread-safe</a>. The following is a simple
example of a class with copyable semantics and internal synchronization through example of a class with copyable semantics and internal synchronization through
a mutex member.</p> a mutex member.</p>
<pre> <pre>class counter
class counter
{ {
public: public:
// Doesn't need synchronization since there can be no references to *this // Doesn't need synchronization since there can be no references to *this
@@ -145,8 +144,8 @@ private:
a mutex member as mutable clearly documents the intended semantics.</p> a mutex member as mutable clearly documents the intended semantics.</p>
<h2><a name="question7"></a>7. Why supply <a href="condition.html">condition variables</a> <h2><a name="question7"></a>7. Why supply <a href="condition.html">condition variables</a>
rather than <a href="rationale.html#Events">event variables</a>?</h2> rather than <a href="rationale.html#Events">event variables</a>?</h2>
<p>Condition variables result in user code much less prone to <a href= <p>Condition variables result in user code much less prone to
"definitions.html#Race condition">race conditions</a> than event variables. <a href="definitions.html#definition-race-condition">race conditions</a> than event variables.
See <a href="rationale.html#Events">Rationale</a> for analysis. Also see <a href="bibliography.html#Hoare-74">[Hoare See <a href="rationale.html#Events">Rationale</a> for analysis. Also see <a href="bibliography.html#Hoare-74">[Hoare
74]</a> and <a href="bibliography.html#Schmidt-00">[Schmidt 00]</a>.</p> 74]</a> and <a href="bibliography.html#Schmidt-00">[Schmidt 00]</a>.</p>
<h2><a name="question8"></a>8. Why isn&#39;t thread cancellation or termination <h2><a name="question8"></a>8. Why isn&#39;t thread cancellation or termination
@@ -167,9 +166,7 @@ private:
greater safety by the combination of a mutex and a condition variable.</p> greater safety by the combination of a mutex and a condition variable.</p>
<hr> <hr>
<p>Revised <p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->09 January, 2003<!--webbot bot="Timestamp" endspan i-checksum="38582" -->
05 November, 2001
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p> </p>
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002. <p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
All Rights Reserved.</i></p> All Rights Reserved.</i></p>
@@ -180,4 +177,4 @@ private:
makes no representations about the suitability of this software for any purpose. makes no representations about the suitability of this software for any purpose.
It is provided &quot;as is&quot; without express or implied warranty.</p> It is provided &quot;as is&quot; without express or implied warranty.</p>
</body> </body>
</html> </html>

View File

@@ -145,7 +145,7 @@
<p>A Mutex object has two states: locked and unlocked. Mutex object state can <p>A Mutex object has two states: locked and unlocked. Mutex object state can
only be determined by an object meeting the <a href="lock_concept.html#ScopedLock">ScopedLock</a> only be determined by an object meeting the <a href="lock_concept.html#ScopedLock">ScopedLock</a>
requirements and constructed for the Mutex object.</p> requirements and constructed for the Mutex object.</p>
<p>A Mutex is <a href="../../utility/utility.htm#Class noncopyable">NonCopyable</a>.</p> <p>A Mutex is <a href="../../utility/utility.htm#Class_noncopyable">NonCopyable</a>.</p>
<p>For a Mutex type M and an object m of that type, the following expressions <p>For a Mutex type M and an object m of that type, the following expressions
must be well-formed and have the indicated effects.</p> must be well-formed and have the indicated effects.</p>
<table summary="Mutex expressions" border="1" cellpadding="5"> <table summary="Mutex expressions" border="1" cellpadding="5">
@@ -223,9 +223,7 @@
</table> </table>
<hr> <hr>
<p>Revised <p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->09 January, 2003<!--webbot bot="Timestamp" endspan i-checksum="38582" -->
05 November, 2001
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p> </p>
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002. <p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
All Rights Reserved.</i></p> All Rights Reserved.</i></p>
@@ -236,4 +234,4 @@
makes no representations about the suitability of this software for any purpose. makes no representations about the suitability of this software for any purpose.
It is provided &quot;as is&quot; without express or implied warranty.</p> It is provided &quot;as is&quot; without express or implied warranty.</p>
</body> </body>
</html> </html>

View File

@@ -110,7 +110,8 @@
<p><b>Warning:</b> Multithreaded programs such as those using <b> Boost.Threads</b> <p><b>Warning:</b> Multithreaded programs such as those using <b> Boost.Threads</b>
must link to <a href="definitions.html#Thread-safe"> thread-safe</a> versions must link to <a href="definitions.html#Thread-safe"> thread-safe</a> versions
of all runtime libraries used by the program, including the runtime library of all runtime libraries used by the program, including the runtime library
for the C++ Standard Library. Otherwise <a href="definitions.html#Race condition">race for the C++ Standard Library. Otherwise
<a href="definitions.html#definition-race-condition">race
conditions</a> will occur when multiple threads simultaneously execute runtime conditions</a> will occur when multiple threads simultaneously execute runtime
library functions for <i>new</i>, <i>delete</i>, or other language features library functions for <i>new</i>, <i>delete</i>, or other language features
which imply shared state.</p> which imply shared state.</p>
@@ -157,9 +158,7 @@
as implementations are free to meet the NonCopyable requirement in other ways.</p> as implementations are free to meet the NonCopyable requirement in other ways.</p>
<hr> <hr>
<p>Revised <p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->09 January, 2003<!--webbot bot="Timestamp" endspan i-checksum="38582" -->
05 November, 2001
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p> </p>
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002. <p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
All Rights Reserved.</i></p> All Rights Reserved.</i></p>
@@ -170,4 +169,4 @@
makes no representations about the suitability of this software for any purpose. makes no representations about the suitability of this software for any purpose.
It is provided &quot;as is&quot; without express or implied warranty.</p> It is provided &quot;as is&quot; without express or implied warranty.</p>
</body> </body>
</html> </html>

View File

@@ -144,31 +144,27 @@
appear to bear them out. To illustrate the analysis we&#39;ll first provide appear to bear them out. To illustrate the analysis we&#39;ll first provide
pseudo-code illustrating the six typical usage patterns of a thread object.</p> pseudo-code illustrating the six typical usage patterns of a thread object.</p>
<h3>1. Simple creation of a thread.</h3> <h3>1. Simple creation of a thread.</h3>
<pre> <pre>void foo()
void foo()
{ {
create_thread(&amp;bar); create_thread(&amp;bar);
} }
</pre> </pre>
<h3>2. Creation of a thread that's later joined.</h3> <h3>2. Creation of a thread that's later joined.</h3>
<pre> <pre>Void foo()
Void foo()
{ {
thread = create_thread(&amp;bar); thread = create_thread(&amp;bar);
join(thread); join(thread);
} }
</pre> </pre>
<h3>3. Simple creation of several threads in a loop.</h3> <h3>3. Simple creation of several threads in a loop.</h3>
<pre> <pre>Void foo()
Void foo()
{ {
for (int i=0; i&lt;NUM_THREADS; ++i) for (int i=0; i&lt;NUM_THREADS; ++i)
create_thread(&amp;bar); create_thread(&amp;bar);
} }
</pre> </pre>
<h3>4. Creation of several threads in a loop which are later joined.</h3> <h3>4. Creation of several threads in a loop which are later joined.</h3>
<pre> <pre>Void foo()
Void foo()
{ {
for (int i=0; i&lt;NUM_THREADS; ++i) for (int i=0; i&lt;NUM_THREADS; ++i)
threads[i] = create_thread(&amp;bar); threads[i] = create_thread(&amp;bar);
@@ -177,16 +173,14 @@ Void foo()
} }
</pre> </pre>
<h3>5. Creation of a thread whose ownership is passed to another object/method.</h3> <h3>5. Creation of a thread whose ownership is passed to another object/method.</h3>
<pre> <pre>Void foo()
Void foo()
{ {
thread = create_thread(&amp;bar); thread = create_thread(&amp;bar);
manager.owns(thread); manager.owns(thread);
} }
</pre> </pre>
<h3>6. Creation of a thread whose ownership is shared between multiple objects.</h3> <h3>6. Creation of a thread whose ownership is shared between multiple objects.</h3>
<pre> <pre>Void foo()
Void foo()
{ {
thread = create_thread(&amp;bar); thread = create_thread(&amp;bar);
manager1.add(thread); manager1.add(thread);
@@ -211,8 +205,7 @@ Void foo()
for any of the usage patterns there would be a good argument for choosing the for any of the usage patterns there would be a good argument for choosing the
other design. So we&#39;ll code all six usage patterns using both designs.</p> other design. So we&#39;ll code all six usage patterns using both designs.</p>
<h3>1.</h3> <h3>1.</h3>
<pre> <pre>void foo()
void foo()
{ {
thread thrd(&amp;bar); thread thrd(&amp;bar);
} }
@@ -223,8 +216,7 @@ void foo()
} }
</pre> </pre>
<h3>2.</h3> <h3>2.</h3>
<pre> <pre>void foo()
void foo()
{ {
thread thrd(&amp;bar); thread thrd(&amp;bar);
thrd.join(); thrd.join();
@@ -237,8 +229,7 @@ void foo()
} }
</pre> </pre>
<h3>3.</h3> <h3>3.</h3>
<pre> <pre>void foo()
void foo()
{ {
for (int i=0; i&lt;NUM_THREADS; ++i) for (int i=0; i&lt;NUM_THREADS; ++i)
thread thrd(&amp;bar); thread thrd(&amp;bar);
@@ -251,8 +242,7 @@ void foo()
} }
</pre> </pre>
<h3>4.</h3> <h3>4.</h3>
<pre> <pre>void foo()
void foo()
{ {
std::auto_ptr&lt;thread&gt; threads[NUM_THREADS]; std::auto_ptr&lt;thread&gt; threads[NUM_THREADS];
for (int i=0; i&lt;NUM_THREADS; ++i) for (int i=0; i&lt;NUM_THREADS; ++i)
@@ -271,8 +261,7 @@ void foo()
} }
</pre> </pre>
<h3>5.</h3> <h3>5.</h3>
<pre> <pre>void foo()
void foo()
{ {
thread thrd* = new thread(&amp;bar); thread thrd* = new thread(&amp;bar);
manager.owns(thread); manager.owns(thread);
@@ -285,8 +274,7 @@ void foo()
} }
</pre> </pre>
<h3>6.</h3> <h3>6.</h3>
<pre> <pre>void foo()
void foo()
{ {
boost::shared_ptr&lt;thread&gt; thrd(new thread(&amp;bar)); boost::shared_ptr&lt;thread&gt; thrd(new thread(&amp;bar));
manager1.add(thrd); manager1.add(thrd);
@@ -308,8 +296,7 @@ void foo()
the presence of operator new in user code, but this can be eliminated by proper 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 design of higher level concepts, such as the boost::thread_group class that
simplifies example (4) down to:</p> simplifies example (4) down to:</p>
<pre> <pre>void foo()
void foo()
{ {
thread_group threads; thread_group threads;
for (int i=0; i&lt;NUM_THREADS; ++i) for (int i=0; i&lt;NUM_THREADS; ++i)
@@ -366,8 +353,7 @@ void foo()
variables are a continuing source of errors, even after previous bad experiences 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 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 can be avoided, for example, by teaming the event variable with a mutex, but
that may just convert a <a href= that may just convert a <a href="definitions.html#definition-race-condition">race condition</a> into another problem,
"definitions.html#Race condition">race condition</a> into another problem,
such as excessive resource use. One of the most distressing aspects of the experience 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 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 work correctly, but contain hidden timing dependencies which will cause them
@@ -383,9 +369,7 @@ void foo()
<p>[Rationale provided by Beman Dawes]</p> <p>[Rationale provided by Beman Dawes]</p>
<hr> <hr>
<p>Revised <p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->09 January, 2003<!--webbot bot="Timestamp" endspan i-checksum="38582" -->
05 November, 2001
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p> </p>
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002. <p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
All Rights Reserved.</i></p> All Rights Reserved.</i></p>
@@ -396,4 +380,4 @@ void foo()
makes no representations about the suitability of this software for any purpose. makes no representations about the suitability of this software for any purpose.
It is provided &quot;as is&quot; without express or implied warranty.</p> It is provided &quot;as is&quot; without express or implied warranty.</p>
</body> </body>
</html> </html>

View File

@@ -85,10 +85,8 @@
having first been called, the thread of execution continues until its initial having first been called, the thread of execution continues until its initial
function completes.</p> function completes.</p>
<h4><a name="class-thread-synopsis"></a>Class <code>thread</code> synopsis</h4> <h4><a name="class-thread-synopsis"></a>Class <code>thread</code> synopsis</h4>
<pre> <pre>namespace boost {
namespace boost { class thread : <a href="../../utility/utility.htm#Class_noncopyable">boost::noncopyable</a> // Exposition only.
class thread : <a href=
"../../utility/utility.htm#Class noncopyable">boost::noncopyable</a> // Exposition only.
// Class thread meets the <a href= // Class thread meets the <a href=
"overview.html#non-copyable">NonCopyable</a> requirement. "overview.html#non-copyable">NonCopyable</a> requirement.
{ {
@@ -109,8 +107,7 @@ public:
</pre> </pre>
<h4><a name="class-thread-ctors"></a>Class <code>thread</code> constructors and <h4><a name="class-thread-ctors"></a>Class <code>thread</code> constructors and
destructor</h4> destructor</h4>
<pre> <pre>thread();
thread();
</pre> </pre>
<dl class="function-semantics"> <dl class="function-semantics">
<dt><b>Effects:</b> Constructs a <code>thread</code> object representing the <dt><b>Effects:</b> Constructs a <code>thread</code> object representing the
@@ -118,8 +115,7 @@ thread();
<dt><b>Postconditions:</b> <code>*this</code> is non-joinable.</dt> <dt><b>Postconditions:</b> <code>*this</code> is non-joinable.</dt>
<dt><b>Danger:</b> <code>*this</code> is valid only within the current thread.</dt> <dt><b>Danger:</b> <code>*this</code> is valid only within the current thread.</dt>
</dl> </dl>
<pre> <pre>thread(const <a href="../../function/index.html">boost::function0</a>&lt;void&gt;&amp; threadfunc);
thread(const <a href="../../function/index.html">boost::function0</a>&lt;void&gt;&amp; threadfunc);
</pre> </pre>
<dl class="function-semantics"> <dl class="function-semantics">
<dt><b>Effects:</b> Starts a new thread of execution and constructs a <code>thread</code> <dt><b>Effects:</b> Starts a new thread of execution and constructs a <code>thread</code>
@@ -132,8 +128,7 @@ thread(const <a href="../../function/index.html">boost::function0</a>&lt;void&gt
<dt><b>Throws:</b> <code>boost::thread_resource_error</code> if a new thread <dt><b>Throws:</b> <code>boost::thread_resource_error</code> if a new thread
of execution cannot be started.</dt> of execution cannot be started.</dt>
</dl> </dl>
<pre> <pre>~Thread();
~Thread();
</pre> </pre>
<dl class="function-semantics"> <dl class="function-semantics">
<dt><b>Effects:</b> Destroys <code>*this</code>. The actual thread of execution <dt><b>Effects:</b> Destroys <code>*this</code>. The actual thread of execution
@@ -146,24 +141,21 @@ thread(const <a href="../../function/index.html">boost::function0</a>&lt;void&gt
</dl> </dl>
<h4><a name="class-thread-comparisons"></a>Class <code>thread</code> comparison <h4><a name="class-thread-comparisons"></a>Class <code>thread</code> comparison
functions</h4> functions</h4>
<pre> <pre>bool operator==(const thread&amp; rhs) const;
bool operator==(const thread&amp; rhs) const;
</pre> </pre>
<dl class="function-semantics"> <dl class="function-semantics">
<dt><b>Requires:</b> The thread is non-terminated or <code>*this</code> is joinable.</dt> <dt><b>Requires:</b> The thread is non-terminated or <code>*this</code> is joinable.</dt>
<dt><b>Returns:</b> <code>true</code> if <code>*this</code> and <code> rhs</code> <dt><b>Returns:</b> <code>true</code> if <code>*this</code> and <code> rhs</code>
represent the same thread of execution.</dt> represent the same thread of execution.</dt>
</dl> </dl>
<pre> <pre>bool operator!=(const thread&amp; rhs) const;
bool operator!=(const thread&amp; rhs) const;
</pre> </pre>
<dl class="function-semantics"> <dl class="function-semantics">
<dt><b>Requires:</b> The thread is non-terminated or <code>*this</code> is joinable.</dt> <dt><b>Requires:</b> The thread is non-terminated or <code>*this</code> is joinable.</dt>
<dt><b>Returns:</b> <code>!(*this==rhs)</code>.</dt> <dt><b>Returns:</b> <code>!(*this==rhs)</code>.</dt>
</dl> </dl>
<h4><a name="class-thread-modifiers"></a>Class <code>thread</code> modifier functions</h4> <h4><a name="class-thread-modifiers"></a>Class <code>thread</code> modifier functions</h4>
<pre> <pre>void join();
void join();
</pre> </pre>
<dl class="function-semantics"> <dl class="function-semantics">
<dt><b>Requires:</b> <code>*this</code> is joinable.</dt> <dt><b>Requires:</b> <code>*this</code> is joinable.</dt>
@@ -176,15 +168,13 @@ void join();
<a href="definitions.html#Deadlock"> deadlock</a>.</dt> <a href="definitions.html#Deadlock"> deadlock</a>.</dt>
</dl> </dl>
<h4><a name="class-thread-statics"></a>Class <code>thread</code> static functions</h4> <h4><a name="class-thread-statics"></a>Class <code>thread</code> static functions</h4>
<pre> <pre>static void sleep(const <a href="xtime.html">xtime</a>&amp; XT);
static void sleep(const <a href="xtime.html">xtime</a>&amp; XT);
</pre> </pre>
<dl class="function-semantics"> <dl class="function-semantics">
<dt><b>Effects:</b> The current thread of execution blocks until <code> XT</code> <dt><b>Effects:</b> The current thread of execution blocks until <code> XT</code>
is reached.</dt> is reached.</dt>
</dl> </dl>
<pre> <pre>static void yield();
static void yield();
</pre> </pre>
<dl class="function-semantics"> <dl class="function-semantics">
<dt><b>Effects:</b> The current thread of execution is placed in the &quot;ready&quot; <dt><b>Effects:</b> The current thread of execution is placed in the &quot;ready&quot;
@@ -200,10 +190,9 @@ static void yield();
"definitions.html#thread-safe">thread-safe</a>, except destruction.</p> "definitions.html#thread-safe">thread-safe</a>, except destruction.</p>
<h4><a name="class-thread_group-synopsis"></a>Class <code>thread_group</code> <h4><a name="class-thread_group-synopsis"></a>Class <code>thread_group</code>
synopsis</h4> synopsis</h4>
<pre> <pre>namespace boost {
namespace boost {
class thread_group : <a href= class thread_group : <a href=
"../../utility/utility.htm#Class noncopyable">boost::noncopyable</a> "../../utility/utility.htm#Class_noncopyable">boost::noncopyable</a>
{ {
public: public:
thread_group(); thread_group();
@@ -218,14 +207,12 @@ namespace boost {
</pre> </pre>
<h4><a name="class-thread_group-ctors"></a>Class <code>thread_group</code> constructors <h4><a name="class-thread_group-ctors"></a>Class <code>thread_group</code> constructors
and destructor</h4> and destructor</h4>
<pre> <pre>thread_group();
thread_group();
</pre> </pre>
<dl class="function-semantics"> <dl class="function-semantics">
<dt><b>Effects:</b> Constructs an empty <code>thread_group</code> container.</dt> <dt><b>Effects:</b> Constructs an empty <code>thread_group</code> container.</dt>
</dl> </dl>
<pre> <pre>~thread_group();
~thread_group();
</pre> </pre>
<dl class="function-semantics"> <dl class="function-semantics">
<dt><b>Effects:</b> Destroys each contained thread object. Destroys <code>*this</code>.</dt> <dt><b>Effects:</b> Destroys each contained thread object. Destroys <code>*this</code>.</dt>
@@ -234,8 +221,7 @@ thread_group();
</dl> </dl>
<h4><a name="class-thread_group-modifiers"></a>Class <code>thread_group</code> <h4><a name="class-thread_group-modifiers"></a>Class <code>thread_group</code>
modifier functions</h4> modifier functions</h4>
<pre> <pre>thread* create_thread(const boost::function0&lt;void&gt;&amp; threadfunc);
thread* create_thread(const boost::function0&lt;void&gt;&amp; threadfunc);
</pre> </pre>
<dl class="function-semantics"> <dl class="function-semantics">
<dt><b>Effects:</b> Creates a new <tt>thread</tt> object that executes <tt>threadfunc</tt> <dt><b>Effects:</b> Creates a new <tt>thread</tt> object that executes <tt>threadfunc</tt>
@@ -243,16 +229,14 @@ thread* create_thread(const boost::function0&lt;void&gt;&amp; threadfunc);
<tt>thread</tt> objects.</dt> <tt>thread</tt> objects.</dt>
<dt><b>Returns:</b> Pointer to the newly created thread.</dt> <dt><b>Returns:</b> Pointer to the newly created thread.</dt>
</dl> </dl>
<pre> <pre>void add_thread(thread* thrd);
void add_thread(thread* thrd);
</pre> </pre>
<dl class="function-semantics"> <dl class="function-semantics">
<dt><b>Effects:</b> Adds <tt>thrd</tt> to the <tt>thread_group</tt> object&#39;s <dt><b>Effects:</b> Adds <tt>thrd</tt> to the <tt>thread_group</tt> object&#39;s
list of managed <tt>thread</tt> objects. The <tt>thrd</tt> object must have list of managed <tt>thread</tt> objects. The <tt>thrd</tt> object must have
been allocated via operator new and will be deleted when the group is destroyed.</dt> been allocated via operator new and will be deleted when the group is destroyed.</dt>
</dl> </dl>
<pre> <pre>Void remove_thread(thread* thrd);
Void remove_thread(thread* thrd);
</pre> </pre>
<dl class="function-semantics"> <dl class="function-semantics">
<dt><b>Effects:</b> Removes <code>*this</code>&#39;s list of managed <tt>thread</tt> <dt><b>Effects:</b> Removes <code>*this</code>&#39;s list of managed <tt>thread</tt>
@@ -260,16 +244,14 @@ Void remove_thread(thread* thrd);
<dt><b>Throws:</b> ? if <tt>thrd</tt> is not it <code>*this</code>&#39;s list <dt><b>Throws:</b> ? if <tt>thrd</tt> is not it <code>*this</code>&#39;s list
of managed <tt>thread</tt> objects.</dt> of managed <tt>thread</tt> objects.</dt>
</dl> </dl>
<pre> <pre>Void join_all();
Void join_all();
</pre> </pre>
<dl class="function-semantics"> <dl class="function-semantics">
<dt><b>Effects:</b> Calls <code>join()</code> on each of the managed <tt>thread</tt> <dt><b>Effects:</b> Calls <code>join()</code> on each of the managed <tt>thread</tt>
objects.</dt> objects.</dt>
</dl> </dl>
<h2><a name="functions"></a>Functions</h2> <h2><a name="functions"></a>Functions</h2>
<pre> <pre><a name="function-spec"></a>{{function}}
<a name="function-spec"></a>{{function}}
</pre> </pre>
<dl class="function-semantics"> <dl class="function-semantics">
<dt><b>Requires:</b> {{text}}</dt> <dt><b>Requires:</b> {{text}}</dt>
@@ -286,15 +268,13 @@ Void join_all();
<h3><a name="example-thread"></a>Simple usage of <code>boost::thread</code></h3> <h3><a name="example-thread"></a>Simple usage of <code>boost::thread</code></h3>
<p><a href="../example/thread.cpp">libs/thread/example/thread.cpp</a></p> <p><a href="../example/thread.cpp">libs/thread/example/thread.cpp</a></p>
<p>The output is:</p> <p>The output is:</p>
<pre> <pre>setting alarm for 5 seconds...
setting alarm for 5 seconds...
alarm sounded... alarm sounded...
</pre> </pre>
<h3><a name="example-thread_group"></a>Simple usage of <code>boost::thread_group</code></h3> <h3><a name="example-thread_group"></a>Simple usage of <code>boost::thread_group</code></h3>
<p><a href="../example/thread_group.cpp">libs/thread/example/thread_group.cpp</a></p> <p><a href="../example/thread_group.cpp">libs/thread/example/thread_group.cpp</a></p>
<p>The output is:</p> <p>The output is:</p>
<pre> <pre>count = 1
count = 1
count = 2 count = 2
count = 3 count = 3
count = 4 count = 4
@@ -307,9 +287,7 @@ count = 10
</pre> </pre>
<hr> <hr>
<p>Revised <p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->09 January, 2003<!--webbot bot="Timestamp" endspan i-checksum="38582" -->
05 November, 2001
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p> </p>
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002. <p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
All Rights Reserved.</i></p> All Rights Reserved.</i></p>
@@ -320,4 +298,4 @@ count = 10
makes no representations about the suitability of this software for any purpose. makes no representations about the suitability of this software for any purpose.
It is provided &quot;as is&quot; without express or implied warranty.</p> It is provided &quot;as is&quot; without express or implied warranty.</p>
</body> </body>
</html> </html>

View File

@@ -1,7 +1,19 @@
# (C) Copyright William E. Kempf 2001. Permission to copy, use, modify, sell and # (C) Copyright William E. Kempf 2001. Permission to copy, use, modify, sell
# distribute this software is granted provided this copyright notice appears # and distribute this software is granted provided this copyright notice
# in all copies. This software is provided "as is" without express or implied # appears in all copies. This software is provided "as is" without express or
# warranty, and with no claim as to its suitability for any purpose. # implied warranty, and with no claim as to its suitability for any purpose.
#
# Boost.Threads example Jamfile
#
# Additional configuration variables used:
# 1. PTW32 may be used on Win32 platforms to specify that the pthreads-win32
# library should be used instead of "native" threads. This feature is
# mostly used for testing and it's generally recommended you use the
# native threading libraries instead. PTW32 should be set to be a list
# of two strings, the first specifying the installation path of the
# pthreads-win32 library and the second specifying which library
# variant to link against (see the pthreads-win32 documentation).
# Example: jam -sPTW32="c:\pthreads-win32 pthreadVCE.lib"
# Declare the location of this subproject relative to the root. # Declare the location of this subproject relative to the root.
subproject libs/thread/example ; subproject libs/thread/example ;
@@ -12,23 +24,26 @@ subproject libs/thread/example ;
SEARCH on <module@>threads.jam = $(BOOST_ROOT)/libs/thread/build ; SEARCH on <module@>threads.jam = $(BOOST_ROOT)/libs/thread/build ;
include <module@>threads.jam ; include <module@>threads.jam ;
template example {
## sources ## template example
: <template>thread_base <lib>../build/boost_thread <lib>../../test/build/unit_test_framework $(threadmon) ## sources ##
## requirements ## : <template>thread_base
: <dll>../build/boost_thread
## default build ## ## requirements ##
: release <runtime-link>static :
; ## default build ##
:
;
exe monitor : <template>example monitor.cpp ; exe monitor : <template>example monitor.cpp ;
exe starvephil : <template>example starvephil.cpp ; exe starvephil : <template>example starvephil.cpp ;
exe tennis : <template>example tennis.cpp ; exe tennis : <template>example tennis.cpp ;
exe condition : <template>example condition.cpp ; exe condition : <template>example condition.cpp ;
exe mutex : <template>example mutex.cpp ; exe mutex : <template>example mutex.cpp ;
exe once : <template>example once.cpp ; exe once : <template>example once.cpp ;
exe recursive_mutex : <template>example recursive_mutex.cpp ; exe recursive_mutex : <template>example recursive_mutex.cpp ;
exe thread : <template>example thread.cpp ; exe thread : <template>example thread.cpp ;
exe thread_group : <template>example thread_group.cpp ; exe thread_group : <template>example thread_group.cpp ;
exe tss : <template>example tss.cpp ; exe tss : <template>example tss.cpp ;
exe xtime : <template>example xtime.cpp ; exe xtime : <template>example xtime.cpp ;
}

View File

@@ -1,3 +1,14 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <iostream> #include <iostream>
#include <vector> #include <vector>
#include <boost/utility.hpp> #include <boost/utility.hpp>
@@ -43,9 +54,9 @@ bounded_buffer buf(2);
void sender() { void sender() {
int n = 0; int n = 0;
while (n < 100) { while (n < 100) {
buf.send(n); buf.send(n);
std::cout << "sent: " << n << std::endl; std::cout << "sent: " << n << std::endl;
++n; ++n;
} }
buf.send(-1); buf.send(-1);
} }
@@ -53,8 +64,8 @@ void sender() {
void receiver() { void receiver() {
int n; int n;
do { do {
n = buf.receive(); n = buf.receive();
std::cout << "received: " << n << std::endl; std::cout << "received: " << n << std::endl;
} while (n != -1); // -1 indicates end of buffer } while (n != -1); // -1 indicates end of buffer
} }

View File

@@ -1,3 +1,14 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <vector> #include <vector>
#include <iostream> #include <iostream>
#include <boost/thread/condition.hpp> #include <boost/thread/condition.hpp>
@@ -6,9 +17,11 @@
#include <boost/thread/thread.hpp> #include <boost/thread/thread.hpp>
namespace { namespace {
const int ITERS = 100;
boost::mutex io_mutex; const int ITERS = 100;
} boost::mutex io_mutex;
} // namespace
template <typename M> template <typename M>
class buffer_t class buffer_t

View File

@@ -1,3 +1,14 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/mutex.hpp> #include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp> #include <boost/thread/thread.hpp>
#include <iostream> #include <iostream>

View File

@@ -1,3 +1,14 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/thread.hpp> #include <boost/thread/thread.hpp>
#include <boost/thread/once.hpp> #include <boost/thread/once.hpp>
#include <cassert> #include <cassert>
@@ -12,14 +23,14 @@ void init()
void thread_proc() void thread_proc()
{ {
boost::call_once(&init, once); boost::call_once(&init, once);
} }
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
boost::thread_group threads; boost::thread_group threads;
for (int i=0; i<5; ++i) for (int i=0; i<5; ++i)
threads.create_thread(&thread_proc); threads.create_thread(&thread_proc);
threads.join_all(); threads.join_all();
assert(value == 1); assert(value == 1);
} }

View File

@@ -1,3 +1,14 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/recursive_mutex.hpp> #include <boost/thread/recursive_mutex.hpp>
#include <boost/thread/thread.hpp> #include <boost/thread/thread.hpp>
#include <iostream> #include <iostream>

View File

@@ -1,3 +1,14 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/mutex.hpp> #include <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp> #include <boost/thread/condition.hpp>
#include <boost/thread/thread.hpp> #include <boost/thread/thread.hpp>
@@ -5,9 +16,10 @@
#include <iostream> #include <iostream>
#include <time.h> #include <time.h>
namespace namespace {
{
boost::mutex iomx; boost::mutex iomx;
} }
class canteen class canteen
@@ -39,8 +51,9 @@ public:
boost::mutex::scoped_lock lock(m_mutex); boost::mutex::scoped_lock lock(m_mutex);
{ {
boost::mutex::scoped_lock lock(iomx); boost::mutex::scoped_lock lock(iomx);
std::cout << "(" << clock() << std::cout << "(" << clock()
") Chef: ouch ... make room ... this dish is very hot ..." << std::endl; << ") Chef: ouch ... make room ... this dish is "
<< "very hot ..." << std::endl;
} }
boost::xtime xt; boost::xtime xt;
boost::xtime_get(&xt, boost::TIME_UTC); boost::xtime_get(&xt, boost::TIME_UTC);
@@ -84,7 +97,7 @@ void chef()
{ {
boost::mutex::scoped_lock lock(iomx); boost::mutex::scoped_lock lock(iomx);
std::cout << "(" << clock() << ") Chef: " << chickens std::cout << "(" << clock() << ") Chef: " << chickens
<< " chickens, ready-to-go ..." << std::endl; << " chickens, ready-to-go ..." << std::endl;
} }
g_canteen.put(chickens); g_canteen.put(chickens);
} }
@@ -96,7 +109,8 @@ struct phil
void run() { void run() {
{ {
boost::mutex::scoped_lock lock(iomx); boost::mutex::scoped_lock lock(iomx);
std::cout << "(" << clock() << ") Phil" << m_id << ": starting ..." << std::endl; std::cout << "(" << clock() << ") Phil" << m_id
<< ": starting ..." << std::endl;
} }
for (;;) for (;;)
{ {
@@ -110,13 +124,13 @@ struct phil
{ {
boost::mutex::scoped_lock lock(iomx); boost::mutex::scoped_lock lock(iomx);
std::cout << "(" << clock() << ") Phil" << m_id std::cout << "(" << clock() << ") Phil" << m_id
<< ": gotta eat ..." << std::endl; << ": gotta eat ..." << std::endl;
} }
g_canteen.get(m_id); g_canteen.get(m_id);
{ {
boost::mutex::scoped_lock lock(iomx); boost::mutex::scoped_lock lock(iomx);
std::cout << "(" << clock() << ") Phil" << m_id std::cout << "(" << clock() << ") Phil" << m_id
<< ": mmm ... that's good ..." << std::endl; << ": mmm ... that's good ..." << std::endl;
} }
} }
} }
@@ -129,7 +143,10 @@ struct phil
struct thread_adapt struct thread_adapt
{ {
thread_adapt(void (*func)(void*), void* param) : _func(func), _param(param) { } thread_adapt(void (*func)(void*), void* param)
: _func(func), _param(param)
{
}
int operator()() const int operator()() const
{ {
_func(_param); _func(_param);
@@ -143,7 +160,10 @@ struct thread_adapt
class thread_adapter class thread_adapter
{ {
public: public:
thread_adapter(void (*func)(void*), void* param) : _func(func), _param(param) { } thread_adapter(void (*func)(void*), void* param)
: _func(func), _param(param)
{
}
void operator()() const { _func(_param); } void operator()() const { _func(_param); }
private: private:
void (*_func)(void*); void (*_func)(void*);

View File

@@ -1,3 +1,14 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/mutex.hpp> #include <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp> #include <boost/thread/condition.hpp>
#include <boost/thread/thread.hpp> #include <boost/thread/thread.hpp>
@@ -49,7 +60,8 @@ void player(void* param)
{ {
cond.wait(lock); cond.wait(lock);
if (state == other) if (state == other)
std::cout << "---" << player_name(active) << ": Spurious wakeup!" << std::endl; std::cout << "---" << player_name(active)
<< ": Spurious wakeup!" << std::endl;
} while (state == other); } while (state == other);
} }
@@ -60,7 +72,10 @@ void player(void* param)
struct thread_adapt struct thread_adapt
{ {
thread_adapt(void (*func)(void*), void* param) : _func(func), _param(param) { } thread_adapt(void (*func)(void*), void* param)
: _func(func), _param(param)
{
}
int operator()() const int operator()() const
{ {
_func(_param); _func(_param);
@@ -74,7 +89,10 @@ struct thread_adapt
class thread_adapter class thread_adapter
{ {
public: public:
thread_adapter(void (*func)(void*), void* param) : _func(func), _param(param) { } thread_adapter(void (*func)(void*), void* param)
: _func(func), _param(param)
{
}
void operator()() const { _func(_param); } void operator()() const { _func(_param); }
private: private:
void (*_func)(void*); void (*_func)(void*);

View File

@@ -1,29 +1,40 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/thread.hpp> #include <boost/thread/thread.hpp>
#include <boost/thread/xtime.hpp> #include <boost/thread/xtime.hpp>
#include <iostream> #include <iostream>
struct thread_alarm struct thread_alarm
{ {
thread_alarm(int secs) : m_secs(secs) { } thread_alarm(int secs) : m_secs(secs) { }
void operator()() void operator()()
{ {
boost::xtime xt; boost::xtime xt;
boost::xtime_get(&xt, boost::TIME_UTC); boost::xtime_get(&xt, boost::TIME_UTC);
xt.sec += m_secs; xt.sec += m_secs;
boost::thread::sleep(xt); boost::thread::sleep(xt);
std::cout << "alarm sounded..." << std::endl; std::cout << "alarm sounded..." << std::endl;
} }
int m_secs; int m_secs;
}; };
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
int secs = 5; int secs = 5;
std::cout << "setting alarm for 5 seconds..." << std::endl; std::cout << "setting alarm for 5 seconds..." << std::endl;
thread_alarm alarm(secs); thread_alarm alarm(secs);
boost::thread thrd(alarm); boost::thread thrd(alarm);
thrd.join(); thrd.join();
} }

View File

@@ -1,3 +1,14 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/thread.hpp> #include <boost/thread/thread.hpp>
#include <iostream> #include <iostream>
@@ -6,14 +17,14 @@ boost::mutex mutex;
void increment_count() void increment_count()
{ {
boost::mutex::scoped_lock lock(mutex); boost::mutex::scoped_lock lock(mutex);
std::cout << "count = " << ++count << std::endl; std::cout << "count = " << ++count << std::endl;
} }
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
boost::thread_group threads; boost::thread_group threads;
for (int i = 0; i < 10; ++i) for (int i = 0; i < 10; ++i)
threads.create_thread(&increment_count); threads.create_thread(&increment_count);
threads.join_all(); threads.join_all();
} }

View File

@@ -1,3 +1,14 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/thread.hpp> #include <boost/thread/thread.hpp>
#include <boost/thread/tss.hpp> #include <boost/thread/tss.hpp>
#include <cassert> #include <cassert>
@@ -6,25 +17,25 @@ boost::thread_specific_ptr<int> value;
void increment() void increment()
{ {
int* p = value.get(); int* p = value.get();
++*p; ++*p;
} }
void thread_proc() void thread_proc()
{ {
value.reset(new int(0)); // initialize the thread's storage value.reset(new int(0)); // initialize the thread's storage
for (int i=0; i<10; ++i) for (int i=0; i<10; ++i)
{ {
increment(); increment();
int* p = value.get(); int* p = value.get();
assert(*p == i+1); assert(*p == i+1);
} }
} }
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
boost::thread_group threads; boost::thread_group threads;
for (int i=0; i<5; ++i) for (int i=0; i<5; ++i)
threads.create_thread(&thread_proc); threads.create_thread(&thread_proc);
threads.join_all(); threads.join_all();
} }

View File

@@ -1,10 +1,21 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/thread.hpp> #include <boost/thread/thread.hpp>
#include <boost/thread/xtime.hpp> #include <boost/thread/xtime.hpp>
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
boost::xtime xt; boost::xtime xt;
boost::xtime_get(&xt, boost::TIME_UTC); boost::xtime_get(&xt, boost::TIME_UTC);
xt.sec += 1; xt.sec += 1;
boost::thread::sleep(xt); // Sleep for 1 second boost::thread::sleep(xt); // Sleep for 1 second
} }

24
include/boost/thread.hpp Normal file
View File

@@ -0,0 +1,24 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#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

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2001 // Copyright (C) 2001-2003
// William E. Kempf // William E. Kempf
// //
// Permission to use, copy, modify, distribute and sell this software // Permission to use, copy, modify, distribute and sell this software
@@ -20,6 +20,7 @@
#include <boost/thread/exceptions.hpp> #include <boost/thread/exceptions.hpp>
#include <boost/utility.hpp> #include <boost/utility.hpp>
#include <boost/thread/detail/lock.hpp> #include <boost/thread/detail/lock.hpp>
#include <boost/thread/detail/config.hpp>
#if defined(BOOST_HAS_PTHREADS) #if defined(BOOST_HAS_PTHREADS)
# include <pthread.h> # include <pthread.h>
@@ -31,15 +32,61 @@ namespace boost {
struct xtime; struct xtime;
class condition : private noncopyable namespace detail {
class BOOST_THREAD_DECL condition_impl : private noncopyable
{ {
friend class condition;
public: public:
condition(); condition_impl();
~condition(); ~condition_impl();
void notify_one(); void notify_one();
void notify_all(); 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> template <typename L>
void wait(L& lock) void wait(L& lock)
{ {
@@ -84,79 +131,63 @@ public:
} }
private: private:
detail::condition_impl m_impl;
template <typename M> template <typename M>
void do_wait(M& mutex) void do_wait(M& mutex)
{ {
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS)) #if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
enter_wait(); m_impl.enter_wait();
#endif #endif
typedef detail::thread::lock_ops<M> lock_ops; 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; typename lock_ops::lock_state state;
lock_ops::unlock(mutex, state); lock_ops::unlock(mutex, state);
#if defined(BOOST_HAS_PTHREADS) #if defined(BOOST_HAS_PTHREADS)
do_wait(state.pmutex); m_impl.do_wait(state.pmutex);
#elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS)) #elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
do_wait(); m_impl.do_wait();
#endif #endif
lock_ops::lock(mutex, state); lock_ops::lock(mutex, state);
#undef lock_ops
} }
template <typename M> template <typename M>
bool do_timed_wait(M& mutex, const xtime& xt) bool do_timed_wait(M& mutex, const xtime& xt)
{ {
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS)) #if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
enter_wait(); m_impl.enter_wait();
#endif #endif
typedef detail::thread::lock_ops<M> lock_ops; 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; typename lock_ops::lock_state state;
lock_ops::unlock(mutex, state); lock_ops::unlock(mutex, state);
bool ret = false; bool ret = false;
#if defined(BOOST_HAS_PTHREADS) #if defined(BOOST_HAS_PTHREADS)
ret = do_timed_wait(xt, state.pmutex); ret = m_impl.do_timed_wait(xt, state.pmutex);
#elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS)) #elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
ret = do_timed_wait(xt); ret = m_impl.do_timed_wait(xt);
#endif #endif
lock_ops::lock(mutex, state); lock_ops::lock(mutex, state);
#undef lock_ops
return ret; return ret;
} }
#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 the m_queue
unsigned long m_blocked; // # threads m_blocked m_waiting for the condition
unsigned m_waiting; // # threads m_waiting no longer m_waiting for the condition but still
// m_waiting to be removed from the 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 the m_queue
unsigned long m_blocked; // # threads m_blocked m_waiting for the condition
unsigned m_waiting; // # threads m_waiting no longer m_waiting for the condition but still
// m_waiting to be removed from the m_queue
#endif
}; };
} // namespace boost } // namespace boost
@@ -164,7 +195,8 @@ private:
// Change Log: // Change Log:
// 8 Feb 01 WEKEMPF Initial version. // 8 Feb 01 WEKEMPF Initial version.
// 22 May 01 WEKEMPF Modified to use xtime for time outs. // 22 May 01 WEKEMPF Modified to use xtime for time outs.
// 23 May 01 WEKEMPF Removed "duration" timed_waits, as they are too difficult // 23 May 01 WEKEMPF Removed "duration" timed_waits, as they are too
// to use with spurious wakeups. // difficult to use with spurious wakeups.
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
#endif // BOOST_CONDITION_WEK070601_HPP #endif // BOOST_CONDITION_WEK070601_HPP

View File

@@ -0,0 +1,25 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#ifndef BOOST_THREAD_CONFIG_WEK01032003_HPP
#define BOOST_THREAD_CONFIG_WEK01032003_HPP
#if defined(BOOST_HAS_WINTHREADS)
# if defined(BOOST_THREAD_BUILD_DLL)
# define BOOST_THREAD_DECL __declspec(dllexport)
# else
# define BOOST_THREAD_DECL __declspec(dllimport)
# endif
#else
# define BOOST_THREAD_DECL
#endif // BOOST_THREAD_SHARED_LIB
#endif // BOOST_THREAD_CONFIG_WEK1032003_HPP

View File

@@ -26,12 +26,12 @@ namespace thread {
// general case // general case
template<class Return_Type, class Argument_Type> template<class Return_Type, class Argument_Type>
inline Return_Type &force_cast(Argument_Type &rSrc) inline Return_Type &force_cast(Argument_Type &rSrc)
{ return(*reinterpret_cast<Return_Type *>(&rSrc)); } { return(*reinterpret_cast<Return_Type *>(&rSrc)); }
// specialization for const // specialization for const
template<class Return_Type, class Argument_Type> template<class Return_Type, class Argument_Type>
inline const Return_Type &force_cast(const Argument_Type &rSrc) inline const Return_Type &force_cast(const Argument_Type &rSrc)
{ return(*reinterpret_cast<const Return_Type *>(&rSrc)); } { return(*reinterpret_cast<const Return_Type *>(&rSrc)); }
} // namespace thread } // namespace thread

View File

@@ -20,182 +20,182 @@ namespace boost {
class condition; class condition;
struct xtime; struct xtime;
namespace detail { namespace thread { namespace detail { namespace thread {
template <typename Mutex> template <typename Mutex>
class lock_ops : private noncopyable class lock_ops : private noncopyable
{
private:
lock_ops() { }
public:
typedef typename Mutex::cv_state lock_state;
static void lock(Mutex& m)
{ {
private: m.do_lock();
lock_ops() { } }
static bool trylock(Mutex& m)
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: return m.do_trylock();
typedef Mutex mutex_type; }
static bool timedlock(Mutex& m, const xtime& xt)
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: return m.do_timedlock(xt);
typedef TryMutex mutex_type; }
static void unlock(Mutex& m)
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: m.do_unlock();
typedef TimedMutex mutex_type; }
static void lock(Mutex& m, lock_state& state)
{
m.do_lock(state);
}
static void unlock(Mutex& m, lock_state& state)
{
m.do_unlock(state);
}
};
scoped_timed_lock(TimedMutex& mx, const xtime& xt) template <typename Mutex>
: m_mutex(mx), m_locked(false) class scoped_lock : private noncopyable
{ {
timed_lock(xt); public:
} typedef Mutex mutex_type;
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() explicit scoped_lock(Mutex& mx, bool initially_locked=true)
{ : m_mutex(mx), m_locked(false)
if (m_locked) throw lock_error(); {
lock_ops<TimedMutex>::lock(m_mutex); if (initially_locked) lock();
m_locked = true; }
} ~scoped_lock()
bool timed_lock(const xtime& xt) {
{ if (m_locked) unlock();
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; } void lock()
operator const void*() const { return m_locked ? this : 0; } {
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;
}
private: bool locked() const { return m_locked; }
friend class boost::condition; operator const void*() const { return m_locked ? this : 0; }
TimedMutex& m_mutex; private:
bool m_locked; friend class boost::condition;
};
} // namespace thread Mutex& m_mutex;
} // namespace detail 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 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 } // namespace boost
// Change Log: // Change Log:

View File

@@ -26,29 +26,29 @@ namespace thread {
template<class T> template<class T>
class singleton: private T class singleton: private T
{ {
private: private:
singleton(); singleton();
~singleton(); ~singleton();
public: public:
static T &instance(); static T &instance();
}; };
template<class T> template<class T>
inline singleton<T>::singleton() inline singleton<T>::singleton()
{ /* no-op */ } { /* no-op */ }
template<class T> template<class T>
inline singleton<T>::~singleton() inline singleton<T>::~singleton()
{ /* no-op */ } { /* no-op */ }
template<class T> template<class T>
/*static*/ T &singleton<T>::instance() /*static*/ T &singleton<T>::instance()
{ {
// function-local static to force this to work correctly at static initialization // function-local static to force this to work correctly at static
// time. // initialization time.
static singleton<T> s_oT; static singleton<T> s_oT;
return(s_oT); return(s_oT);
} }

View File

@@ -0,0 +1,25 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/config.hpp>
#ifndef BOOST_HAS_THREADS
# error Thread support is unavailable!
#endif
#include <boost/thread/detail/config.hpp>
#ifdef BOOST_HAS_WINTHREADS
#include <boost/thread/detail/config.hpp>
extern "C" BOOST_THREAD_DECL int on_thread_exit(void (__cdecl * func)(void));
#endif // BOOST_HAS_WINTHREADS

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2001 // Copyright (C) 2001-2003
// William E. Kempf // William E. Kempf
// //
// Permission to use, copy, modify, distribute and sell this software // Permission to use, copy, modify, distribute and sell this software
@@ -12,6 +12,9 @@
#ifndef BOOST_THREAD_EXCEPTIONS_PDM070801_H #ifndef BOOST_THREAD_EXCEPTIONS_PDM070801_H
#define BOOST_THREAD_EXCEPTIONS_PDM070801_H #define BOOST_THREAD_EXCEPTIONS_PDM070801_H
#include <boost/config.hpp>
#include <boost/thread/detail/config.hpp>
// pdm: Sorry, but this class is used all over the place & I end up // pdm: Sorry, but this class is used all over the place & I end up
// with recursive headers if I don't separate it // with recursive headers if I don't separate it
// wek: Not sure why recursive headers would cause compilation problems // wek: Not sure why recursive headers would cause compilation problems
@@ -22,13 +25,13 @@
namespace boost { namespace boost {
class lock_error : public std::logic_error class BOOST_THREAD_DECL lock_error : public std::logic_error
{ {
public: public:
lock_error(); lock_error();
}; };
class thread_resource_error : public std::runtime_error class BOOST_THREAD_DECL thread_resource_error : public std::runtime_error
{ {
public: public:
thread_resource_error(); thread_resource_error();
@@ -36,4 +39,7 @@ public:
} // namespace boost } // namespace boost
// Change log:
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
#endif // BOOST_THREAD_CONFIG_PDM070801_H #endif // BOOST_THREAD_CONFIG_PDM070801_H

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2001 // Copyright (C) 2001-2003
// William E. Kempf // William E. Kempf
// //
// Permission to use, copy, modify, distribute and sell this software // Permission to use, copy, modify, distribute and sell this software
@@ -19,6 +19,7 @@
#include <boost/utility.hpp> #include <boost/utility.hpp>
#include <boost/thread/detail/lock.hpp> #include <boost/thread/detail/lock.hpp>
#include <boost/thread/detail/config.hpp>
#if defined(BOOST_HAS_PTHREADS) #if defined(BOOST_HAS_PTHREADS)
# include <pthread.h> # include <pthread.h>
@@ -32,7 +33,7 @@ namespace boost {
struct xtime; struct xtime;
class mutex : private noncopyable class BOOST_THREAD_DECL mutex : private noncopyable
{ {
public: public:
friend class detail::thread::lock_ops<mutex>; friend class detail::thread::lock_ops<mutex>;
@@ -70,7 +71,7 @@ private:
#endif #endif
}; };
class try_mutex : private noncopyable class BOOST_THREAD_DECL try_mutex : private noncopyable
{ {
public: public:
friend class detail::thread::lock_ops<try_mutex>; friend class detail::thread::lock_ops<try_mutex>;
@@ -110,7 +111,7 @@ private:
#endif #endif
}; };
class timed_mutex : private noncopyable class BOOST_THREAD_DECL timed_mutex : private noncopyable
{ {
public: public:
friend class detail::thread::lock_ops<timed_mutex>; friend class detail::thread::lock_ops<timed_mutex>;
@@ -160,5 +161,6 @@ private:
// 8 Feb 01 WEKEMPF Initial version. // 8 Feb 01 WEKEMPF Initial version.
// 22 May 01 WEKEMPF Modified to use xtime for time outs. Factored out // 22 May 01 WEKEMPF Modified to use xtime for time outs. Factored out
// to three classes, mutex, try_mutex and timed_mutex. // to three classes, mutex, try_mutex and timed_mutex.
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
#endif // BOOST_MUTEX_WEK070601_HPP #endif // BOOST_MUTEX_WEK070601_HPP

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2001 // Copyright (C) 2001-2003
// William E. Kempf // William E. Kempf
// //
// Permission to use, copy, modify, distribute and sell this software // Permission to use, copy, modify, distribute and sell this software
@@ -17,6 +17,8 @@
# error Thread support is unavailable! # error Thread support is unavailable!
#endif #endif
#include <boost/thread/detail/config.hpp>
#if defined(BOOST_HAS_PTHREADS) #if defined(BOOST_HAS_PTHREADS)
# include <pthread.h> # include <pthread.h>
#endif #endif
@@ -35,7 +37,7 @@ typedef long once_flag;
#endif #endif
void call_once(void (*func)(), once_flag& flag); void BOOST_THREAD_DECL call_once(void (*func)(), once_flag& flag);
} // namespace boost } // namespace boost

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2001 // Copyright (C) 2001-2003
// William E. Kempf // William E. Kempf
// //
// Permission to use, copy, modify, distribute and sell this software // Permission to use, copy, modify, distribute and sell this software
@@ -19,6 +19,7 @@
#include <boost/utility.hpp> #include <boost/utility.hpp>
#include <boost/thread/detail/lock.hpp> #include <boost/thread/detail/lock.hpp>
#include <boost/thread/detail/config.hpp>
#if defined(BOOST_HAS_PTHREADS) #if defined(BOOST_HAS_PTHREADS)
# include <pthread.h> # include <pthread.h>
@@ -30,7 +31,7 @@ namespace boost {
struct xtime; struct xtime;
class recursive_mutex : private noncopyable class BOOST_THREAD_DECL recursive_mutex : private noncopyable
{ {
public: public:
friend class detail::thread::lock_ops<recursive_mutex>; friend class detail::thread::lock_ops<recursive_mutex>;
@@ -73,13 +74,14 @@ private:
#endif #endif
}; };
class recursive_try_mutex : private noncopyable class BOOST_THREAD_DECL recursive_try_mutex : private noncopyable
{ {
public: public:
friend class detail::thread::lock_ops<recursive_try_mutex>; friend class detail::thread::lock_ops<recursive_try_mutex>;
typedef detail::thread::scoped_lock<recursive_try_mutex> scoped_lock; typedef detail::thread::scoped_lock<recursive_try_mutex> scoped_lock;
typedef detail::thread::scoped_try_lock<recursive_try_mutex> scoped_try_lock; typedef detail::thread::scoped_try_lock<
recursive_try_mutex> scoped_try_lock;
recursive_try_mutex(); recursive_try_mutex();
~recursive_try_mutex(); ~recursive_try_mutex();
@@ -118,14 +120,16 @@ private:
#endif #endif
}; };
class recursive_timed_mutex : private noncopyable class BOOST_THREAD_DECL recursive_timed_mutex : private noncopyable
{ {
public: public:
friend class detail::thread::lock_ops<recursive_timed_mutex>; friend class detail::thread::lock_ops<recursive_timed_mutex>;
typedef detail::thread::scoped_lock<recursive_timed_mutex> scoped_lock; 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_try_lock<
typedef detail::thread::scoped_timed_lock<recursive_timed_mutex> scoped_timed_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();
~recursive_timed_mutex(); ~recursive_timed_mutex();
@@ -170,5 +174,7 @@ private:
// 1 Jun 01 WEKEMPF Modified to use xtime for time outs. Factored out // 1 Jun 01 WEKEMPF Modified to use xtime for time outs. Factored out
// to three classes, mutex, try_mutex and timed_mutex. // to three classes, mutex, try_mutex and timed_mutex.
// 11 Jun 01 WEKEMPF Modified to use PTHREAD_MUTEX_RECURSIVE if available. // 11 Jun 01 WEKEMPF Modified to use PTHREAD_MUTEX_RECURSIVE if available.
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
#endif // BOOST_RECURSIVE_MUTEX_WEK070601_HPP #endif // BOOST_RECURSIVE_MUTEX_WEK070601_HPP

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2001 // Copyright (C) 2001-2003
// William E. Kempf // William E. Kempf
// //
// Permission to use, copy, modify, distribute and sell this software // Permission to use, copy, modify, distribute and sell this software
@@ -20,6 +20,7 @@
#include <boost/utility.hpp> #include <boost/utility.hpp>
#include <boost/function.hpp> #include <boost/function.hpp>
#include <boost/thread/mutex.hpp> #include <boost/thread/mutex.hpp>
#include <boost/thread/detail/config.hpp>
#include <list> #include <list>
#include <memory> #include <memory>
@@ -34,7 +35,7 @@ namespace boost {
struct xtime; struct xtime;
class thread : private noncopyable class BOOST_THREAD_DECL thread : private noncopyable
{ {
public: public:
thread(); thread();
@@ -63,7 +64,7 @@ private:
bool m_joinable; bool m_joinable;
}; };
class thread_group : private noncopyable class BOOST_THREAD_DECL thread_group : private noncopyable
{ {
public: public:
thread_group(); thread_group();

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2001 // Copyright (C) 2001-2003
// William E. Kempf // William E. Kempf
// //
// Permission to use, copy, modify, distribute and sell this software // Permission to use, copy, modify, distribute and sell this software
@@ -18,6 +18,7 @@
#endif #endif
#include <boost/utility.hpp> #include <boost/utility.hpp>
#include <boost/thread/detail/config.hpp>
#if defined(BOOST_HAS_PTHREADS) #if defined(BOOST_HAS_PTHREADS)
# include <pthread.h> # include <pthread.h>
@@ -27,32 +28,32 @@
namespace boost { namespace boost {
namespace detail { namespace detail {
class tss : private noncopyable class BOOST_THREAD_DECL tss : private noncopyable
{ {
public: public:
tss(void (*cleanup)(void*)=0); tss(void (*cleanup)(void*)=0);
~tss(); ~tss();
void* get() const; void* get() const;
bool set(void* value); bool set(void* value);
private: private:
#if defined(BOOST_HAS_WINTHREADS) #if defined(BOOST_HAS_WINTHREADS)
unsigned long m_key; unsigned long m_key;
void (*m_cleanup)(void*); void (*m_cleanup)(void*);
#elif defined(BOOST_HAS_PTHREADS) #elif defined(BOOST_HAS_PTHREADS)
pthread_key_t m_key; pthread_key_t m_key;
#elif defined(BOOST_HAS_MPTASKS) #elif defined(BOOST_HAS_MPTASKS)
TaskStorageIndex m_key; TaskStorageIndex m_key;
void (*m_cleanup)(void*); void (*m_cleanup)(void*);
#endif #endif
}; };
#if defined(BOOST_HAS_MPTASKS) #if defined(BOOST_HAS_MPTASKS)
void thread_cleanup(); void thread_cleanup();
#endif #endif
} }
template <typename T> template <typename T>
class thread_specific_ptr : private noncopyable class thread_specific_ptr : private noncopyable
@@ -64,7 +65,13 @@ public:
T* operator->() const { return get(); } T* operator->() const { return get(); }
T& operator*() const { return *get(); } T& operator*() const { return *get(); }
T* release() { T* temp = get(); m_tss.set(0); return temp; } T* release() { T* temp = get(); m_tss.set(0); return temp; }
void reset(T* p=0) { T* cur = get(); if (cur == p) return; delete cur; m_tss.set(p); } void reset(T* p=0)
{
T* cur = get();
if (cur == p) return;
delete cur;
m_tss.set(p);
}
private: private:
static void cleanup(void* p) { delete static_cast<T*>(p); } static void cleanup(void* p) { delete static_cast<T*>(p); }

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2001 // Copyright (C) 2001-2003
// William E. Kempf // William E. Kempf
// //
// Permission to use, copy, modify, distribute and sell this software // Permission to use, copy, modify, distribute and sell this software
@@ -12,8 +12,9 @@
#ifndef BOOST_XTIME_WEK070601_HPP #ifndef BOOST_XTIME_WEK070601_HPP
#define BOOST_XTIME_WEK070601_HPP #define BOOST_XTIME_WEK070601_HPP
#include <boost/cstdint.hpp>
#include <boost/config.hpp> #include <boost/config.hpp>
#include <boost/cstdint.hpp>
#include <boost/thread/detail/config.hpp>
namespace boost { namespace boost {
@@ -39,7 +40,7 @@ struct xtime
int_fast32_t nsec; int_fast32_t nsec;
}; };
int xtime_get(struct xtime* xtp, int clock_type); int BOOST_THREAD_DECL xtime_get(struct xtime* xtp, int clock_type);
inline int xtime_cmp(const xtime& xt1, const xtime& xt2) inline int xtime_cmp(const xtime& xt1, const xtime& xt2)
{ {
int res = (int)(xt1.sec - xt2.sec); int res = (int)(xt1.sec - xt2.sec);

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2001 // Copyright (C) 2001-2003
// William E. Kempf // William E. Kempf
// //
// Permission to use, copy, modify, distribute and sell this software // Permission to use, copy, modify, distribute and sell this software
@@ -25,45 +25,49 @@
#elif defined(BOOST_HAS_PTHREADS) #elif defined(BOOST_HAS_PTHREADS)
# include <errno.h> # include <errno.h>
#elif defined(BOOST_HAS_MPTASKS) #elif defined(BOOST_HAS_MPTASKS)
# include <MacErrors.h> # include <MacErrors.h>
# include "mac/init.hpp" # include "mac/init.hpp"
# include "mac/safe.hpp" # include "mac/safe.hpp"
#endif #endif
namespace boost { namespace boost {
namespace detail {
#if defined(BOOST_HAS_WINTHREADS) #if defined(BOOST_HAS_WINTHREADS)
condition::condition() condition_impl::condition_impl()
: m_gone(0), m_blocked(0), m_waiting(0) : m_gone(0), m_blocked(0), m_waiting(0)
{ {
m_gate = reinterpret_cast<void*>(CreateSemaphore(0, 1, 1, 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_queue = reinterpret_cast<void*>(CreateSemaphore(0, 0,
std::numeric_limits<long>::max(),
0));
m_mutex = reinterpret_cast<void*>(CreateMutex(0, 0, 0)); m_mutex = reinterpret_cast<void*>(CreateMutex(0, 0, 0));
if (!m_gate || !m_queue || !m_mutex) if (!m_gate || !m_queue || !m_mutex)
{
int res = 0;
if (m_gate)
{ {
res = CloseHandle(reinterpret_cast<HANDLE>(m_gate)); int res = 0;
assert(res); if (m_gate)
} {
if (m_queue) res = CloseHandle(reinterpret_cast<HANDLE>(m_gate));
{ assert(res);
res = CloseHandle(reinterpret_cast<HANDLE>(m_queue)); }
assert(res); if (m_queue)
} {
if (m_mutex) res = CloseHandle(reinterpret_cast<HANDLE>(m_queue));
{ assert(res);
res = CloseHandle(reinterpret_cast<HANDLE>(m_mutex)); }
assert(res); if (m_mutex)
} {
res = CloseHandle(reinterpret_cast<HANDLE>(m_mutex));
assert(res);
}
throw thread_resource_error(); throw thread_resource_error();
} }
} }
condition::~condition() condition_impl::~condition_impl()
{ {
int res = 0; int res = 0;
res = CloseHandle(reinterpret_cast<HANDLE>(m_gate)); res = CloseHandle(reinterpret_cast<HANDLE>(m_gate));
@@ -74,7 +78,7 @@ condition::~condition()
assert(res); assert(res);
} }
void condition::notify_one() void condition_impl::notify_one()
{ {
unsigned signals = 0; unsigned signals = 0;
@@ -83,50 +87,50 @@ void condition::notify_one()
assert(res == WAIT_OBJECT_0); assert(res == WAIT_OBJECT_0);
if (m_waiting != 0) // the m_gate is already closed if (m_waiting != 0) // the m_gate is already closed
{
if (m_blocked == 0)
{ {
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex)); if (m_blocked == 0)
assert(res); {
return; res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
} assert(res);
return;
}
++m_waiting; ++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; --m_blocked;
signals = 1;
} }
else else
{ {
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0); res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
assert(res); 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)); res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
assert(res); assert(res);
if (signals) if (signals)
{ {
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_queue), signals, 0); res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_queue), signals, 0);
assert(res); assert(res);
} }
} }
void condition::notify_all() void condition_impl::notify_all()
{ {
unsigned signals = 0; unsigned signals = 0;
@@ -135,49 +139,50 @@ void condition::notify_all()
assert(res == WAIT_OBJECT_0); assert(res == WAIT_OBJECT_0);
if (m_waiting != 0) // the m_gate is already closed if (m_waiting != 0) // the m_gate is already closed
{
if (m_blocked == 0)
{ {
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex)); if (m_blocked == 0)
assert(res); {
return; res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
} assert(res);
return;
}
m_waiting += (signals = m_blocked); 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; m_blocked = 0;
} }
else else
{ {
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0); res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
assert(res); 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)); res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
assert(res); assert(res);
if (signals) if (signals)
{ {
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_queue), signals, 0); res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_queue), signals,
0);
assert(res); assert(res);
} }
}
} }
void condition::enter_wait() void condition_impl::enter_wait()
{ {
int res = 0; int res = 0;
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE); res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
@@ -187,7 +192,7 @@ void condition::enter_wait()
assert(res); assert(res);
} }
void condition::do_wait() void condition_impl::do_wait()
{ {
int res = 0; int res = 0;
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue), INFINITE); res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue), INFINITE);
@@ -201,71 +206,74 @@ void condition::do_wait()
was_waiting = m_waiting; was_waiting = m_waiting;
was_gone = m_gone; was_gone = m_gone;
if (was_waiting != 0) if (was_waiting != 0)
{
if (--m_waiting == 0)
{ {
if (m_blocked != 0) if (--m_waiting == 0)
{ {
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0); // open m_gate if (m_blocked != 0)
assert(res); {
was_waiting = 0; res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1,
} 0); // open m_gate
else if (m_gone != 0) assert(res);
m_gone = 0; was_waiting = 0;
}
else if (m_gone != 0)
m_gone = 0;
}
} }
}
else if (++m_gone == (std::numeric_limits<unsigned>::max() / 2)) else if (++m_gone == (std::numeric_limits<unsigned>::max() / 2))
{ {
// timeout occured, normalize the m_gone count // timeout occured, normalize the m_gone count
// this may occur if many calls to wait with a timeout are made and // this may occur if many calls to wait with a timeout are made and
// no call to notify_* is made // no call to notify_* is made
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE); res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
assert(res == WAIT_OBJECT_0); assert(res == WAIT_OBJECT_0);
m_blocked -= m_gone; m_blocked -= m_gone;
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0); res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
assert(res); assert(res);
m_gone = 0; m_gone = 0;
} }
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex)); res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
assert(res); assert(res);
if (was_waiting == 1) if (was_waiting == 1)
{
for (/**/ ; was_gone; --was_gone)
{ {
// better now than spurious later for (/**/ ; was_gone; --was_gone)
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue), INFINITE); {
assert(res == WAIT_OBJECT_0); // 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);
} }
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
assert(res);
}
} }
bool condition::do_timed_wait(const xtime& xt) bool condition_impl::do_timed_wait(const xtime& xt)
{ {
bool ret = false; bool ret = false;
unsigned int res = 0; unsigned int res = 0;
for (;;) 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; int milliseconds;
xtime_get(&cur, TIME_UTC); to_duration(xt, milliseconds);
if (xtime_cmp(xt, cur) > 0)
continue;
}
break; 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_waiting=0;
unsigned was_gone=0; unsigned was_gone=0;
@@ -275,57 +283,59 @@ bool condition::do_timed_wait(const xtime& xt)
was_waiting = m_waiting; was_waiting = m_waiting;
was_gone = m_gone; was_gone = m_gone;
if (was_waiting != 0) if (was_waiting != 0)
{
if (!ret) // timeout
{ {
if (m_blocked != 0) if (!ret) // timeout
--m_blocked; {
else if (m_blocked != 0)
++m_gone; // count spurious wakeups --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;
}
} }
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)) else if (++m_gone == (std::numeric_limits<unsigned>::max() / 2))
{ {
// timeout occured, normalize the m_gone count // timeout occured, normalize the m_gone count
// this may occur if many calls to wait with a timeout are made and // this may occur if many calls to wait with a timeout are made and
// no call to notify_* is made // no call to notify_* is made
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE); res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
assert(res == WAIT_OBJECT_0); assert(res == WAIT_OBJECT_0);
m_blocked -= m_gone; m_blocked -= m_gone;
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0); res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
assert(res); assert(res);
m_gone = 0; m_gone = 0;
} }
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex)); res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
assert(res); assert(res);
if (was_waiting == 1) if (was_waiting == 1)
{
for (/**/ ; was_gone; --was_gone)
{ {
// better now than spurious later for (/**/ ; was_gone; --was_gone)
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue), INFINITE); {
assert(res == WAIT_OBJECT_0); // 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);
} }
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
assert(res);
}
return ret; return ret;
} }
#elif defined(BOOST_HAS_PTHREADS) #elif defined(BOOST_HAS_PTHREADS)
condition::condition() condition_impl::condition_impl()
{ {
int res = 0; int res = 0;
res = pthread_cond_init(&m_condition, 0); res = pthread_cond_init(&m_condition, 0);
@@ -333,35 +343,35 @@ condition::condition()
throw thread_resource_error(); throw thread_resource_error();
} }
condition::~condition() condition_impl::~condition_impl()
{ {
int res = 0; int res = 0;
res = pthread_cond_destroy(&m_condition); res = pthread_cond_destroy(&m_condition);
assert(res == 0); assert(res == 0);
} }
void condition::notify_one() void condition_impl::notify_one()
{ {
int res = 0; int res = 0;
res = pthread_cond_signal(&m_condition); res = pthread_cond_signal(&m_condition);
assert(res == 0); assert(res == 0);
} }
void condition::notify_all() void condition_impl::notify_all()
{ {
int res = 0; int res = 0;
res = pthread_cond_broadcast(&m_condition); res = pthread_cond_broadcast(&m_condition);
assert(res == 0); assert(res == 0);
} }
void condition::do_wait(pthread_mutex_t* pmutex) void condition_impl::do_wait(pthread_mutex_t* pmutex)
{ {
int res = 0; int res = 0;
res = pthread_cond_wait(&m_condition, pmutex); res = pthread_cond_wait(&m_condition, pmutex);
assert(res == 0); assert(res == 0);
} }
bool condition::do_timed_wait(const xtime& xt, pthread_mutex_t* pmutex) bool condition_impl::do_timed_wait(const xtime& xt, pthread_mutex_t* pmutex)
{ {
timespec ts; timespec ts;
to_timespec(xt, ts); to_timespec(xt, ts);
@@ -377,7 +387,7 @@ bool condition::do_timed_wait(const xtime& xt, pthread_mutex_t* pmutex)
using threads::mac::detail::safe_enter_critical_region; using threads::mac::detail::safe_enter_critical_region;
using threads::mac::detail::safe_wait_on_semaphore; using threads::mac::detail::safe_wait_on_semaphore;
condition::condition() condition_impl::condition_impl()
: m_gone(0), m_blocked(0), m_waiting(0) : m_gone(0), m_blocked(0), m_waiting(0)
{ {
threads::mac::detail::thread_init(); threads::mac::detail::thread_init();
@@ -389,23 +399,23 @@ condition::condition()
lStatus = MPCreateSemaphore(ULONG_MAX, 0, &m_queue); lStatus = MPCreateSemaphore(ULONG_MAX, 0, &m_queue);
if(lStatus != noErr || !m_gate || !m_queue) if(lStatus != noErr || !m_gate || !m_queue)
{
if (m_gate)
{ {
lStatus = MPDeleteSemaphore(m_gate); if (m_gate)
assert(lStatus == noErr); {
} lStatus = MPDeleteSemaphore(m_gate);
if (m_queue) assert(lStatus == noErr);
{ }
lStatus = MPDeleteSemaphore(m_queue); if (m_queue)
assert(lStatus == noErr); {
} lStatus = MPDeleteSemaphore(m_queue);
assert(lStatus == noErr);
}
throw thread_resource_error(); throw thread_resource_error();
} }
} }
condition::~condition() condition_impl::~condition_impl()
{ {
OSStatus lStatus = noErr; OSStatus lStatus = noErr;
lStatus = MPDeleteSemaphore(m_gate); lStatus = MPDeleteSemaphore(m_gate);
@@ -414,111 +424,113 @@ condition::~condition()
assert(lStatus == noErr); assert(lStatus == noErr);
} }
void condition::notify_one() void condition_impl::notify_one()
{ {
unsigned signals = 0; unsigned signals = 0;
OSStatus lStatus = noErr; OSStatus lStatus = noErr;
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex); lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
m_mutex_mutex);
assert(lStatus == noErr); assert(lStatus == noErr);
if (m_waiting != 0) // the m_gate is already closed if (m_waiting != 0) // the m_gate is already closed
{
if (m_blocked == 0)
{ {
lStatus = MPExitCriticalRegion(m_mutex); if (m_blocked == 0)
assert(lStatus == noErr); {
return; lStatus = MPExitCriticalRegion(m_mutex);
} assert(lStatus == noErr);
return;
}
++m_waiting; ++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; --m_blocked;
} }
else else
{ {
lStatus = MPSignalSemaphore(m_gate); lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
assert(lStatus == noErr); 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); lStatus = MPExitCriticalRegion(m_mutex);
assert(lStatus == noErr);
while (signals)
{
lStatus = MPSignalSemaphore(m_queue);
assert(lStatus == noErr); assert(lStatus == noErr);
--signals;
while (signals)
{
lStatus = MPSignalSemaphore(m_queue);
assert(lStatus == noErr);
--signals;
}
} }
}
} }
void condition::notify_all() void condition_impl::notify_all()
{ {
unsigned signals = 0; unsigned signals = 0;
OSStatus lStatus = noErr; OSStatus lStatus = noErr;
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex); lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
m_mutex_mutex);
assert(lStatus == noErr); assert(lStatus == noErr);
if (m_waiting != 0) // the m_gate is already closed if (m_waiting != 0) // the m_gate is already closed
{
if (m_blocked == 0)
{ {
lStatus = MPExitCriticalRegion(m_mutex); if (m_blocked == 0)
assert(lStatus == noErr); {
return; lStatus = MPExitCriticalRegion(m_mutex);
} assert(lStatus == noErr);
return;
}
m_waiting += (signals = m_blocked); 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; m_blocked = 0;
} }
else else
{ {
lStatus = MPSignalSemaphore(m_gate); lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
assert(lStatus == noErr); 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); lStatus = MPExitCriticalRegion(m_mutex);
assert(lStatus == noErr);
while (signals)
{
lStatus = MPSignalSemaphore(m_queue);
assert(lStatus == noErr); assert(lStatus == noErr);
--signals;
while (signals)
{
lStatus = MPSignalSemaphore(m_queue);
assert(lStatus == noErr);
--signals;
}
} }
}
} }
void condition::enter_wait() void condition_impl::enter_wait()
{ {
OSStatus lStatus = noErr; OSStatus lStatus = noErr;
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever); lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
@@ -528,7 +540,7 @@ void condition::enter_wait()
assert(lStatus == noErr); assert(lStatus == noErr);
} }
void condition::do_wait() void condition_impl::do_wait()
{ {
OSStatus lStatus = noErr; OSStatus lStatus = noErr;
lStatus = safe_wait_on_semaphore(m_queue, kDurationForever); lStatus = safe_wait_on_semaphore(m_queue, kDurationForever);
@@ -537,53 +549,54 @@ void condition::do_wait()
unsigned was_waiting=0; unsigned was_waiting=0;
unsigned was_gone=0; unsigned was_gone=0;
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex); lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
m_mutex_mutex);
assert(lStatus == noErr); assert(lStatus == noErr);
was_waiting = m_waiting; was_waiting = m_waiting;
was_gone = m_gone; was_gone = m_gone;
if (was_waiting != 0) if (was_waiting != 0)
{
if (--m_waiting == 0)
{ {
if (m_blocked != 0) if (--m_waiting == 0)
{ {
lStatus = MPSignalSemaphore(m_gate); // open m_gate if (m_blocked != 0)
assert(lStatus == noErr); {
was_waiting = 0; lStatus = MPSignalSemaphore(m_gate); // open m_gate
} assert(lStatus == noErr);
else if (m_gone != 0) was_waiting = 0;
m_gone = 0; }
else if (m_gone != 0)
m_gone = 0;
}
} }
}
else if (++m_gone == (std::numeric_limits<unsigned>::max() / 2)) else if (++m_gone == (std::numeric_limits<unsigned>::max() / 2))
{ {
// timeout occured, normalize the m_gone count // timeout occured, normalize the m_gone count
// this may occur if many calls to wait with a timeout are made and // this may occur if many calls to wait with a timeout are made and
// no call to notify_* is made // no call to notify_* is made
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever); lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
assert(lStatus == noErr); assert(lStatus == noErr);
m_blocked -= m_gone; m_blocked -= m_gone;
lStatus = MPSignalSemaphore(m_gate); lStatus = MPSignalSemaphore(m_gate);
assert(lStatus == noErr); assert(lStatus == noErr);
m_gone = 0; m_gone = 0;
} }
lStatus = MPExitCriticalRegion(m_mutex); lStatus = MPExitCriticalRegion(m_mutex);
assert(lStatus == noErr); assert(lStatus == noErr);
if (was_waiting == 1) if (was_waiting == 1)
{
for (/**/ ; was_gone; --was_gone)
{ {
// better now than spurious later for (/**/ ; was_gone; --was_gone)
lStatus = safe_wait_on_semaphore(m_queue, kDurationForever); {
// better now than spurious later
lStatus = safe_wait_on_semaphore(m_queue, kDurationForever);
assert(lStatus == noErr);
}
lStatus = MPSignalSemaphore(m_gate);
assert(lStatus == noErr); assert(lStatus == noErr);
} }
lStatus = MPSignalSemaphore(m_gate);
assert(lStatus == noErr);
}
} }
bool condition::do_timed_wait(const xtime& xt) bool condition_impl::do_timed_wait(const xtime& xt)
{ {
int milliseconds; int milliseconds;
to_duration(xt, milliseconds); to_duration(xt, milliseconds);
@@ -597,64 +610,68 @@ bool condition::do_timed_wait(const xtime& xt)
unsigned was_waiting=0; unsigned was_waiting=0;
unsigned was_gone=0; unsigned was_gone=0;
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex); lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
m_mutex_mutex);
assert(lStatus == noErr); assert(lStatus == noErr);
was_waiting = m_waiting; was_waiting = m_waiting;
was_gone = m_gone; was_gone = m_gone;
if (was_waiting != 0) if (was_waiting != 0)
{
if (!ret) // timeout
{ {
if (m_blocked != 0) if (!ret) // timeout
--m_blocked; {
else if (m_blocked != 0)
++m_gone; // count spurious wakeups --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;
}
} }
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)) else if (++m_gone == (std::numeric_limits<unsigned>::max() / 2))
{ {
// timeout occured, normalize the m_gone count // timeout occured, normalize the m_gone count
// this may occur if many calls to wait with a timeout are made and // this may occur if many calls to wait with a timeout are made and
// no call to notify_* is made // no call to notify_* is made
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever); lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
assert(lStatus == noErr); assert(lStatus == noErr);
m_blocked -= m_gone; m_blocked -= m_gone;
lStatus = MPSignalSemaphore(m_gate); lStatus = MPSignalSemaphore(m_gate);
assert(lStatus == noErr); assert(lStatus == noErr);
m_gone = 0; m_gone = 0;
} }
lStatus = MPExitCriticalRegion(m_mutex); lStatus = MPExitCriticalRegion(m_mutex);
assert(lStatus == noErr); assert(lStatus == noErr);
if (was_waiting == 1) if (was_waiting == 1)
{
for (/**/ ; was_gone; --was_gone)
{ {
// better now than spurious later for (/**/ ; was_gone; --was_gone)
lStatus = safe_wait_on_semaphore(m_queue, kDurationForever); {
// better now than spurious later
lStatus = safe_wait_on_semaphore(m_queue, kDurationForever);
assert(lStatus == noErr);
}
lStatus = MPSignalSemaphore(m_gate);
assert(lStatus == noErr); assert(lStatus == noErr);
} }
lStatus = MPSignalSemaphore(m_gate);
assert(lStatus == noErr);
}
return ret; return ret;
} }
#endif #endif
} // namespace detail
} // namespace boost } // namespace boost
// Change Log: // Change Log:
// 8 Feb 01 WEKEMPF Initial version. // 8 Feb 01 WEKEMPF Initial version.
// 22 May 01 WEKEMPF Modified to use xtime for time outs. // 22 May 01 WEKEMPF Modified to use xtime for time outs.
// 3 Jan 03 WEKEMPF Modified for DLL implementation.

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2001 // Copyright (C) 2001-2003
// William E. Kempf // William E. Kempf
// //
// Permission to use, copy, modify, distribute and sell this software // Permission to use, copy, modify, distribute and sell this software
@@ -14,11 +14,13 @@
namespace boost { namespace boost {
lock_error::lock_error() : std::logic_error("thread lock error") lock_error::lock_error()
: std::logic_error("thread lock error")
{ {
} }
thread_resource_error::thread_resource_error() : std::runtime_error("thread resource error") thread_resource_error::thread_resource_error()
: std::runtime_error("thread resource error")
{ {
} }

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2001 // Copyright (C) 2001-2003
// William E. Kempf // William E. Kempf
// //
// Permission to use, copy, modify, distribute and sell this software // Permission to use, copy, modify, distribute and sell this software
@@ -16,7 +16,6 @@
#include <boost/limits.hpp> #include <boost/limits.hpp>
#include <stdexcept> #include <stdexcept>
#include <cassert> #include <cassert>
#include <new>
#include "timeconv.inl" #include "timeconv.inl"
#if defined(BOOST_HAS_WINTHREADS) #if defined(BOOST_HAS_WINTHREADS)
@@ -25,18 +24,23 @@
#elif defined(BOOST_HAS_PTHREADS) #elif defined(BOOST_HAS_PTHREADS)
# include <errno.h> # include <errno.h>
#elif defined(BOOST_HAS_MPTASKS) #elif defined(BOOST_HAS_MPTASKS)
# include <MacErrors.h> # include <MacErrors.h>
# include "mac/init.hpp"
# include "mac/init.hpp" # include "mac/safe.hpp"
# include "mac/safe.hpp"
#endif #endif
namespace boost { namespace boost {
#if defined(BOOST_HAS_WINTHREADS) #if defined(BOOST_HAS_WINTHREADS)
mutex::mutex() mutex::mutex() : m_mutex(0)
{ {
m_mutex = reinterpret_cast<void*>(new(std::nothrow) CRITICAL_SECTION); try
{
m_mutex = reinterpret_cast<void*>(new CRITICAL_SECTION);
}
catch (...)
{
}
if (!m_mutex) if (!m_mutex)
throw thread_resource_error(); throw thread_resource_error();
InitializeCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(m_mutex)); InitializeCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(m_mutex));
@@ -151,7 +155,8 @@ bool timed_mutex::do_timedlock(const xtime& xt)
int milliseconds; int milliseconds;
to_duration(xt, milliseconds); to_duration(xt, milliseconds);
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), milliseconds); res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex),
milliseconds);
assert(res != WAIT_FAILED && res != WAIT_ABANDONED); assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
if (res == WAIT_TIMEOUT) if (res == WAIT_TIMEOUT)
@@ -427,7 +432,8 @@ mutex::~mutex()
void mutex::do_lock() void mutex::do_lock()
{ {
OSStatus lStatus = noErr; OSStatus lStatus = noErr;
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex); lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
m_mutex_mutex);
assert(lStatus == noErr); assert(lStatus == noErr);
} }
@@ -459,7 +465,8 @@ try_mutex::~try_mutex()
void try_mutex::do_lock() void try_mutex::do_lock()
{ {
OSStatus lStatus = noErr; OSStatus lStatus = noErr;
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex); lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
m_mutex_mutex);
assert(lStatus == noErr); assert(lStatus == noErr);
} }
@@ -499,7 +506,8 @@ timed_mutex::~timed_mutex()
void timed_mutex::do_lock() void timed_mutex::do_lock()
{ {
OSStatus lStatus = noErr; OSStatus lStatus = noErr;
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex); lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
m_mutex_mutex);
assert(lStatus == noErr); assert(lStatus == noErr);
} }

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2001 // Copyright (C) 2001-2003
// William E. Kempf // William E. Kempf
// //
// Permission to use, copy, modify, distribute and sell this software // Permission to use, copy, modify, distribute and sell this software
@@ -17,14 +17,16 @@
# include <windows.h> # include <windows.h>
# if defined(BOOST_NO_STRINGSTREAM) # if defined(BOOST_NO_STRINGSTREAM)
# include <strstream> # include <strstream>
class unfreezer
{ class unfreezer
public: {
unfreezer(std::ostrstream& s) : m_stream(s) {} public:
~unfreezer() { m_stream.freeze(false); } unfreezer(std::ostrstream& s) : m_stream(s) {}
private: ~unfreezer() { m_stream.freeze(false); }
std::ostrstream& m_stream; private:
}; std::ostrstream& m_stream;
};
# else # else
# include <sstream> # include <sstream>
# endif # endif
@@ -33,7 +35,7 @@
#endif #endif
#ifdef BOOST_NO_STDC_NAMESPACE #ifdef BOOST_NO_STDC_NAMESPACE
namespace std { using ::sprintf; } namespace std { using ::sprintf; }
#endif #endif
#if defined(BOOST_HAS_PTHREADS) #if defined(BOOST_HAS_PTHREADS)
@@ -46,64 +48,70 @@ typedef void (*once_callback)();
extern "C" { extern "C" {
static void key_init() static void key_init()
{ {
pthread_key_create(&key, 0); pthread_key_create(&key, 0);
} }
static void do_once() static void do_once()
{ {
once_callback* cb = reinterpret_cast<once_callback*>(pthread_getspecific(key)); once_callback* cb = reinterpret_cast<once_callback*>(
(**cb)(); pthread_getspecific(key));
} (**cb)();
}
} }
#elif defined(BOOST_HAS_MPTASKS) #elif defined(BOOST_HAS_MPTASKS)
namespace { namespace {
void *remote_call_proxy(void *pData) 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)
{ {
std::pair<void (*)(), boost::once_flag *> &rData(*reinterpret_cast<std::pair<void (*)(), boost::once_flag *> *>(pData)); rData.first();
*rData.second = true;
if(*rData.second == false)
{
rData.first();
*rData.second = true;
}
return(NULL);
} }
return(NULL);
} }
}
#elif defined(BOOST_HAS_WINTHREADS) #elif defined(BOOST_HAS_WINTHREADS)
namespace { namespace {
// The signature for InterlockedCompareExchange has changed with the // The signature for InterlockedCompareExchange has changed with the
// addition of Win64 support. I can't determine any (consistent and // addition of Win64 support. I can't determine any (consistent and
// portable) way of using conditional compilation to detect this, so // portable) way of using conditional compilation to detect this, so
// we use these type wrappers. Unfortunately, the various vendors // we use these type wrappers. Unfortunately, the various vendors
// use different calling conventions and other signature anamolies, // use different calling conventions and other signature anamolies,
// and thus have unique types as well. This is known to work on VC6, // 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 // VC7, Borland 5.5.2 and gcc 3.2. Are there other signatures for
// other platforms? // other platforms?
inline LONG ice_wrapper(LONG (__stdcall *ice)(LONG*, LONG, LONG), volatile LONG* dest, LONG exch, LONG cmp) 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); {
} 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) inline LONG ice_wrapper(LONG (__stdcall *ice)(volatile LONG*, LONG, LONG),
{ volatile LONG* dest, LONG exch, LONG cmp)
return (*ice)(dest, exch, cmp); {
} return (*ice)(dest, exch, cmp);
}
inline LONG ice_wrapper(LPVOID (__stdcall *ice)(LPVOID*, LPVOID, LPVOID), volatile LONG* dest, LONG exch, LONG 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); {
} return (LONG)(*ice)((LPVOID*)dest, (LPVOID)exch, (LPVOID)cmp);
}
// The friendly form of InterlockedCompareExchange that defers // The friendly form of InterlockedCompareExchange that defers
// according to the above function type wrappers. // according to the above function type wrappers.
inline LONG compare_exchange(volatile LPLONG dest, LONG exch, LONG cmp) inline LONG compare_exchange(volatile LPLONG dest, LONG exch, LONG cmp)
{ {
return ice_wrapper(&InterlockedCompareExchange, dest, exch, cmp); return ice_wrapper(&InterlockedCompareExchange, dest, exch, cmp);
} }
} }
#endif #endif
@@ -116,13 +124,15 @@ void call_once(void (*func)(), once_flag& flag)
{ {
#if defined(BOOST_NO_STRINGSTREAM) #if defined(BOOST_NO_STRINGSTREAM)
std::ostrstream strm; std::ostrstream strm;
strm << "2AC1A572DB6944B0A65C38C4140AF2F4" << std::hex << GetCurrentProcessId() << &flag << std::ends; strm << "2AC1A572DB6944B0A65C38C4140AF2F4" << std::hex
<< GetCurrentProcessId() << &flag << std::ends;
unfreezer unfreeze(strm); unfreezer unfreeze(strm);
HANDLE mutex = CreateMutex(NULL, FALSE, strm.str()); HANDLE mutex = CreateMutex(NULL, FALSE, strm.str());
#else #else
std::ostringstream strm; std::ostringstream strm;
strm << "2AC1A572DB6944B0A65C38C4140AF2F4" << std::hex << GetCurrentProcessId() << &flag; strm << "2AC1A572DB6944B0A65C38C4140AF2F4" << std::hex
HANDLE mutex = CreateMutex(NULL, FALSE, strm.str().c_str()); << GetCurrentProcessId() << &flag;
HANDLE mutex = CreateMutexA(NULL, FALSE, strm.str().c_str());
#endif #endif
assert(mutex != NULL); assert(mutex != NULL);
@@ -148,7 +158,8 @@ void call_once(void (*func)(), once_flag& flag)
#elif defined(BOOST_HAS_MPTASKS) #elif defined(BOOST_HAS_MPTASKS)
if(flag == false) if(flag == false)
{ {
// all we do here is make a remote call to blue, as blue is not reentrant. // all we do here is make a remote call to blue, as blue is not
// reentrant.
std::pair<void (*)(), once_flag *> sData(func, &flag); std::pair<void (*)(), once_flag *> sData(func, &flag);
MPRemoteCall(remote_call_proxy, &sData, kMPOwningProcessRemoteContext); MPRemoteCall(remote_call_proxy, &sData, kMPOwningProcessRemoteContext);
assert(flag == true); assert(flag == true);

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2001 // Copyright (C) 2001-2003
// William E. Kempf // William E. Kempf
// //
// Permission to use, copy, modify, distribute and sell this software // Permission to use, copy, modify, distribute and sell this software
@@ -23,17 +23,23 @@
#elif defined(BOOST_HAS_PTHREADS) #elif defined(BOOST_HAS_PTHREADS)
# include <errno.h> # include <errno.h>
#elif defined(BOOST_HAS_MPTASKS) #elif defined(BOOST_HAS_MPTASKS)
# include <MacErrors.h> # include <MacErrors.h>
# include "safe.hpp" # include "safe.hpp"
#endif #endif
namespace boost { namespace boost {
#if defined(BOOST_HAS_WINTHREADS) #if defined(BOOST_HAS_WINTHREADS)
recursive_mutex::recursive_mutex() recursive_mutex::recursive_mutex()
: m_count(0) : m_mutex(0), m_count(0)
{ {
m_mutex = reinterpret_cast<void*>(new(std::nothrow) CRITICAL_SECTION); try
{
m_mutex = reinterpret_cast<void*>(new CRITICAL_SECTION);
}
catch (...)
{
}
if (!m_mutex) if (!m_mutex)
throw thread_resource_error(); throw thread_resource_error();
InitializeCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(m_mutex)); InitializeCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(m_mutex));
@@ -201,7 +207,8 @@ bool recursive_timed_mutex::do_timedlock(const xtime& xt)
to_duration(xt, milliseconds); to_duration(xt, milliseconds);
unsigned int res = 0; unsigned int res = 0;
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), milliseconds); res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex),
milliseconds);
assert(res != WAIT_FAILED && res != WAIT_ABANDONED); assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
if (res == WAIT_TIMEOUT) if (res == WAIT_TIMEOUT)
@@ -798,7 +805,8 @@ recursive_mutex::~recursive_mutex()
void recursive_mutex::do_lock() void recursive_mutex::do_lock()
{ {
OSStatus lStatus = noErr; OSStatus lStatus = noErr;
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex); lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
m_mutex_mutex);
assert(lStatus == noErr); assert(lStatus == noErr);
if (++m_count > 1) if (++m_count > 1)
@@ -821,7 +829,8 @@ void recursive_mutex::do_unlock()
void recursive_mutex::do_lock(cv_state& state) void recursive_mutex::do_lock(cv_state& state)
{ {
OSStatus lStatus = noErr; OSStatus lStatus = noErr;
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex); lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
m_mutex_mutex);
assert(lStatus == noErr); assert(lStatus == noErr);
m_count = state; m_count = state;
@@ -849,7 +858,8 @@ recursive_try_mutex::~recursive_try_mutex()
void recursive_try_mutex::do_lock() void recursive_try_mutex::do_lock()
{ {
OSStatus lStatus = noErr; OSStatus lStatus = noErr;
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex); lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
m_mutex_mutex);
assert(lStatus == noErr); assert(lStatus == noErr);
if (++m_count > 1) if (++m_count > 1)
@@ -890,7 +900,8 @@ void recursive_try_mutex::do_unlock()
void recursive_try_mutex::do_lock(cv_state& state) void recursive_try_mutex::do_lock(cv_state& state)
{ {
OSStatus lStatus = noErr; OSStatus lStatus = noErr;
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex); lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
m_mutex_mutex);
assert(lStatus == noErr); assert(lStatus == noErr);
m_count = state; m_count = state;
@@ -918,7 +929,8 @@ recursive_timed_mutex::~recursive_timed_mutex()
void recursive_timed_mutex::do_lock() void recursive_timed_mutex::do_lock()
{ {
OSStatus lStatus = noErr; OSStatus lStatus = noErr;
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex); lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
m_mutex_mutex);
assert(lStatus == noErr); assert(lStatus == noErr);
if (++m_count > 1) if (++m_count > 1)
@@ -981,7 +993,8 @@ void recursive_timed_mutex::do_unlock()
void recursive_timed_mutex::do_lock(cv_state& state) void recursive_timed_mutex::do_lock(cv_state& state)
{ {
OSStatus lStatus = noErr; OSStatus lStatus = noErr;
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex); lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
m_mutex_mutex);
assert(lStatus == noErr); assert(lStatus == noErr);
m_count = state; m_count = state;

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2001 // Copyright (C) 2001-2003
// William E. Kempf // William E. Kempf
// //
// Permission to use, copy, modify, distribute and sell this software // Permission to use, copy, modify, distribute and sell this software
@@ -18,11 +18,11 @@
# include <windows.h> # include <windows.h>
# include <process.h> # include <process.h>
#elif defined(BOOST_HAS_MPTASKS) #elif defined(BOOST_HAS_MPTASKS)
# include <DriverServices.h> # include <DriverServices.h>
# include "init.hpp" # include "init.hpp"
# include "safe.hpp" # include "safe.hpp"
# include <boost/thread/tss.hpp> # include <boost/thread/tss.hpp>
#endif #endif
#include "timeconv.inl" #include "timeconv.inl"
@@ -32,7 +32,10 @@ namespace {
class thread_param class thread_param
{ {
public: public:
thread_param(const boost::function0<void>& threadfunc) : m_threadfunc(threadfunc), m_started(false) { } thread_param(const boost::function0<void>& threadfunc)
: m_threadfunc(threadfunc), m_started(false)
{
}
void wait() void wait()
{ {
boost::mutex::scoped_lock scoped_lock(m_mutex); boost::mutex::scoped_lock scoped_lock(m_mutex);
@@ -56,28 +59,28 @@ public:
extern "C" { extern "C" {
#if defined(BOOST_HAS_WINTHREADS) #if defined(BOOST_HAS_WINTHREADS)
unsigned __stdcall thread_proxy(void* param) unsigned __stdcall thread_proxy(void* param)
#elif defined(BOOST_HAS_PTHREADS) #elif defined(BOOST_HAS_PTHREADS)
static void* thread_proxy(void* param) static void* thread_proxy(void* param)
#elif defined(BOOST_HAS_MPTASKS) #elif defined(BOOST_HAS_MPTASKS)
static OSStatus thread_proxy(void* param) static OSStatus thread_proxy(void* param)
#endif #endif
{
try
{ {
thread_param* p = static_cast<thread_param*>(param); try
boost::function0<void> threadfunc = p->m_threadfunc; {
p->started(); thread_param* p = static_cast<thread_param*>(param);
threadfunc(); boost::function0<void> threadfunc = p->m_threadfunc;
} p->started();
catch (...) threadfunc();
{ }
} catch (...)
{
}
#if defined(BOOST_HAS_MPTASKS) #if defined(BOOST_HAS_MPTASKS)
::boost::detail::thread_cleanup(); ::boost::detail::thread_cleanup();
#endif #endif
return 0; return 0;
} }
} }
@@ -104,7 +107,8 @@ thread::thread(const function0<void>& threadfunc)
{ {
thread_param param(threadfunc); thread_param param(threadfunc);
#if defined(BOOST_HAS_WINTHREADS) #if defined(BOOST_HAS_WINTHREADS)
m_thread = reinterpret_cast<void*>(_beginthreadex(0, 0, &thread_proxy, &param, 0, &m_id)); m_thread = reinterpret_cast<void*>(_beginthreadex(0, 0, &thread_proxy,
&param, 0, &m_id));
if (!m_thread) if (!m_thread)
throw thread_resource_error(); throw thread_resource_error();
#elif defined(BOOST_HAS_PTHREADS) #elif defined(BOOST_HAS_PTHREADS)
@@ -121,11 +125,11 @@ thread::thread(const function0<void>& threadfunc)
m_pTaskID = kInvalidID; m_pTaskID = kInvalidID;
lStatus = MPCreateQueue(&m_pJoinQueueID); lStatus = MPCreateQueue(&m_pJoinQueueID);
if(lStatus != noErr) throw thread_resource_error(); if (lStatus != noErr) throw thread_resource_error();
lStatus = MPCreateTask(&thread_proxy, &param, 0UL, m_pJoinQueueID, NULL, NULL, lStatus = MPCreateTask(&thread_proxy, &param, 0UL, m_pJoinQueueID, NULL,
0UL, &m_pTaskID); NULL, 0UL, &m_pTaskID);
if(lStatus != noErr) if (lStatus != noErr)
{ {
lStatus = MPDeleteQueue(m_pJoinQueueID); lStatus = MPDeleteQueue(m_pJoinQueueID);
assert(lStatus == noErr); assert(lStatus == noErr);
@@ -181,7 +185,8 @@ void thread::join()
res = pthread_join(m_thread, 0); res = pthread_join(m_thread, 0);
assert(res == 0); assert(res == 0);
#elif defined(BOOST_HAS_MPTASKS) #elif defined(BOOST_HAS_MPTASKS)
OSStatus lStatus = threads::mac::detail::safe_wait_on_queue(m_pJoinQueueID, NULL, NULL, NULL, kDurationForever); OSStatus lStatus = threads::mac::detail::safe_wait_on_queue(
m_pJoinQueueID, NULL, NULL, NULL, kDurationForever);
assert(lStatus == noErr); assert(lStatus == noErr);
#endif #endif
// This isn't a race condition since any race that could occur would // This isn't a race condition since any race that could occur would
@@ -260,17 +265,20 @@ thread_group::thread_group()
thread_group::~thread_group() thread_group::~thread_group()
{ {
// We shouldn't have to scoped_lock here, since referencing this object from another thread // We shouldn't have to scoped_lock here, since referencing this object
// while we're deleting it in the current thread is going to lead to undefined behavior // from another thread while we're deleting it in the current thread is
// any way. // going to lead to undefined behavior any way.
for (std::list<thread*>::iterator it = m_threads.begin(); it != m_threads.end(); ++it) for (std::list<thread*>::iterator it = m_threads.begin();
it != m_threads.end(); ++it)
{
delete (*it); delete (*it);
}
} }
thread* thread_group::create_thread(const function0<void>& threadfunc) thread* thread_group::create_thread(const function0<void>& threadfunc)
{ {
// No scoped_lock required here since the only "shared data" that's modified here occurs // No scoped_lock required here since the only "shared data" that's
// inside add_thread which does scoped_lock. // modified here occurs inside add_thread which does scoped_lock.
std::auto_ptr<thread> thrd(new thread(threadfunc)); std::auto_ptr<thread> thrd(new thread(threadfunc));
add_thread(thrd.get()); add_thread(thrd.get());
return thrd.release(); return thrd.release();
@@ -280,9 +288,11 @@ void thread_group::add_thread(thread* thrd)
{ {
mutex::scoped_lock scoped_lock(m_mutex); mutex::scoped_lock scoped_lock(m_mutex);
// For now we'll simply ignore requests to add a thread object multiple times. // For now we'll simply ignore requests to add a thread object multiple
// Should we consider this an error and either throw or return an error value? // times. Should we consider this an error and either throw or return an
std::list<thread*>::iterator it = std::find(m_threads.begin(), m_threads.end(), thrd); // error value?
std::list<thread*>::iterator it = std::find(m_threads.begin(),
m_threads.end(), thrd);
assert(it == m_threads.end()); assert(it == m_threads.end());
if (it == m_threads.end()) if (it == m_threads.end())
m_threads.push_back(thrd); m_threads.push_back(thrd);
@@ -292,9 +302,11 @@ void thread_group::remove_thread(thread* thrd)
{ {
mutex::scoped_lock scoped_lock(m_mutex); mutex::scoped_lock scoped_lock(m_mutex);
// For now we'll simply ignore requests to remove a thread object that's not in the group. // For now we'll simply ignore requests to remove a thread object that's
// Should we consider this an error and either throw or return an error value? // not in the group. Should we consider this an error and either throw or
std::list<thread*>::iterator it = std::find(m_threads.begin(), m_threads.end(), thrd); // return an error value?
std::list<thread*>::iterator it = std::find(m_threads.begin(),
m_threads.end(), thrd);
assert(it != m_threads.end()); assert(it != m_threads.end());
if (it != m_threads.end()) if (it != m_threads.end())
m_threads.erase(it); m_threads.erase(it);
@@ -303,8 +315,11 @@ void thread_group::remove_thread(thread* thrd)
void thread_group::join_all() void thread_group::join_all()
{ {
mutex::scoped_lock scoped_lock(m_mutex); mutex::scoped_lock scoped_lock(m_mutex);
for (std::list<thread*>::iterator it = m_threads.begin(); it != m_threads.end(); ++it) for (std::list<thread*>::iterator it = m_threads.begin();
it != m_threads.end(); ++it)
{
(*it)->join(); (*it)->join();
}
} }
} // namespace boost } // namespace boost

View File

@@ -1,12 +1,23 @@
// threadmon.cpp : Defines the entry point for the DLL application. // Copyright (C) 2001-2003
// William E. Kempf
// //
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#define BOOST_THREADMON_EXPORTS #include <boost/config.hpp>
#include "threadmon.hpp"
#ifdef BOOST_HAS_WINTHREADS #if defined(BOOST_HAS_WINTHREADS)
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers #if defined(BOOST_THREAD_BUILD_DLL)
#include <boost/thread/detail/threadmon.hpp>
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#include <windows.h> #include <windows.h>
#ifdef BOOST_MSVC #ifdef BOOST_MSVC
@@ -23,9 +34,9 @@ typedef std::set<exit_handlers*> registered_handlers;
namespace namespace
{ {
CRITICAL_SECTION cs; CRITICAL_SECTION cs;
DWORD key; DWORD key;
registered_handlers registry; registered_handlers registry;
} }
#if defined(__BORLANDC__) #if defined(__BORLANDC__)
@@ -33,61 +44,75 @@ namespace
#endif #endif
extern "C" extern "C"
BOOL WINAPI DllMain(HANDLE module, DWORD reason, LPVOID) BOOL WINAPI DllMain(HANDLE /*module*/, DWORD reason, LPVOID)
{ {
switch (reason) switch (reason)
{ {
case DLL_PROCESS_ATTACH: case DLL_PROCESS_ATTACH:
InitializeCriticalSection(&cs); InitializeCriticalSection(&cs);
key = TlsAlloc(); key = TlsAlloc();
break; break;
case DLL_THREAD_ATTACH: case DLL_THREAD_ATTACH:
break; break;
case DLL_THREAD_DETACH: case DLL_THREAD_DETACH:
{
// Call the thread's exit handlers.
exit_handlers* handlers =
static_cast<exit_handlers*>(TlsGetValue(key));
if (handlers)
{
for (exit_handlers::iterator it = handlers->begin();
it != handlers->end(); ++it)
{ {
// Call the thread's exit handlers. (*it)();
exit_handlers* handlers = static_cast<exit_handlers*>(TlsGetValue(key));
if (handlers)
{
for (exit_handlers::iterator it = handlers->begin(); it != handlers->end(); ++it)
(*it)();
// Remove the exit handler list from the registered lists and then destroy it.
EnterCriticalSection(&cs);
registry.erase(handlers);
LeaveCriticalSection(&cs);
delete handlers;
}
} }
break;
case DLL_PROCESS_DETACH: // Remove the exit handler list from the registered lists
// and then destroy it.
EnterCriticalSection(&cs);
registry.erase(handlers);
LeaveCriticalSection(&cs);
delete handlers;
}
}
break;
case DLL_PROCESS_DETACH:
{
// Assume the main thread is ending (call its handlers) and
// all other threads have already ended. If this DLL is
// loaded and unloaded dynamically at run time
// this is a bad assumption, but this is the best we can do.
exit_handlers* handlers =
static_cast<exit_handlers*>(TlsGetValue(key));
if (handlers)
{
for (exit_handlers::iterator it = handlers->begin();
it != handlers->end(); ++it)
{ {
// Assume the main thread is ending (call its handlers) and all other threads (*it)();
// have already ended. If this DLL is loaded and unloaded dynamically at run time
// this is a bad assumption, but this is the best we can do.
exit_handlers* handlers = static_cast<exit_handlers*>(TlsGetValue(key));
if (handlers)
{
for (exit_handlers::iterator it = handlers->begin(); it != handlers->end(); ++it)
(*it)();
}
// Destroy any remaining exit handlers. Above we assumed there'd only be the main
// thread left, but to insure we don't get memory leaks we won't make that assumption
// here.
EnterCriticalSection(&cs);
for (registered_handlers::iterator it = registry.begin(); it != registry.end(); ++it)
delete (*it);
LeaveCriticalSection(&cs);
DeleteCriticalSection(&cs);
TlsFree(key);
} }
break; }
// Destroy any remaining exit handlers. Above we assumed
// there'd only be the main thread left, but to insure we
// don't get memory leaks we won't make that assumption
// here.
EnterCriticalSection(&cs);
for (registered_handlers::iterator it = registry.begin();
it != registry.end(); ++it)
{
delete (*it);
}
LeaveCriticalSection(&cs);
DeleteCriticalSection(&cs);
TlsFree(key);
}
break;
} }
return TRUE; return TRUE;
} }
int on_thread_exit(void (__cdecl * func)(void)) extern "C" BOOST_THREAD_DECL int on_thread_exit(void (__cdecl * func)(void))
{ {
// Get the exit handlers for the current thread, creating and registering // Get the exit handlers for the current thread, creating and registering
// one if it doesn't exist. // one if it doesn't exist.
@@ -97,7 +122,7 @@ int on_thread_exit(void (__cdecl * func)(void))
try try
{ {
handlers = new exit_handlers; handlers = new exit_handlers;
// Handle "broken" implementations of operator new that don't throw. // Handle broken implementations of operator new that don't throw.
if (!handlers) if (!handlers)
return -1; return -1;
} }
@@ -129,8 +154,8 @@ int on_thread_exit(void (__cdecl * func)(void))
} }
} }
// Attempt to add the handler to the list of exit handlers. If it's been previously // Attempt to add the handler to the list of exit handlers. If it's been
// added just report success and exit. // previously added just report success and exit.
try try
{ {
handlers->push_front(func); handlers->push_front(func);
@@ -143,4 +168,6 @@ int on_thread_exit(void (__cdecl * func)(void))
return 0; return 0;
} }
#endif // BOOST_THREAD_BUILD_DLL
#endif // BOOST_HAS_WINTHREADS #endif // BOOST_HAS_WINTHREADS

View File

@@ -1,23 +0,0 @@
#include <boost/config.hpp>
#ifndef BOOST_HAS_THREADS
# error Thread support is unavailable!
#endif
#ifdef BOOST_HAS_WINTHREADS
// The following ifdef block is the standard way of creating macros which make exporting
// from a DLL simpler. All files within this DLL are compiled with the BOOST_THREADMON_EXPORTS
// symbol defined on the command line. this symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see
// BOOST_THREADMON_API functions as being imported from a DLL, wheras this DLL sees symbols
// defined with this macro as being exported.
#ifdef BOOST_THREADMON_EXPORTS
#define BOOST_THREADMON_API __declspec(dllexport)
#else
#define BOOST_THREADMON_API __declspec(dllimport)
#endif
extern "C" BOOST_THREADMON_API int on_thread_exit(void (__cdecl * func)(void));
#endif // BOOST_HAS_WINTHREADS

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2001 // Copyright (C) 2001-2003
// William E. Kempf // William E. Kempf
// //
// Permission to use, copy, modify, distribute and sell this software // Permission to use, copy, modify, distribute and sell this software
@@ -10,113 +10,119 @@
// It is provided "as is" without express or implied warranty. // It is provided "as is" without express or implied warranty.
namespace { namespace {
const int MILLISECONDS_PER_SECOND = 1000; const int MILLISECONDS_PER_SECOND = 1000;
const int NANOSECONDS_PER_SECOND = 1000000000; const int NANOSECONDS_PER_SECOND = 1000000000;
const int NANOSECONDS_PER_MILLISECOND = 1000000; const int NANOSECONDS_PER_MILLISECOND = 1000000;
const int MICROSECONDS_PER_SECOND = 1000000; const int MICROSECONDS_PER_SECOND = 1000000;
const int NANOSECONDS_PER_MICROSECOND = 1000; const int NANOSECONDS_PER_MICROSECOND = 1000;
inline void to_time(int milliseconds, boost::xtime& xt) inline void to_time(int milliseconds, boost::xtime& xt)
{
int res = 0;
res = boost::xtime_get(&xt, boost::TIME_UTC);
assert(res == boost::TIME_UTC);
xt.sec += (milliseconds / MILLISECONDS_PER_SECOND);
xt.nsec += ((milliseconds % MILLISECONDS_PER_SECOND) *
NANOSECONDS_PER_MILLISECOND);
if (xt.nsec > static_cast<const int>(NANOSECONDS_PER_SECOND))
{ {
int res = 0; ++xt.sec;
res = boost::xtime_get(&xt, boost::TIME_UTC); xt.nsec -= NANOSECONDS_PER_SECOND;
assert(res == boost::TIME_UTC);
xt.sec += (milliseconds / MILLISECONDS_PER_SECOND);
xt.nsec += ((milliseconds % MILLISECONDS_PER_SECOND) * NANOSECONDS_PER_MILLISECOND);
if (xt.nsec > static_cast<const int>(NANOSECONDS_PER_SECOND))
{
++xt.sec;
xt.nsec -= NANOSECONDS_PER_SECOND;
}
} }
}
#if defined(BOOST_HAS_PTHREADS) #if defined(BOOST_HAS_PTHREADS)
inline void to_timespec(const boost::xtime& xt, timespec& ts) inline void to_timespec(const boost::xtime& xt, timespec& ts)
{
ts.tv_sec = static_cast<int>(xt.sec);
ts.tv_nsec = static_cast<int>(xt.nsec);
if(ts.tv_nsec > static_cast<const int>(NANOSECONDS_PER_SECOND))
{ {
ts.tv_sec = static_cast<int>(xt.sec); ts.tv_sec += ts.tv_nsec / NANOSECONDS_PER_SECOND;
ts.tv_nsec = static_cast<int>(xt.nsec); ts.tv_nsec %= NANOSECONDS_PER_SECOND;
}
}
inline void to_time(int milliseconds, timespec& ts)
{
boost::xtime xt;
to_time(milliseconds, xt);
to_timespec(xt, ts);
}
inline void to_timespec_duration(const boost::xtime& xt, timespec& ts)
{
boost::xtime cur;
int res = 0;
res = boost::xtime_get(&cur, boost::TIME_UTC);
assert(res == boost::TIME_UTC);
if (boost::xtime_cmp(xt, cur) <= 0)
{
ts.tv_sec = 0;
ts.tv_nsec = 0;
}
else
{
ts.tv_sec = xt.sec - cur.sec;
ts.tv_nsec = xt.nsec - cur.nsec;
if( ts.tv_nsec < 0 )
{
ts.tv_sec -= 1;
ts.tv_nsec += NANOSECONDS_PER_SECOND;
}
if(ts.tv_nsec > static_cast<const int>(NANOSECONDS_PER_SECOND)) if(ts.tv_nsec > static_cast<const int>(NANOSECONDS_PER_SECOND))
{ {
ts.tv_sec += ts.tv_nsec / NANOSECONDS_PER_SECOND; ts.tv_sec += ts.tv_nsec / NANOSECONDS_PER_SECOND;
ts.tv_nsec %= NANOSECONDS_PER_SECOND; ts.tv_nsec %= NANOSECONDS_PER_SECOND;
} }
} }
}
inline void to_time(int milliseconds, timespec& ts)
{
boost::xtime xt;
to_time(milliseconds, xt);
to_timespec(xt, ts);
}
inline void to_timespec_duration(const boost::xtime& xt, timespec& ts)
{
boost::xtime cur;
int res = 0;
res = boost::xtime_get(&cur, boost::TIME_UTC);
assert(res == boost::TIME_UTC);
if (boost::xtime_cmp(xt, cur) <= 0)
{
ts.tv_sec = 0;
ts.tv_nsec = 0;
}
else
{
ts.tv_sec = xt.sec - cur.sec;
ts.tv_nsec = xt.nsec - cur.nsec;
if( ts.tv_nsec < 0 )
{
ts.tv_sec -= 1;
ts.tv_nsec += NANOSECONDS_PER_SECOND;
}
if(ts.tv_nsec > static_cast<const int>(NANOSECONDS_PER_SECOND))
{
ts.tv_sec += ts.tv_nsec / NANOSECONDS_PER_SECOND;
ts.tv_nsec %= NANOSECONDS_PER_SECOND;
}
}
}
#endif #endif
inline void to_duration(const boost::xtime& xt, int& milliseconds) inline void to_duration(boost::xtime xt, int& milliseconds)
{ {
boost::xtime cur; boost::xtime cur;
int res = 0; int res = 0;
res = boost::xtime_get(&cur, boost::TIME_UTC); res = boost::xtime_get(&cur, boost::TIME_UTC);
assert(res == boost::TIME_UTC); assert(res == boost::TIME_UTC);
if (boost::xtime_cmp(xt, cur) <= 0) if (boost::xtime_cmp(xt, cur) <= 0)
milliseconds = 0; milliseconds = 0;
else else
{
if (cur.nsec > xt.nsec)
{ {
milliseconds = ((xt.sec - cur.sec) * MILLISECONDS_PER_SECOND) + xt.nsec += NANOSECONDS_PER_SECOND;
(((xt.nsec - cur.nsec) + (NANOSECONDS_PER_MILLISECOND/2)) / --xt.sec;
}
milliseconds = (int)((xt.sec - cur.sec) * MILLISECONDS_PER_SECOND) +
(((xt.nsec - cur.nsec) + (NANOSECONDS_PER_MILLISECOND/2)) /
NANOSECONDS_PER_MILLISECOND); NANOSECONDS_PER_MILLISECOND);
}
} }
}
inline void to_microduration(const boost::xtime& xt, int& microseconds) inline void to_microduration(const boost::xtime& xt, int& microseconds)
{
boost::xtime cur;
int res = 0;
res = boost::xtime_get(&cur, boost::TIME_UTC);
assert(res == boost::TIME_UTC);
if (boost::xtime_get(&cur, boost::TIME_UTC) <= 0)
microseconds = 0;
else
{ {
boost::xtime cur; microseconds = (int)((xt.sec - cur.sec) * MICROSECONDS_PER_SECOND) +
int res = 0; (((xt.nsec - cur.nsec) + (NANOSECONDS_PER_MICROSECOND/2)) /
res = boost::xtime_get(&cur, boost::TIME_UTC);
assert(res == boost::TIME_UTC);
if (boost::xtime_get(&cur, boost::TIME_UTC) <= 0)
microseconds = 0;
else
{
microseconds = ((xt.sec - cur.sec) * MICROSECONDS_PER_SECOND) +
(((xt.nsec - cur.nsec) + (NANOSECONDS_PER_MICROSECOND/2)) /
NANOSECONDS_PER_MICROSECOND); NANOSECONDS_PER_MICROSECOND);
}
} }
} }
}
// Change Log: // Change Log:
// 1 Jun 01 Initial creation. // 1 Jun 01 Initial creation.

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2001 // Copyright (C) 2001-2003
// William E. Kempf // William E. Kempf
// //
// Permission to use, copy, modify, distribute and sell this software // Permission to use, copy, modify, distribute and sell this software
@@ -20,97 +20,103 @@
#endif #endif
#if defined(BOOST_HAS_WINTHREADS) #if defined(BOOST_HAS_WINTHREADS)
#include "threadmon.hpp" #include <boost/thread/detail/threadmon.hpp>
#include <map> #include <map>
namespace { namespace {
typedef std::pair<void(*)(void*), void*> cleanup_info; typedef std::pair<void(*)(void*), void*> cleanup_info;
typedef std::map<int, cleanup_info> cleanup_handlers; typedef std::map<int, cleanup_info> cleanup_handlers;
DWORD key; DWORD key;
boost::once_flag once = BOOST_ONCE_INIT; boost::once_flag once = BOOST_ONCE_INIT;
void init_cleanup_key() void init_cleanup_key()
{
key = TlsAlloc();
assert(key != 0xFFFFFFFF);
}
void __cdecl cleanup()
{
cleanup_handlers* handlers = static_cast<cleanup_handlers*>(
TlsGetValue(key));
for (cleanup_handlers::iterator it = handlers->begin();
it != handlers->end(); ++it)
{ {
key = TlsAlloc(); cleanup_info info = it->second;
assert(key != 0xFFFFFFFF); if (info.second)
info.first(info.second);
} }
delete handlers;
}
void __cdecl cleanup() cleanup_handlers* get_handlers()
{
boost::call_once(&init_cleanup_key, once);
cleanup_handlers* handlers = static_cast<cleanup_handlers*>(
TlsGetValue(key));
if (!handlers)
{ {
cleanup_handlers* handlers = static_cast<cleanup_handlers*>(TlsGetValue(key)); try
for (cleanup_handlers::iterator it = handlers->begin(); it != handlers->end(); ++it)
{ {
cleanup_info info = it->second; handlers = new cleanup_handlers;
if (info.second)
info.first(info.second);
} }
delete handlers; catch (...)
}
cleanup_handlers* get_handlers()
{
boost::call_once(&init_cleanup_key, once);
cleanup_handlers* handlers = static_cast<cleanup_handlers*>(TlsGetValue(key));
if (!handlers)
{ {
try return 0;
{
handlers = new cleanup_handlers;
}
catch (...)
{
return 0;
}
int res = 0;
res = TlsSetValue(key, handlers);
assert(res);
res = on_thread_exit(&cleanup);
assert(res == 0);
} }
int res = 0;
return handlers; res = TlsSetValue(key, handlers);
assert(res);
res = on_thread_exit(&cleanup);
assert(res == 0);
} }
return handlers;
}
} }
#elif defined(BOOST_HAS_MPTASKS) #elif defined(BOOST_HAS_MPTASKS)
#include <map> #include <map>
namespace { namespace {
typedef std::pair<void(*)(void*), void*> cleanup_info; typedef std::pair<void(*)(void*), void*> cleanup_info;
typedef std::map<int, cleanup_info> cleanup_handlers; typedef std::map<int, cleanup_info> cleanup_handlers;
TaskStorageIndex key; TaskStorageIndex key;
boost::once_flag once = BOOST_ONCE_INIT; boost::once_flag once = BOOST_ONCE_INIT;
void init_cleanup_key() void init_cleanup_key()
{
OSStatus lStatus = MPAllocateTaskStorageIndex(&key);
assert(lStatus == noErr);
}
cleanup_handlers* get_handlers()
{
boost::call_once(&init_cleanup_key, once);
cleanup_handlers* handlers = reinterpret_cast<cleanup_handlers*>(
MPGetTaskStorageValue(key));
if (!handlers)
{ {
OSStatus lStatus = MPAllocateTaskStorageIndex(&key); try
assert(lStatus == noErr);
}
cleanup_handlers* get_handlers()
{
boost::call_once(&init_cleanup_key, once);
cleanup_handlers* handlers = reinterpret_cast<cleanup_handlers*>(MPGetTaskStorageValue(key));
if (!handlers)
{ {
try handlers = new cleanup_handlers;
{
handlers = new cleanup_handlers;
}
catch (...)
{
return 0;
}
OSStatus lStatus = noErr;
lStatus = MPSetTaskStorageValue(key, reinterpret_cast<TaskStorageValue>(handlers));
assert(lStatus == noErr);
// TODO - create a generalized mechanism for registering thread exit functions
// and use it here.
} }
catch (...)
return handlers; {
return 0;
}
OSStatus lStatus = noErr;
lStatus = MPSetTaskStorageValue(key,
reinterpret_cast<TaskStorageValue>(handlers));
assert(lStatus == noErr);
// TODO - create a generalized mechanism for registering thread exit
// functions and use it here.
} }
return handlers;
}
} }
namespace boost { namespace boost {
@@ -120,10 +126,12 @@ namespace detail {
void thread_cleanup() void thread_cleanup()
{ {
cleanup_handlers* handlers = reinterpret_cast<cleanup_handlers*>(MPGetTaskStorageValue(key)); cleanup_handlers* handlers = reinterpret_cast<cleanup_handlers*>(
MPGetTaskStorageValue(key));
if(handlers != NULL) if(handlers != NULL)
{ {
for (cleanup_handlers::iterator it = handlers->begin(); it != handlers->end(); ++it) for (cleanup_handlers::iterator it = handlers->begin();
it != handlers->end(); ++it)
{ {
cleanup_info info = it->second; cleanup_info info = it->second;
if (info.second) if (info.second)
@@ -235,7 +243,8 @@ bool tss::set(void* value)
cleanup_info info(m_cleanup, value); cleanup_info info(m_cleanup, value);
(*handlers)[m_key] = info; (*handlers)[m_key] = info;
} }
OSStatus lStatus = MPSetTaskStorageValue(m_key, reinterpret_cast<TaskStorageValue>(value)); OSStatus lStatus = MPSetTaskStorageValue(m_key,
reinterpret_cast<TaskStorageValue>(value));
return(lStatus == noErr); return(lStatus == noErr);
} }
#endif #endif

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2001 // Copyright (C) 2001-2003
// William E. Kempf // William E. Kempf
// //
// Permission to use, copy, modify, distribute and sell this software // Permission to use, copy, modify, distribute and sell this software
@@ -33,29 +33,30 @@ struct startup_time_info
{ {
startup_time_info() startup_time_info()
{ {
// 1970 Jan 1 at 00:00:00 // 1970 Jan 1 at 00:00:00
static const DateTimeRec k_sUNIXBase = {1970, 1, 1, 0, 0, 0, 0}; static const DateTimeRec k_sUNIXBase = {1970, 1, 1, 0, 0, 0, 0};
static unsigned long s_ulUNIXBaseSeconds = 0UL; static unsigned long s_ulUNIXBaseSeconds = 0UL;
if(s_ulUNIXBaseSeconds == 0UL) if(s_ulUNIXBaseSeconds == 0UL)
{ {
// calculate the number of seconds between the Mac OS base and the UNIX base // calculate the number of seconds between the Mac OS base and the
// the first time we enter this constructor. // UNIX base the first time we enter this constructor.
DateToSeconds(&k_sUNIXBase, &s_ulUNIXBaseSeconds); DateToSeconds(&k_sUNIXBase, &s_ulUNIXBaseSeconds);
} }
unsigned long ulSeconds; unsigned long ulSeconds;
// get the time in UpTime units twice, with the time in seconds in the middle. // get the time in UpTime units twice, with the time in seconds in the
// middle.
uint64_t ullFirstUpTime = force_cast<uint64_t>(UpTime()); uint64_t ullFirstUpTime = force_cast<uint64_t>(UpTime());
GetDateTime(&ulSeconds); GetDateTime(&ulSeconds);
uint64_t ullSecondUpTime = force_cast<uint64_t>(UpTime()); uint64_t ullSecondUpTime = force_cast<uint64_t>(UpTime());
// calculate the midpoint of the two UpTimes, and save that. // calculate the midpoint of the two UpTimes, and save that.
uint64_t ullAverageUpTime = (ullFirstUpTime + ullSecondUpTime) / 2ULL; uint64_t ullAverageUpTime = (ullFirstUpTime + ullSecondUpTime) / 2ULL;
m_sStartupAbsoluteTime = force_cast<AbsoluteTime>(ullAverageUpTime); m_sStartupAbsoluteTime = force_cast<AbsoluteTime>(ullAverageUpTime);
// save the number of seconds, recentered at the UNIX base. // save the number of seconds, recentered at the UNIX base.
m_ulStartupSeconds = ulSeconds - s_ulUNIXBaseSeconds; m_ulStartupSeconds = ulSeconds - s_ulUNIXBaseSeconds;
} }
@@ -77,10 +78,13 @@ int xtime_get(struct xtime* xtp, int clock_type)
#if defined(BOOST_HAS_FTIME) #if defined(BOOST_HAS_FTIME)
FILETIME ft; FILETIME ft;
GetSystemTimeAsFileTime(&ft); GetSystemTimeAsFileTime(&ft);
const boost::uint64_t TIMESPEC_TO_FILETIME_OFFSET = ((boost::uint64_t)27111902UL << 32) + (boost::uint64_t)3577643008UL; const boost::uint64_t TIMESPEC_TO_FILETIME_OFFSET =
xtp->sec = (int)((*(__int64*)&ft - TIMESPEC_TO_FILETIME_OFFSET) / 10000000); ((boost::uint64_t)27111902UL << 32) +
(boost::uint64_t)3577643008UL;
xtp->sec = (int)((*(__int64*)&ft - TIMESPEC_TO_FILETIME_OFFSET) /
10000000);
xtp->nsec = (int)((*(__int64*)&ft - TIMESPEC_TO_FILETIME_OFFSET - xtp->nsec = (int)((*(__int64*)&ft - TIMESPEC_TO_FILETIME_OFFSET -
((__int64)xtp->sec * (__int64)10000000)) * 100); ((__int64)xtp->sec * (__int64)10000000)) * 100);
return clock_type; return clock_type;
#elif defined(BOOST_HAS_GETTIMEOFDAY) #elif defined(BOOST_HAS_GETTIMEOFDAY)
struct timeval tv; struct timeval tv;
@@ -96,12 +100,16 @@ int xtime_get(struct xtime* xtp, int clock_type)
return clock_type; return clock_type;
#elif defined(BOOST_HAS_MPTASKS) #elif defined(BOOST_HAS_MPTASKS)
using detail::thread::force_cast; using detail::thread::force_cast;
// the Mac OS does not have an MP-safe way of getting the date/time, so we use a // the Mac OS does not have an MP-safe way of getting the date/time,
// delta from the startup time. We _could_ defer this and use something that is // so we use a delta from the startup time. We _could_ defer this
// interrupt-safe, but this would be _SLOW_, and we need speed here. // and use something that is interrupt-safe, but this would be _SLOW_,
// and we need speed here.
const uint64_t k_ullNanosecondsPerSecond(1000ULL * 1000ULL * 1000ULL); const uint64_t k_ullNanosecondsPerSecond(1000ULL * 1000ULL * 1000ULL);
AbsoluteTime sUpTime(UpTime()); AbsoluteTime sUpTime(UpTime());
uint64_t ullNanoseconds(force_cast<uint64_t>(AbsoluteDeltaToNanoseconds(sUpTime, detail::g_sStartupTimeInfo.m_sStartupAbsoluteTime))); uint64_t ullNanoseconds(
force_cast<uint64_t>(
AbsoluteDeltaToNanoseconds(sUpTime,
detail::g_sStartupTimeInfo.m_sStartupAbsoluteTime)));
uint64_t ullSeconds = (ullNanoseconds / k_ullNanosecondsPerSecond); uint64_t ullSeconds = (ullNanoseconds / k_ullNanosecondsPerSecond);
ullNanoseconds -= (ullSeconds * k_ullNanosecondsPerSecond); ullNanoseconds -= (ullSeconds * k_ullNanosecondsPerSecond);
xtp->sec = detail::g_sStartupTimeInfo.m_ulStartupSeconds + ullSeconds; xtp->sec = detail::g_sStartupTimeInfo.m_ulStartupSeconds + ullSeconds;

View File

@@ -1,12 +1,10 @@
# (C) Copyright William E. Kempf 2001. Permission to copy, use, modify, sell and # (C) Copyright William E. Kempf 2001. Permission to copy, use, modify, sell
# distribute this software is granted provided this copyright notice appears # and distribute this software is granted provided this copyright notice
# in all copies. This software is provided "as is" without express or implied # appears in all copies. This software is provided "as is" without express or
# warranty, and with no claim as to its suitability for any purpose. # implied warranty, and with no claim as to its suitability for any purpose.
# #
# Boost.Threads test Jamfile # Boost.Threads test Jamfile
# #
# Declares the following targets:
# 1. test_thread, a unit test executable.
# Additional configuration variables used: # Additional configuration variables used:
# 1. PTW32 may be used on Win32 platforms to specify that the pthreads-win32 # 1. PTW32 may be used on Win32 platforms to specify that the pthreads-win32
# library should be used instead of "native" threads. This feature is # library should be used instead of "native" threads. This feature is
@@ -30,23 +28,24 @@ include threads.jam ;
SEARCH on testing.jam = $(BOOST_BUILD_PATH) ; SEARCH on testing.jam = $(BOOST_BUILD_PATH) ;
include testing.jam ; include testing.jam ;
sources = test.cpp test_thread.cpp test_mutex.cpp test_condition.cpp test_tss.cpp test_once.cpp ; {
template test
## sources ##
: <template>thread_base
<dll>../build/boost_thread
<lib>../../test/build/boost_unit_test_framework
## requirements ##
:
## default build ##
:
;
template test test-suite "threads"
## sources ## : [ run test_thread.cpp <template>test ]
: <template>thread_base <lib>../build/boost_thread <lib>../../test/build/unit_test_framework $(threadmon) [ run test_mutex.cpp <template>test ]
## requirements ## [ run test_condition.cpp <template>test ]
: [ run test_tss.cpp <template>test ]
## default build ## [ run test_once.cpp <template>test ]
: debug release <runtime-link>static/dynamic [ run test_xtime.cpp <template>test ]
; ;
}
#######################
# Declare the Boost.Threads unit test program test_thread.
run test_thread.cpp <template>test ;
run test_mutex.cpp <template>test ;
run test_condition.cpp <template>test ;
run test_tss.cpp <template>test ;
run test_once.cpp <template>test ;
run test_xtime.cpp <template>test ;

View File

@@ -1,103 +1,97 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/condition.hpp> #include <boost/thread/condition.hpp>
#include <boost/thread/thread.hpp> #include <boost/thread/thread.hpp>
#include <boost/thread/xtime.hpp> #include <boost/thread/xtime.hpp>
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
namespace #include "util.inl"
struct condition_test_data
{ {
struct condition_test_data condition_test_data() : notified(0), awoken(0) { }
{
condition_test_data() : notified(0), awoken(0) { }
boost::mutex mutex; boost::mutex mutex;
boost::condition condition; boost::condition condition;
int notified; int notified;
int awoken; int awoken;
}; };
void condition_test_thread(void* param) void condition_test_thread(condition_test_data* data)
{ {
condition_test_data* data = static_cast<condition_test_data*>(param); boost::mutex::scoped_lock lock(data->mutex);
boost::mutex::scoped_lock lock(data->mutex); BOOST_CHECK(lock ? true : false);
BOOST_CHECK(lock ? true : false); while (!(data->notified > 0))
while (!(data->notified > 0)) data->condition.wait(lock);
data->condition.wait(lock); BOOST_CHECK(lock ? true : false);
BOOST_CHECK(lock ? true : false); data->awoken++;
data->awoken++;
}
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;
};
struct cond_predicate
{
cond_predicate(int& var, int val) : _var(var), _val(val) { }
bool operator()() { return _var == _val; }
int& _var;
int _val;
};
void condition_test_waits(void* param)
{
condition_test_data* data = static_cast<condition_test_data*>(param);
boost::mutex::scoped_lock lock(data->mutex);
BOOST_CHECK(lock ? true : false);
// Test wait.
while (data->notified != 1)
data->condition.wait(lock);
BOOST_CHECK(lock ? true : false);
BOOST_CHECK_EQUAL(data->notified, 1);
data->awoken++;
data->condition.notify_one();
// Test predicate wait.
data->condition.wait(lock, cond_predicate(data->notified, 2));
BOOST_CHECK(lock ? true : false);
BOOST_CHECK_EQUAL(data->notified, 2);
data->awoken++;
data->condition.notify_one();
// Test timed_wait.
boost::xtime xt;
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
xt.sec += 10;
while (data->notified != 3)
data->condition.timed_wait(lock, xt);
BOOST_CHECK(lock ? true : false);
BOOST_CHECK_EQUAL(data->notified, 3);
data->awoken++;
data->condition.notify_one();
// Test predicate timed_wait.
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
xt.sec += 10;
cond_predicate pred(data->notified, 4);
BOOST_CHECK(data->condition.timed_wait(lock, xt, pred));
BOOST_CHECK(lock ? true : false);
BOOST_CHECK(pred());
BOOST_CHECK_EQUAL(data->notified, 4);
data->awoken++;
data->condition.notify_one();
}
} }
void test_condition_notify_one() struct cond_predicate
{
cond_predicate(int& var, int val) : _var(var), _val(val) { }
bool operator()() { return _var == _val; }
int& _var;
int _val;
};
void condition_test_waits(condition_test_data* data)
{
boost::mutex::scoped_lock lock(data->mutex);
BOOST_CHECK(lock ? true : false);
// Test wait.
while (data->notified != 1)
data->condition.wait(lock);
BOOST_CHECK(lock ? true : false);
BOOST_CHECK_EQUAL(data->notified, 1);
data->awoken++;
data->condition.notify_one();
// Test predicate wait.
data->condition.wait(lock, cond_predicate(data->notified, 2));
BOOST_CHECK(lock ? true : false);
BOOST_CHECK_EQUAL(data->notified, 2);
data->awoken++;
data->condition.notify_one();
// Test timed_wait.
boost::xtime xt = delay(10);
while (data->notified != 3)
data->condition.timed_wait(lock, xt);
BOOST_CHECK(lock ? true : false);
BOOST_CHECK_EQUAL(data->notified, 3);
data->awoken++;
data->condition.notify_one();
// Test predicate timed_wait.
xt = delay(10);
cond_predicate pred(data->notified, 4);
BOOST_CHECK(data->condition.timed_wait(lock, xt, pred));
BOOST_CHECK(lock ? true : false);
BOOST_CHECK(pred());
BOOST_CHECK_EQUAL(data->notified, 4);
data->awoken++;
data->condition.notify_one();
}
void do_test_condition_notify_one()
{ {
condition_test_data data; condition_test_data data;
boost::thread thread(thread_adapter(&condition_test_thread, &data)); boost::thread thread(bind(&condition_test_thread, &data));
{ {
boost::mutex::scoped_lock lock(data.mutex); boost::mutex::scoped_lock lock(data.mutex);
@@ -110,14 +104,19 @@ void test_condition_notify_one()
BOOST_CHECK_EQUAL(data.awoken, 1); BOOST_CHECK_EQUAL(data.awoken, 1);
} }
void test_condition_notify_all() void test_condition_notify_one()
{
timed_test(&do_test_condition_notify_one, 2, execution_monitor::use_mutex);
}
void do_test_condition_notify_all()
{ {
const int NUMTHREADS = 5; const int NUMTHREADS = 5;
boost::thread_group threads; boost::thread_group threads;
condition_test_data data; condition_test_data data;
for (int i = 0; i < NUMTHREADS; ++i) for (int i = 0; i < NUMTHREADS; ++i)
threads.create_thread(thread_adapter(&condition_test_thread, &data)); threads.create_thread(bind(&condition_test_thread, &data));
{ {
boost::mutex::scoped_lock lock(data.mutex); boost::mutex::scoped_lock lock(data.mutex);
@@ -130,21 +129,25 @@ void test_condition_notify_all()
BOOST_CHECK_EQUAL(data.awoken, NUMTHREADS); BOOST_CHECK_EQUAL(data.awoken, NUMTHREADS);
} }
void test_condition_waits() void test_condition_notify_all()
{
// We should have already tested notify_one here, so
// a timed test with the default execution_monitor::use_condition
// should be OK, and gives the fastest performance
timed_test(&do_test_condition_notify_all, 3);
}
void do_test_condition_waits()
{ {
condition_test_data data; condition_test_data data;
boost::thread thread(thread_adapter(&condition_test_waits, &data)); boost::thread thread(bind(&condition_test_waits, &data));
boost::xtime xt;
{ {
boost::mutex::scoped_lock lock(data.mutex); boost::mutex::scoped_lock lock(data.mutex);
BOOST_CHECK(lock ? true : false); BOOST_CHECK(lock ? true : false);
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC)); boost::thread::sleep(delay(1));
xt.sec += 1;
boost::thread::sleep(xt);
data.notified++; data.notified++;
data.condition.notify_one(); data.condition.notify_one();
while (data.awoken != 1) while (data.awoken != 1)
@@ -152,9 +155,7 @@ void test_condition_waits()
BOOST_CHECK(lock ? true : false); BOOST_CHECK(lock ? true : false);
BOOST_CHECK_EQUAL(data.awoken, 1); BOOST_CHECK_EQUAL(data.awoken, 1);
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC)); boost::thread::sleep(delay(1));
xt.sec += 1;
boost::thread::sleep(xt);
data.notified++; data.notified++;
data.condition.notify_one(); data.condition.notify_one();
while (data.awoken != 2) while (data.awoken != 2)
@@ -162,9 +163,7 @@ void test_condition_waits()
BOOST_CHECK(lock ? true : false); BOOST_CHECK(lock ? true : false);
BOOST_CHECK_EQUAL(data.awoken, 2); BOOST_CHECK_EQUAL(data.awoken, 2);
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC)); boost::thread::sleep(delay(1));
xt.sec += 1;
boost::thread::sleep(xt);
data.notified++; data.notified++;
data.condition.notify_one(); data.condition.notify_one();
while (data.awoken != 3) while (data.awoken != 3)
@@ -172,9 +171,7 @@ void test_condition_waits()
BOOST_CHECK(lock ? true : false); BOOST_CHECK(lock ? true : false);
BOOST_CHECK_EQUAL(data.awoken, 3); BOOST_CHECK_EQUAL(data.awoken, 3);
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC)); boost::thread::sleep(delay(1));
xt.sec += 1;
boost::thread::sleep(xt);
data.notified++; data.notified++;
data.condition.notify_one(); data.condition.notify_one();
while (data.awoken != 4) while (data.awoken != 4)
@@ -183,16 +180,22 @@ void test_condition_waits()
BOOST_CHECK_EQUAL(data.awoken, 4); BOOST_CHECK_EQUAL(data.awoken, 4);
} }
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
xt.sec += 1;
boost::thread::sleep(xt);
thread.join(); thread.join();
BOOST_CHECK_EQUAL(data.awoken, 4); BOOST_CHECK_EQUAL(data.awoken, 4);
} }
void test_condition_waits()
{
// We should have already tested notify_one here, so
// a timed test with the default execution_monitor::use_condition
// should be OK, and gives the fastest performance
timed_test(&do_test_condition_waits, 12);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{ {
boost::unit_test_framework::test_suite* test = BOOST_TEST_SUITE("Boost.Threads: condition test suite"); boost::unit_test_framework::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: condition test suite");
test->add(BOOST_TEST_CASE(&test_condition_notify_one)); test->add(BOOST_TEST_CASE(&test_condition_notify_one));
test->add(BOOST_TEST_CASE(&test_condition_notify_all)); test->add(BOOST_TEST_CASE(&test_condition_notify_all));

View File

@@ -1,3 +1,14 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/mutex.hpp> #include <boost/thread/mutex.hpp>
#include <boost/thread/recursive_mutex.hpp> #include <boost/thread/recursive_mutex.hpp>
#include <boost/thread/xtime.hpp> #include <boost/thread/xtime.hpp>
@@ -6,22 +17,8 @@
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
#include <boost/test/unit_test_suite_ex.hpp> #include <boost/test/unit_test_suite_ex.hpp>
namespace #define DEFAULT_EXECUTION_MONITOR_TYPE execution_monitor::use_sleep_only
{ #include "util.inl"
inline bool xtime_in_range(boost::xtime& xt, int less_seconds, int greater_seconds)
{
boost::xtime cur;
BOOST_CHECK_EQUAL(boost::xtime_get(&cur, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
boost::xtime less = cur;
less.sec += less_seconds;
boost::xtime greater = cur;
greater.sec += greater_seconds;
return (boost::xtime_cmp(xt, less) >= 0) && (boost::xtime_cmp(xt, greater) <= 0);
}
}
template <typename M> template <typename M>
struct test_lock struct test_lock
@@ -43,9 +40,7 @@ struct test_lock
BOOST_CHECK(lock ? true : false); BOOST_CHECK(lock ? true : false);
// Construct and initialize an xtime for a fast time out. // Construct and initialize an xtime for a fast time out.
boost::xtime xt; boost::xtime xt = delay(0, 100);
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
xt.nsec += 100000000;
// Test the lock and the mutex with condition variables. // Test the lock and the mutex with condition variables.
// No one is going to notify this condition variable. We expect to // No one is going to notify this condition variable. We expect to
@@ -85,9 +80,7 @@ struct test_trylock
BOOST_CHECK(lock ? true : false); BOOST_CHECK(lock ? true : false);
// Construct and initialize an xtime for a fast time out. // Construct and initialize an xtime for a fast time out.
boost::xtime xt; boost::xtime xt = delay(0, 100);
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
xt.nsec += 100000000;
// Test the lock and the mutex with condition variables. // Test the lock and the mutex with condition variables.
// No one is going to notify this condition variable. We expect to // No one is going to notify this condition variable. We expect to
@@ -121,9 +114,7 @@ struct test_timedlock
// Test the lock's constructors. // Test the lock's constructors.
{ {
// Construct and initialize an xtime for a fast time out. // Construct and initialize an xtime for a fast time out.
boost::xtime xt; boost::xtime xt = delay(0, 100);
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
xt.nsec += 100000000;
timed_lock_type lock(mutex, xt); timed_lock_type lock(mutex, xt);
BOOST_CHECK(lock ? true : false); BOOST_CHECK(lock ? true : false);
@@ -136,16 +127,14 @@ struct test_timedlock
BOOST_CHECK(lock ? true : false); BOOST_CHECK(lock ? true : false);
// Construct and initialize an xtime for a fast time out. // Construct and initialize an xtime for a fast time out.
boost::xtime xt; boost::xtime xt = delay(0, 100);
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
xt.nsec += 100000000;
// Test the lock and the mutex with condition variables. // Test the lock and the mutex with condition variables.
// No one is going to notify this condition variable. We expect to // No one is going to notify this condition variable. We expect to
// time out. // time out.
BOOST_CHECK(!condition.timed_wait(lock, xt)); BOOST_CHECK(!condition.timed_wait(lock, xt));
BOOST_CHECK(lock ? true : false); BOOST_CHECK(lock ? true : false);
BOOST_CHECK(xtime_in_range(xt, -1, 0)); BOOST_CHECK(in_range(xt));
// Test the lock, unlock and timedlock methods. // Test the lock, unlock and timedlock methods.
lock.unlock(); lock.unlock();
@@ -154,8 +143,7 @@ struct test_timedlock
BOOST_CHECK(lock ? true : false); BOOST_CHECK(lock ? true : false);
lock.unlock(); lock.unlock();
BOOST_CHECK(!lock); BOOST_CHECK(!lock);
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC)); xt = delay(0, 100);
xt.nsec += 100000000;
BOOST_CHECK(lock.timed_lock(xt)); BOOST_CHECK(lock.timed_lock(xt));
BOOST_CHECK(lock ? true : false); BOOST_CHECK(lock ? true : false);
} }
@@ -175,38 +163,63 @@ struct test_recursive_lock
} }
}; };
void test_mutex() void do_test_mutex()
{ {
test_lock<boost::mutex>()(); test_lock<boost::mutex>()();
} }
void test_try_mutex() void test_mutex()
{
timed_test(&do_test_mutex, 3);
}
void do_test_try_mutex()
{ {
test_lock<boost::try_mutex>()(); test_lock<boost::try_mutex>()();
test_trylock<boost::try_mutex>()(); test_trylock<boost::try_mutex>()();
} }
void test_timed_mutex() void test_try_mutex()
{
timed_test(&do_test_try_mutex, 3);
}
void do_test_timed_mutex()
{ {
test_lock<boost::timed_mutex>()(); test_lock<boost::timed_mutex>()();
test_trylock<boost::timed_mutex>()(); test_trylock<boost::timed_mutex>()();
test_timedlock<boost::timed_mutex>()(); test_timedlock<boost::timed_mutex>()();
} }
void test_recursive_mutex() void test_timed_mutex()
{
timed_test(&do_test_timed_mutex, 3);
}
void do_test_recursive_mutex()
{ {
test_lock<boost::recursive_mutex>()(); test_lock<boost::recursive_mutex>()();
test_recursive_lock<boost::recursive_mutex>()(); test_recursive_lock<boost::recursive_mutex>()();
} }
void test_recursive_try_mutex() void test_recursive_mutex()
{
timed_test(&do_test_recursive_mutex, 3);
}
void do_test_recursive_try_mutex()
{ {
test_lock<boost::recursive_try_mutex>()(); test_lock<boost::recursive_try_mutex>()();
test_trylock<boost::recursive_try_mutex>()(); test_trylock<boost::recursive_try_mutex>()();
test_recursive_lock<boost::recursive_try_mutex>()(); test_recursive_lock<boost::recursive_try_mutex>()();
} }
void test_recursive_timed_mutex() void test_recursive_try_mutex()
{
timed_test(&do_test_recursive_try_mutex, 3);
}
void do_test_recursive_timed_mutex()
{ {
test_lock<boost::recursive_timed_mutex>()(); test_lock<boost::recursive_timed_mutex>()();
test_trylock<boost::recursive_timed_mutex>()(); test_trylock<boost::recursive_timed_mutex>()();
@@ -214,9 +227,15 @@ void test_recursive_timed_mutex()
test_recursive_lock<boost::recursive_timed_mutex>()(); test_recursive_lock<boost::recursive_timed_mutex>()();
} }
void test_recursive_timed_mutex()
{
timed_test(&do_test_recursive_timed_mutex, 3);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{ {
boost::unit_test_framework::test_suite* test = BOOST_TEST_SUITE("Boost.Threads: mutex test suite"); boost::unit_test_framework::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: mutex test suite");
test->add(BOOST_TEST_CASE(&test_mutex)); test->add(BOOST_TEST_CASE(&test_mutex));
test->add(BOOST_TEST_CASE(&test_try_mutex)); test->add(BOOST_TEST_CASE(&test_try_mutex));

View File

@@ -1,25 +1,35 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/once.hpp> #include <boost/thread/once.hpp>
#include <boost/thread/thread.hpp> #include <boost/thread/thread.hpp>
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
namespace #include "util.inl"
int once_value = 0;
boost::once_flag once = BOOST_ONCE_INIT;
void init_once_value()
{ {
int once_value = 0; once_value++;
boost::once_flag once = BOOST_ONCE_INIT;
void init_once_value()
{
once_value++;
}
void test_once_thread()
{
boost::call_once(init_once_value, once);
}
} }
void test_once() void test_once_thread()
{
boost::call_once(init_once_value, once);
}
void do_test_once()
{ {
const int NUMTHREADS=5; const int NUMTHREADS=5;
boost::thread_group threads; boost::thread_group threads;
@@ -29,9 +39,15 @@ void test_once()
BOOST_CHECK_EQUAL(once_value, 1); BOOST_CHECK_EQUAL(once_value, 1);
} }
void test_once()
{
timed_test(&do_test_once, 2);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{ {
boost::unit_test_framework::test_suite* test = BOOST_TEST_SUITE("Boost.Threads: once test suite"); boost::unit_test_framework::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: once test suite");
test->add(BOOST_TEST_CASE(test_once)); test->add(BOOST_TEST_CASE(test_once));

View File

@@ -1,68 +1,47 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/thread.hpp> #include <boost/thread/thread.hpp>
#include <boost/thread/xtime.hpp> #include <boost/thread/xtime.hpp>
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
namespace #define DEFAULT_EXECUTION_MONITOR_TYPE execution_monitor::use_sleep_only
#include "util.inl"
int test_value;
void simple_thread()
{ {
inline bool xtime_in_range(boost::xtime& xt, int less_seconds, int greater_seconds) test_value = 999;
{ }
boost::xtime cur;
BOOST_CHECK_EQUAL(boost::xtime_get(&cur, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
boost::xtime less = cur; void comparison_thread(boost::thread* parent)
less.sec += less_seconds; {
boost::thread thrd;
boost::xtime greater = cur; BOOST_TEST(thrd != *parent);
greater.sec += greater_seconds; BOOST_TEST(thrd == boost::thread());
return (boost::xtime_cmp(xt, less) >= 0) && (boost::xtime_cmp(xt, greater) <= 0);
}
int test_value;
void simple_thread()
{
test_value = 999;
}
struct thread_adapter
{
thread_adapter(void (*func)(boost::thread& parent), boost::thread& parent)
: func(func), parent(parent)
{
}
void operator()()
{
(*func)(parent);
}
void (*func)(boost::thread& parent);
boost::thread& parent;
};
void comparison_thread(boost::thread& parent)
{
boost::thread thrd;
BOOST_TEST(thrd != parent);
BOOST_TEST(thrd == boost::thread());
}
} }
void test_sleep() void test_sleep()
{ {
boost::xtime xt; boost::xtime xt = delay(3);
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
xt.sec += 3;
boost::thread::sleep(xt); boost::thread::sleep(xt);
// Insure it's in a range instead of checking actual equality due to time lapse // Ensure it's in a range instead of checking actual equality due to time
BOOST_CHECK(xtime_in_range(xt, -1, 0)); // lapse
BOOST_CHECK(in_range(xt));
} }
void test_creation() void do_test_creation()
{ {
test_value = 0; test_value = 0;
boost::thread thrd(&simple_thread); boost::thread thrd(&simple_thread);
@@ -70,16 +49,27 @@ void test_creation()
BOOST_CHECK_EQUAL(test_value, 999); BOOST_CHECK_EQUAL(test_value, 999);
} }
void test_comparison() void test_creation()
{
timed_test(&do_test_creation, 1);
}
void do_test_comparison()
{ {
boost::thread self; boost::thread self;
boost::thread thrd(thread_adapter(comparison_thread, self)); boost::thread thrd(bind(&comparison_thread, &self));
thrd.join(); thrd.join();
} }
void test_comparison()
{
timed_test(&do_test_comparison, 1);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{ {
boost::unit_test_framework::test_suite* test = BOOST_TEST_SUITE("Boost.Threads: thread test suite"); boost::unit_test_framework::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: thread test suite");
test->add(BOOST_TEST_CASE(test_sleep)); test->add(BOOST_TEST_CASE(test_sleep));
test->add(BOOST_TEST_CASE(test_creation)); test->add(BOOST_TEST_CASE(test_creation));

View File

@@ -1,45 +1,55 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/tss.hpp> #include <boost/thread/tss.hpp>
#include <boost/thread/mutex.hpp> #include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp> #include <boost/thread/thread.hpp>
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
namespace #include "util.inl"
boost::mutex tss_mutex;
int tss_instances = 0;
struct tss_value_t
{ {
boost::mutex tss_mutex; tss_value_t()
int tss_instances = 0;
struct tss_value_t
{ {
tss_value_t() boost::mutex::scoped_lock lock(tss_mutex);
{ ++tss_instances;
boost::mutex::scoped_lock lock(tss_mutex); value = 0;
++tss_instances; }
value = 0; ~tss_value_t()
}
~tss_value_t()
{
boost::mutex::scoped_lock lock(tss_mutex);
--tss_instances;
}
int value;
};
boost::thread_specific_ptr<tss_value_t> tss_value;
void test_tss_thread()
{ {
tss_value.reset(new tss_value_t()); boost::mutex::scoped_lock lock(tss_mutex);
for (int i=0; i<1000; ++i) --tss_instances;
{ }
int& n = tss_value->value; int value;
BOOST_CHECK_EQUAL(n, i); };
++n;
} boost::thread_specific_ptr<tss_value_t> tss_value;
void test_tss_thread()
{
tss_value.reset(new tss_value_t());
for (int i=0; i<1000; ++i)
{
int& n = tss_value->value;
BOOST_CHECK_EQUAL(n, i);
++n;
} }
} }
void test_tss() void do_test_tss()
{ {
const int NUMTHREADS=5; const int NUMTHREADS=5;
boost::thread_group threads; boost::thread_group threads;
@@ -49,9 +59,15 @@ void test_tss()
BOOST_CHECK_EQUAL(tss_instances, 0); BOOST_CHECK_EQUAL(tss_instances, 0);
} }
void test_tss()
{
timed_test(&do_test_tss, 2);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{ {
boost::unit_test_framework::test_suite* test = BOOST_TEST_SUITE("Boost.Threads: tss test suite"); boost::unit_test_framework::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: tss test suite");
test->add(BOOST_TEST_CASE(test_tss)); test->add(BOOST_TEST_CASE(test_tss));

View File

@@ -1,3 +1,14 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/xtime.hpp> #include <boost/thread/xtime.hpp>
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
@@ -5,7 +16,9 @@
void test_xtime_cmp() void test_xtime_cmp()
{ {
boost::xtime xt1, xt2, cur; boost::xtime xt1, xt2, cur;
BOOST_CHECK_EQUAL(boost::xtime_get(&cur, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC)); BOOST_CHECK_EQUAL(
boost::xtime_get(&cur, boost::TIME_UTC),
static_cast<int>(boost::TIME_UTC));
xt1 = xt2 = cur; xt1 = xt2 = cur;
xt1.nsec -= 1; xt1.nsec -= 1;
@@ -27,12 +40,16 @@ void test_xtime_cmp()
void test_xtime_get() void test_xtime_get()
{ {
boost::xtime orig, cur, old; boost::xtime orig, cur, old;
BOOST_CHECK_EQUAL(boost::xtime_get(&orig, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC)); BOOST_CHECK_EQUAL(
boost::xtime_get(&orig,
boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
old = orig; old = orig;
for (int x=0; x < 100; ++x) for (int x=0; x < 100; ++x)
{ {
BOOST_CHECK_EQUAL(boost::xtime_get(&cur, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC)); BOOST_CHECK_EQUAL(
boost::xtime_get(&cur, boost::TIME_UTC),
static_cast<int>(boost::TIME_UTC));
BOOST_CHECK(boost::xtime_cmp(cur, orig) >= 0); BOOST_CHECK(boost::xtime_cmp(cur, orig) >= 0);
BOOST_CHECK(boost::xtime_cmp(cur, old) >= 0); BOOST_CHECK(boost::xtime_cmp(cur, old) >= 0);
old = cur; old = cur;
@@ -41,7 +58,8 @@ void test_xtime_get()
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{ {
boost::unit_test_framework::test_suite* test = BOOST_TEST_SUITE("Boost.Threads: xtime test suite"); boost::unit_test_framework::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: xtime test suite");
test->add(BOOST_TEST_CASE(&test_xtime_cmp)); test->add(BOOST_TEST_CASE(&test_xtime_cmp));
test->add(BOOST_TEST_CASE(&test_xtime_get)); test->add(BOOST_TEST_CASE(&test_xtime_get));

162
test/util.inl Normal file
View File

@@ -0,0 +1,162 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#if !defined(UTIL_INL_WEK01242003)
#define UTIL_INL_WEK01242003
#include <boost/thread/xtime.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/thread.hpp>
#ifndef DEFAULT_EXECUTION_MONITOR_TYPE
# define DEFAULT_EXECUTION_MONITOR_TYPE execution_monitor::use_condition
#endif
namespace
{
inline boost::xtime delay(int secs, int msecs=0, int nsecs=0)
{
const int MILLISECONDS_PER_SECOND = 1000;
const int NANOSECONDS_PER_SECOND = 1000000000;
const int NANOSECONDS_PER_MILLISECOND = 1000000;
boost::xtime xt;
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC),
static_cast<int>(boost::TIME_UTC));
nsecs += xt.nsec;
msecs += nsecs / NANOSECONDS_PER_MILLISECOND;
secs += msecs / MILLISECONDS_PER_SECOND;
nsecs += (msecs % MILLISECONDS_PER_SECOND) * NANOSECONDS_PER_MILLISECOND;
xt.nsec = nsecs % NANOSECONDS_PER_SECOND;
xt.sec += secs + (nsecs / NANOSECONDS_PER_SECOND);
return xt;
}
inline bool in_range(const boost::xtime& xt, int secs=1)
{
boost::xtime min = delay(-secs);
boost::xtime max = delay(0);
return (boost::xtime_cmp(xt, min) >= 0) &&
(boost::xtime_cmp(xt, max) <= 0);
}
class execution_monitor
{
public:
enum wait_type { use_sleep_only, use_mutex, use_condition };
execution_monitor(wait_type type, int secs)
: done(false), type(type), secs(secs) { }
void start()
{
if (type != use_sleep_only) {
boost::mutex::scoped_lock lock(mutex); done = false;
} else {
done = false;
}
}
void finish()
{
if (type != use_sleep_only) {
boost::mutex::scoped_lock lock(mutex);
done = true;
if (type == use_condition)
cond.notify_one();
} else {
done = true;
}
}
bool wait()
{
boost::xtime xt = delay(secs);
if (type != use_condition)
boost::thread::sleep(xt);
if (type != use_sleep_only) {
boost::mutex::scoped_lock lock(mutex);
while (type == use_condition && !done) {
if (!cond.timed_wait(lock, xt))
break;
}
return done;
}
return done;
}
private:
boost::mutex mutex;
boost::condition cond;
bool done;
wait_type type;
int secs;
};
template <typename F>
class indirect_adapter
{
public:
indirect_adapter(F func, execution_monitor& monitor)
: func(func), monitor(monitor) { }
void operator()() const
{
try
{
boost::thread thrd(func);
thrd.join();
}
catch (...)
{
monitor.finish();
throw;
}
monitor.finish();
}
private:
F func;
execution_monitor& monitor;
};
template <typename F>
void timed_test(F func, int secs,
execution_monitor::wait_type type=DEFAULT_EXECUTION_MONITOR_TYPE)
{
execution_monitor monitor(type, secs);
indirect_adapter<F> ifunc(func, monitor);
monitor.start();
boost::thread thrd(ifunc);
BOOST_REQUIRE_MESSAGE(monitor.wait(),
"Timed test didn't complete in time, possible deadlock.");
}
template <typename F, typename T>
class binder
{
public:
binder(const F& func, const T& param)
: func(func), param(param) { }
void operator()() const { func(param); }
private:
F func;
T param;
};
template <typename F, typename T>
binder<F, T> bind(const F& func, const T& param)
{
return binder<F, T>(func, param);
}
} // namespace
#endif

View File

@@ -1,8 +1,19 @@
# (C) Copyright William E. Kempf 2001. Permission to copy, use, modify, sell and # (C) Copyright William E. Kempf 2001. Permission to copy, use, modify, sell
# distribute this software is granted provided this copyright notice appears # and distribute this software is granted provided this copyright notice
# in all copies. This software is provided "as is" without express or implied # appears in all copies. This software is provided "as is" without express or
# warranty, and with no claim as to its suitability for any purpose. # implied warranty, and with no claim as to its suitability for any purpose.
# #
# Boost.Threads example Jamfile
#
# Additional configuration variables used:
# 1. PTW32 may be used on Win32 platforms to specify that the pthreads-win32
# library should be used instead of "native" threads. This feature is
# mostly used for testing and it's generally recommended you use the
# native threading libraries instead. PTW32 should be set to be a list
# of two strings, the first specifying the installation path of the
# pthreads-win32 library and the second specifying which library
# variant to link against (see the pthreads-win32 documentation).
# Example: jam -sPTW32="c:\pthreads-win32 pthreadVCE.lib"
# Declare the location of this subproject relative to the root. # Declare the location of this subproject relative to the root.
@@ -14,22 +25,25 @@ subproject libs/thread/tutorial ;
SEARCH on <module@>threads.jam = $(BOOST_ROOT)/libs/thread/build ; SEARCH on <module@>threads.jam = $(BOOST_ROOT)/libs/thread/build ;
include <module@>threads.jam ; include <module@>threads.jam ;
template tutorial {
## sources ## template tutorial
: <template>thread_base <lib>../build/boost_thread <lib>../../test/build/unit_test_framework $(threadmon) ## sources ##
## requirements ## : <template>thread_base
: <dll>../build/boost_thread
## default build ## ## requirements ##
: release <runtime-link>static :
; ## default build ##
:
;
exe helloworld : <template>tutorial helloworld.cpp ; exe helloworld : <template>tutorial helloworld.cpp ;
exe helloworld2 : <template>tutorial helloworld2.cpp ; exe helloworld2 : <template>tutorial helloworld2.cpp ;
exe helloworld3 : <template>tutorial helloworld3.cpp ; exe helloworld3 : <template>tutorial helloworld3.cpp ;
exe helloworld4 : <template>tutorial helloworld4.cpp ; exe helloworld4 : <template>tutorial helloworld4.cpp ;
exe factorial : <template>tutorial factorial.cpp ; exe factorial : <template>tutorial factorial.cpp ;
exe factorial2 : <template>tutorial factorial2.cpp ; exe factorial2 : <template>tutorial factorial2.cpp ;
exe factorial3 : <template>tutorial factorial3.cpp ; exe factorial3 : <template>tutorial factorial3.cpp ;
exe counter : <template>tutorial counter.cpp ; exe counter : <template>tutorial counter.cpp ;
exe bounded_buffer : <template>tutorial bounded_buffer.cpp ; exe bounded_buffer : <template>tutorial bounded_buffer.cpp ;
exe once : <template>tutorial once.cpp ; exe once : <template>tutorial once.cpp ;
}

View File

@@ -0,0 +1,74 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/condition.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include <iostream>
#include <vector>
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()
{
boost::thread thrd1(&sender);
boost::thread thrd2(&receiver);
thrd1.join();
thrd2.join();
}

33
tutorial/counter.cpp Normal file
View File

@@ -0,0 +1,33 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include <iostream>
boost::mutex mutex;
int counter=0;
void change_count()
{
boost::mutex::scoped_lock lock(mutex);
int i = ++counter;
std::cout << "count == " << i << std::endl;
}
int main()
{
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();
}

View File

@@ -1,3 +1,14 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/thread.hpp> #include <boost/thread/thread.hpp>
#include <iostream> #include <iostream>
@@ -23,4 +34,4 @@ int main()
boost::thread thrd(f); boost::thread thrd(f);
thrd.join(); thrd.join();
std::cout << "10! = " << result << std::endl; std::cout << "10! = " << result << std::endl;
} }

View File

@@ -1,3 +1,14 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/thread.hpp> #include <boost/thread/thread.hpp>
#include <boost/ref.hpp> #include <boost/ref.hpp>
#include <iostream> #include <iostream>
@@ -23,4 +34,4 @@ int main()
boost::thread thrd(boost::ref(f)); boost::thread thrd(boost::ref(f));
thrd.join(); thrd.join();
std::cout << "10! = " << f.result() << std::endl; std::cout << "10! = " << f.result() << std::endl;
} }

41
tutorial/factorial3.cpp Normal file
View File

@@ -0,0 +1,41 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/thread.hpp>
#include <iostream>
const int NUM_CALCS=5;
class factorial
{
public:
factorial(int x, int& res) : x(x), res(res) { }
void operator()() { res = calculate(x); }
int result() const { return res; }
private:
int calculate(int x) { return x <= 1 ? 1 : x * calculate(x-1); }
private:
int x;
int& res;
};
int main()
{
int results[NUM_CALCS];
boost::thread_group thrds;
for (int i=0; i < NUM_CALCS; ++i)
thrds.create_thread(factorial(i*10, results[i]));
thrds.join_all();
for (int j=0; j < NUM_CALCS; ++j)
std::cout << j*10 << "! = " << results[j] << std::endl;
}

View File

@@ -1,3 +1,14 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/thread.hpp> #include <boost/thread/thread.hpp>
#include <iostream> #include <iostream>
@@ -10,4 +21,4 @@ int main()
{ {
boost::thread thrd(&helloworld); boost::thread thrd(&helloworld);
thrd.join(); thrd.join();
} }

View File

@@ -1,3 +1,14 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/thread.hpp> #include <boost/thread/thread.hpp>
#include <iostream> #include <iostream>
@@ -11,4 +22,4 @@ int main()
{ {
boost::thread thrd(helloworld()); boost::thread thrd(helloworld());
thrd.join(); thrd.join();
} }

View File

@@ -1,3 +1,14 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/thread.hpp> #include <boost/thread/thread.hpp>
#include <iostream> #include <iostream>
@@ -12,4 +23,4 @@ int main()
{ {
boost::thread thrd(helloworld("Bob")); boost::thread thrd(helloworld("Bob"));
thrd.join(); thrd.join();
} }

25
tutorial/helloworld4.cpp Normal file
View File

@@ -0,0 +1,25 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/thread.hpp>
#include <boost/bind.hpp>
#include <iostream>
void helloworld(const char* who)
{
std::cout << who << "says, \"Hello World.\"" << std::endl;
}
int main()
{
boost::thread thrd(boost::bind(&helloworld, "Bob"));
thrd.join();
}

36
tutorial/once.cpp Normal file
View File

@@ -0,0 +1,36 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#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);
}

41
tutorial/tss.cpp Normal file
View File

@@ -0,0 +1,41 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#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();
}