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

Compare commits

..

4 Commits

Author SHA1 Message Date
nobody
60326d5b37 This commit was manufactured by cvs2svn to create tag
'Version_1_29_0'.

[SVN r15904]
2002-10-11 15:17:55 +00:00
Björn Karlsson
9169abc03f Added missing typenames
[SVN r15612]
2002-10-01 14:59:08 +00:00
Björn Karlsson
13233e3146 Fix for BOOST_TEST_EQUAL with unnamed enum (TIME_UTC)
[SVN r15523]
2002-09-26 09:13:54 +00:00
nobody
813620fa7c This commit was manufactured by cvs2svn to create branch 'RC_1_29_0'.
[SVN r15460]
2002-09-19 20:49:39 +00:00
44 changed files with 604 additions and 958 deletions

View File

@@ -1,11 +1,17 @@
# (C) Copyright William E. Kempf 2001. Permission to copy, use, modify,
# sell and distribute this software is granted provided this copyright
# notice appears in all copies. This software is provided "as is" without
# express or implied warranty, and with no claim as to its suitability for
# any purpose.
# (C) Copyright William E. Kempf 2001. Permission to copy, use, modify, sell and
# distribute this software is granted provided this copyright notice appears
# in all copies. This software is provided "as is" without express or implied
# warranty, and with no claim as to its suitability for any purpose.
#
# 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:
# 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
@@ -25,29 +31,37 @@ subproject libs/thread/build ;
SEARCH on <module@>threads.jam = $(SUBDIR) ;
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)
{
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
;
dll boost_threadmon : <template>thread_libs ../src/threadmon.cpp ;
}
#######################
# 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,12 +0,0 @@
# Declare the uses system library
lib pthread : : <name>pthread ;
project boost/thread
: source-location ../src
: usage-requirements <library>pthread
;
CPP_SOURCES = condition mutex recursive_mutex thread tss xtime once exceptions ;
lib boost_thread : $(CPP_SOURCES).cpp ;

View File

@@ -1,28 +1,32 @@
# Do some OS-specific setup
threadmon = ;
pthreads-win32 = ;
if $(NT)
{
pthreads-win32 = ;
if $(NT)
if $(PTW32)
{
if $(PTW32)
{
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)
;
}
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
## sources ##
:
## requirements ##
: <sysinclude>$(BOOST_ROOT) <threading>multi $(pthreads-win32)
## default build ##
:
;
}
template thread_base
## sources ##
:
## requirements ##
: <sysinclude>$(BOOST_ROOT) <threading>multi $(pthreads-win32)
## default build ##
:
;

View File

@@ -61,9 +61,10 @@
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>
<h4><a name="class-condition-synopsis"></a>Class <code>condition</code> synopsis</h4>
<pre>namespace boost
<pre>
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.
{
public:
@@ -85,19 +86,22 @@
</pre>
<h4><a name="class-condition-ctors"></a>Class <code>condition</code> constructors
and destructor</h4>
<pre>condition();
<pre>
condition();
</pre>
<dl class="function-semantics">
<dt><b>Effects:</b> Constructs a <code>condition</code> object.</dt>
</dl>
<pre>~condition();
<pre>
~condition();
</pre>
<dl class="function-semantics">
<dt><b>Effects:</b> Destroys <code>*this</code>.</dt>
</dl>
<h4><a name="class-condition-modifiers"></a>Class <code>condition</code> modifier
functions</h4>
<pre>void notify_one();
<pre>
void notify_one();
</pre>
<dl class="function-semantics">
<dt><b>Effects:</b> If there is a thread waiting on <code>*this</code>, change
@@ -107,14 +111,16 @@
thread must still acquire the mutex again (which occurs within the call to
one of the <code>condition</code> object's wait functions).</dt>
</dl>
<pre>void notify_all();
<pre>
void notify_all();
</pre>
<dl class="function-semantics">
<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
no effect.</dt>
</dl>
<pre>template &lt;typename ScopedLock&gt;
<pre>
template &lt;typename ScopedLock&gt;
void wait(ScopedLock&amp; lock);
</pre>
<dl class="function-semantics">
@@ -132,7 +138,8 @@
wake ups&quot;. The second version encapsulates this loop idiom internally
and is generally the preferred method.</dt>
</dl>
<pre>Template&lt;typename ScopedLock, typename Pr&gt;
<pre>
Template&lt;typename ScopedLock, typename Pr&gt;
void wait(ScopedLock&amp; lock, Pr pred);
</pre>
<dl class="function-semantics">
@@ -142,7 +149,8 @@
<dt><b>Throws:</b> <code><a href="exceptions.html#class-lock_error">lock_error</a></code>
if <code>!lock.locked()</code></dt>
</dl>
<pre>template &lt;typename ScopedLock&gt;
<pre>
template &lt;typename ScopedLock&gt;
bool timed_wait(ScopedLock&amp; lock, const <a href="xtime.html">xtime</a>&amp; XT);
</pre>
<dl class="function-semantics">
@@ -163,14 +171,16 @@
ups&quot;. The second version encapsulates this loop idiom internally and
is generally the preferred method.</dt>
</dl>
<pre>Template&lt;typename ScopedLock, typename Pr&gt;
<pre>
Template&lt;typename ScopedLock, typename Pr&gt;
bool timed_wait(ScopedLock&amp; lock, const <a href="xtime.html">xtime</a>&amp; XT, Pr pred);
</pre>
<dl class="function-semantics">
<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>
<dt><b>Effects:</b> As if:<br>
<pre>while (!pred())
<pre>
while (!pred())
{
if (!timed_wait(lock, XT))
return false;
@@ -186,7 +196,8 @@ return true;
<h2><a name="examples"></a>Example(s)</h2>
<p><a href="../example/condition.cpp">libs/thread/example/condition.cpp</a></p>
<p>Typical output (dependent on scheduling policies) is:</p>
<pre>sent: 0
<pre>
sent: 0
sent: 1
received: 0
received: 1
@@ -198,7 +209,9 @@ sent: 4
received: 4
</pre>
<p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->09 January, 2003<!--webbot bot="Timestamp" endspan i-checksum="38582" -->
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
05 November, 2001
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p>
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
All Rights Reserved.</i></p>
@@ -209,4 +222,4 @@ received: 4
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>
</body>
</html>
</html>

View File

@@ -241,17 +241,18 @@
there is no matching exception handler in a program [15.3/9]. That is, terminate()
is called, and it is implementation defined whether or not the stack is unwound.</p>
<h2><a name="acknowledgements"></a>Acknowledgments</h2>
<p>This document was originally written by Beman Dawes, and then much improved by the incorporation of comments from
William Kempf, who now maintains the contents.</p>
<p>This document has been much improved by the incorporation of comments from
William Kempf.</p>
<p>The visibility rules are based on <a href=
"bibliography.html#Butenhof-97">[Butenhof 97]</a>.</p>
<hr>
<p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->06 October, 2002<!--webbot bot="Timestamp" endspan i-checksum="38429" -->
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
05 November, 2001
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p>
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
All Rights Reserved.<br>
</i>© Copyright Beman Dawes, 2001</p>
All Rights Reserved.</i></p>
<p>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
@@ -259,4 +260,4 @@
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>
</body>
</html>
</html>

View File

@@ -86,7 +86,8 @@
"definitions.html#Thread-safe">thread-safe</a>. The following is a simple
example of a class with copyable semantics and internal synchronization through
a mutex member.</p>
<pre>class counter
<pre>
class counter
{
public:
// Doesn't need synchronization since there can be no references to *this
@@ -144,8 +145,8 @@ private:
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>
rather than <a href="rationale.html#Events">event variables</a>?</h2>
<p>Condition variables result in user code much less prone to
<a href="definitions.html#definition-race-condition">race conditions</a> than event variables.
<p>Condition variables result in user code much less prone to <a href=
"definitions.html#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
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
@@ -166,7 +167,9 @@ private:
greater safety by the combination of a mutex and a condition variable.</p>
<hr>
<p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->09 January, 2003<!--webbot bot="Timestamp" endspan i-checksum="38582" -->
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
05 November, 2001
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p>
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
All Rights Reserved.</i></p>
@@ -177,4 +180,4 @@ private:
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>
</body>
</html>
</html>

View File

@@ -145,7 +145,7 @@
<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>
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
must be well-formed and have the indicated effects.</p>
<table summary="Mutex expressions" border="1" cellpadding="5">
@@ -223,7 +223,9 @@
</table>
<hr>
<p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->09 January, 2003<!--webbot bot="Timestamp" endspan i-checksum="38582" -->
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
05 November, 2001
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p>
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
All Rights Reserved.</i></p>
@@ -234,4 +236,4 @@
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>
</body>
</html>
</html>

View File

@@ -110,8 +110,7 @@
<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
of all runtime libraries used by the program, including the runtime library
for the C++ Standard Library. Otherwise
<a href="definitions.html#definition-race-condition">race
for the C++ Standard Library. Otherwise <a href="definitions.html#Race condition">race
conditions</a> will occur when multiple threads simultaneously execute runtime
library functions for <i>new</i>, <i>delete</i>, or other language features
which imply shared state.</p>
@@ -158,7 +157,9 @@
as implementations are free to meet the NonCopyable requirement in other ways.</p>
<hr>
<p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->09 January, 2003<!--webbot bot="Timestamp" endspan i-checksum="38582" -->
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
05 November, 2001
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p>
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
All Rights Reserved.</i></p>
@@ -169,4 +170,4 @@
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>
</body>
</html>
</html>

View File

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

View File

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

View File

@@ -14,13 +14,11 @@ include <module@>threads.jam ;
template example
## sources ##
: <template>thread_base
<dll>../build/boost_thread
$(threadmon)
: <template>thread_base <lib>../build/boost_thread <lib>../../test/build/unit_test_framework $(threadmon)
## requirements ##
:
## default build ##
: release <runtime-link>dynamic
: release <runtime-link>static
;
exe monitor : <template>example monitor.cpp ;

View File

@@ -1,5 +0,0 @@
exe starvephil
: starvephil.cpp ../build/boost_thread ../../test/build/unit_test_framework
;

View File

@@ -20,7 +20,6 @@
#include <boost/thread/exceptions.hpp>
#include <boost/utility.hpp>
#include <boost/thread/detail/lock.hpp>
#include <boost/thread/detail/config.hpp>
#if defined(BOOST_HAS_PTHREADS)
# include <pthread.h>
@@ -32,60 +31,14 @@ namespace boost {
struct xtime;
namespace detail {
class BOOST_THREAD_DECL condition_impl : private noncopyable
{
friend class condition;
public:
condition_impl();
~condition_impl();
void notify_one();
void notify_all();
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
void enter_wait();
void do_wait();
bool do_timed_wait(const xtime& xt);
#elif defined(BOOST_HAS_PTHREADS)
void do_wait(pthread_mutex_t* pmutex);
bool do_timed_wait(const xtime& xt, pthread_mutex_t* pmutex);
#endif
#if defined(BOOST_HAS_WINTHREADS)
void* m_gate;
void* m_queue;
void* m_mutex;
unsigned m_gone; // # threads that timed out and never made it to m_queue
unsigned long m_blocked; // # threads blocked on the condition
unsigned m_waiting; // # threads no longer waiting for the condition but
// still waiting to be removed from m_queue
#elif defined(BOOST_HAS_PTHREADS)
pthread_cond_t m_condition;
#elif defined(BOOST_HAS_MPTASKS)
MPSemaphoreID m_gate;
MPSemaphoreID m_queue;
threads::mac::detail::scoped_critical_region m_mutex;
threads::mac::detail::scoped_critical_region m_mutex_mutex;
unsigned m_gone; // # threads that timed out and never made it to m_queue
unsigned long m_blocked; // # threads blocked on the condition
unsigned m_waiting; // # threads no longer waiting for the condition but
// still waiting to be removed from m_queue
#endif
};
} // namespace detail
class condition : private noncopyable
{
public:
condition() { }
~condition() { }
condition();
~condition();
void notify_one() { m_impl.notify_one(); }
void notify_all() { m_impl.notify_all(); }
void notify_one();
void notify_all();
template <typename L>
void wait(L& lock)
@@ -131,63 +84,79 @@ public:
}
private:
detail::condition_impl m_impl;
template <typename M>
void do_wait(M& mutex)
{
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
m_impl.enter_wait();
enter_wait();
#endif
typedef detail::thread::lock_ops<M>
#if defined(__HP_aCC) && __HP_aCC <= 33900 && !defined(BOOST_STRICT_CONFIG)
# define lock_ops lock_ops_ // HP confuses lock_ops witht the template
#endif
lock_ops;
typedef detail::thread::lock_ops<M> lock_ops;
typename lock_ops::lock_state state;
lock_ops::unlock(mutex, state);
#if defined(BOOST_HAS_PTHREADS)
m_impl.do_wait(state.pmutex);
do_wait(state.pmutex);
#elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
m_impl.do_wait();
do_wait();
#endif
lock_ops::lock(mutex, state);
#undef lock_ops
}
template <typename M>
bool do_timed_wait(M& mutex, const xtime& xt)
{
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
m_impl.enter_wait();
enter_wait();
#endif
typedef detail::thread::lock_ops<M>
#if defined(__HP_aCC) && __HP_aCC <= 33900 && !defined(BOOST_STRICT_CONFIG)
# define lock_ops lock_ops_ // HP confuses lock_ops witht the template
#endif
lock_ops;
typedef detail::thread::lock_ops<M> lock_ops;
typename lock_ops::lock_state state;
lock_ops::unlock(mutex, state);
bool ret = false;
#if defined(BOOST_HAS_PTHREADS)
ret = m_impl.do_timed_wait(xt, state.pmutex);
ret = do_timed_wait(xt, state.pmutex);
#elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
ret = m_impl.do_timed_wait(xt);
ret = do_timed_wait(xt);
#endif
lock_ops::lock(mutex, state);
#undef lock_ops
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
@@ -195,8 +164,7 @@ private:
// Change Log:
// 8 Feb 01 WEKEMPF Initial version.
// 22 May 01 WEKEMPF Modified to use xtime for time outs.
// 23 May 01 WEKEMPF Removed "duration" timed_waits, as they are too
// difficult to use with spurious wakeups.
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
// 23 May 01 WEKEMPF Removed "duration" timed_waits, as they are too difficult
// to use with spurious wakeups.
#endif // BOOST_CONDITION_WEK070601_HPP

View File

@@ -1,14 +0,0 @@
#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

@@ -1,14 +0,0 @@
#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

@@ -12,9 +12,6 @@
#ifndef 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
// with recursive headers if I don't separate it
// wek: Not sure why recursive headers would cause compilation problems
@@ -25,13 +22,13 @@
namespace boost {
class BOOST_THREAD_DECL lock_error : public std::logic_error
class lock_error : public std::logic_error
{
public:
lock_error();
};
class BOOST_THREAD_DECL thread_resource_error : public std::runtime_error
class thread_resource_error : public std::runtime_error
{
public:
thread_resource_error();
@@ -39,7 +36,4 @@ public:
} // namespace boost
// Change log:
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
#endif // BOOST_THREAD_CONFIG_PDM070801_H

View File

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

View File

@@ -17,8 +17,6 @@
# error Thread support is unavailable!
#endif
#include <boost/thread/detail/config.hpp>
#if defined(BOOST_HAS_PTHREADS)
# include <pthread.h>
#endif
@@ -37,7 +35,7 @@ typedef long once_flag;
#endif
void BOOST_THREAD_DECL call_once(void (*func)(), once_flag& flag);
void call_once(void (*func)(), once_flag& flag);
} // namespace boost

View File

@@ -19,7 +19,6 @@
#include <boost/utility.hpp>
#include <boost/thread/detail/lock.hpp>
#include <boost/thread/detail/config.hpp>
#if defined(BOOST_HAS_PTHREADS)
# include <pthread.h>
@@ -31,7 +30,7 @@ namespace boost {
struct xtime;
class BOOST_THREAD_DECL recursive_mutex : private noncopyable
class recursive_mutex : private noncopyable
{
public:
friend class detail::thread::lock_ops<recursive_mutex>;
@@ -74,7 +73,7 @@ private:
#endif
};
class BOOST_THREAD_DECL recursive_try_mutex : private noncopyable
class recursive_try_mutex : private noncopyable
{
public:
friend class detail::thread::lock_ops<recursive_try_mutex>;
@@ -119,7 +118,7 @@ private:
#endif
};
class BOOST_THREAD_DECL recursive_timed_mutex : private noncopyable
class recursive_timed_mutex : private noncopyable
{
public:
friend class detail::thread::lock_ops<recursive_timed_mutex>;
@@ -171,7 +170,5 @@ private:
// 1 Jun 01 WEKEMPF Modified to use xtime for time outs. Factored out
// to three classes, mutex, try_mutex and timed_mutex.
// 11 Jun 01 WEKEMPF Modified to use PTHREAD_MUTEX_RECURSIVE if available.
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
#endif // BOOST_RECURSIVE_MUTEX_WEK070601_HPP

View File

@@ -20,7 +20,6 @@
#include <boost/utility.hpp>
#include <boost/function.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/detail/config.hpp>
#include <list>
#include <memory>
@@ -35,7 +34,7 @@ namespace boost {
struct xtime;
class BOOST_THREAD_DECL thread : private noncopyable
class thread : private noncopyable
{
public:
thread();
@@ -64,7 +63,7 @@ private:
bool m_joinable;
};
class BOOST_THREAD_DECL thread_group : private noncopyable
class thread_group : private noncopyable
{
public:
thread_group();

View File

@@ -18,7 +18,6 @@
#endif
#include <boost/utility.hpp>
#include <boost/thread/detail/config.hpp>
#if defined(BOOST_HAS_PTHREADS)
# include <pthread.h>
@@ -29,7 +28,7 @@
namespace boost {
namespace detail {
class BOOST_THREAD_DECL tss : private noncopyable
class tss : private noncopyable
{
public:
tss(void (*cleanup)(void*)=0);

View File

@@ -12,9 +12,8 @@
#ifndef BOOST_XTIME_WEK070601_HPP
#define BOOST_XTIME_WEK070601_HPP
#include <boost/config.hpp>
#include <boost/cstdint.hpp>
#include <boost/thread/detail/config.hpp>
#include <boost/config.hpp>
namespace boost {
@@ -40,7 +39,7 @@ struct xtime
int_fast32_t nsec;
};
int BOOST_THREAD_DECL xtime_get(struct xtime* xtp, int clock_type);
int xtime_get(struct xtime* xtp, int clock_type);
inline int xtime_cmp(const xtime& xt1, const xtime& xt2)
{
int res = (int)(xt1.sec - xt2.sec);

View File

@@ -32,15 +32,12 @@
namespace boost {
namespace detail {
#if defined(BOOST_HAS_WINTHREADS)
condition_impl::condition_impl()
condition::condition()
: m_gone(0), m_blocked(0), m_waiting(0)
{
m_gate = reinterpret_cast<void*>(CreateSemaphore(0, 1, 1, 0));
m_queue = reinterpret_cast<void*>(CreateSemaphore(0, 0,
std::numeric_limits<long>::max(), 0));
m_queue = reinterpret_cast<void*>(CreateSemaphore(0, 0, std::numeric_limits<long>::max(), 0));
m_mutex = reinterpret_cast<void*>(CreateMutex(0, 0, 0));
if (!m_gate || !m_queue || !m_mutex)
@@ -66,7 +63,7 @@ condition_impl::condition_impl()
}
}
condition_impl::~condition_impl()
condition::~condition()
{
int res = 0;
res = CloseHandle(reinterpret_cast<HANDLE>(m_gate));
@@ -77,7 +74,7 @@ condition_impl::~condition_impl()
assert(res);
}
void condition_impl::notify_one()
void condition::notify_one()
{
unsigned signals = 0;
@@ -129,7 +126,7 @@ void condition_impl::notify_one()
}
}
void condition_impl::notify_all()
void condition::notify_all()
{
unsigned signals = 0;
@@ -180,7 +177,7 @@ void condition_impl::notify_all()
}
}
void condition_impl::enter_wait()
void condition::enter_wait()
{
int res = 0;
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
@@ -190,7 +187,7 @@ void condition_impl::enter_wait()
assert(res);
}
void condition_impl::do_wait()
void condition::do_wait()
{
int res = 0;
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue), INFINITE);
@@ -209,8 +206,7 @@ void condition_impl::do_wait()
{
if (m_blocked != 0)
{
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1,
0); // open m_gate
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0); // open m_gate
assert(res);
was_waiting = 0;
}
@@ -238,8 +234,7 @@ void condition_impl::do_wait()
for (/**/ ; was_gone; --was_gone)
{
// better now than spurious later
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue),
INFINITE);
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue), INFINITE);
assert(res == WAIT_OBJECT_0);
}
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
@@ -247,7 +242,7 @@ void condition_impl::do_wait()
}
}
bool condition_impl::do_timed_wait(const xtime& xt)
bool condition::do_timed_wait(const xtime& xt)
{
bool ret = false;
unsigned int res = 0;
@@ -257,8 +252,7 @@ bool condition_impl::do_timed_wait(const xtime& xt)
int milliseconds;
to_duration(xt, milliseconds);
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue),
milliseconds);
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue), milliseconds);
assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
ret = (res == WAIT_OBJECT_0);
@@ -293,8 +287,7 @@ bool condition_impl::do_timed_wait(const xtime& xt)
{
if (m_blocked != 0)
{
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1,
0); // open m_gate
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0); // open m_gate
assert(res);
was_waiting = 0;
}
@@ -322,8 +315,7 @@ bool condition_impl::do_timed_wait(const xtime& xt)
for (/**/ ; was_gone; --was_gone)
{
// better now than spurious later
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue),
INFINITE);
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue), INFINITE);
assert(res == WAIT_OBJECT_0);
}
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
@@ -333,7 +325,7 @@ bool condition_impl::do_timed_wait(const xtime& xt)
return ret;
}
#elif defined(BOOST_HAS_PTHREADS)
condition_impl::condition_impl()
condition::condition()
{
int res = 0;
res = pthread_cond_init(&m_condition, 0);
@@ -341,35 +333,35 @@ condition_impl::condition_impl()
throw thread_resource_error();
}
condition_impl::~condition_impl()
condition::~condition()
{
int res = 0;
res = pthread_cond_destroy(&m_condition);
assert(res == 0);
}
void condition_impl::notify_one()
void condition::notify_one()
{
int res = 0;
res = pthread_cond_signal(&m_condition);
assert(res == 0);
}
void condition_impl::notify_all()
void condition::notify_all()
{
int res = 0;
res = pthread_cond_broadcast(&m_condition);
assert(res == 0);
}
void condition_impl::do_wait(pthread_mutex_t* pmutex)
void condition::do_wait(pthread_mutex_t* pmutex)
{
int res = 0;
res = pthread_cond_wait(&m_condition, pmutex);
assert(res == 0);
}
bool condition_impl::do_timed_wait(const xtime& xt, pthread_mutex_t* pmutex)
bool condition::do_timed_wait(const xtime& xt, pthread_mutex_t* pmutex)
{
timespec ts;
to_timespec(xt, ts);
@@ -385,7 +377,7 @@ bool condition_impl::do_timed_wait(const xtime& xt, pthread_mutex_t* pmutex)
using threads::mac::detail::safe_enter_critical_region;
using threads::mac::detail::safe_wait_on_semaphore;
condition_impl::condition_impl()
condition::condition()
: m_gone(0), m_blocked(0), m_waiting(0)
{
threads::mac::detail::thread_init();
@@ -413,7 +405,7 @@ condition_impl::condition_impl()
}
}
condition_impl::~condition_impl()
condition::~condition()
{
OSStatus lStatus = noErr;
lStatus = MPDeleteSemaphore(m_gate);
@@ -422,7 +414,7 @@ condition_impl::~condition_impl()
assert(lStatus == noErr);
}
void condition_impl::notify_one()
void condition::notify_one()
{
unsigned signals = 0;
@@ -474,7 +466,7 @@ void condition_impl::notify_one()
}
}
void condition_impl::notify_all()
void condition::notify_all()
{
unsigned signals = 0;
@@ -526,7 +518,7 @@ void condition_impl::notify_all()
}
}
void condition_impl::enter_wait()
void condition::enter_wait()
{
OSStatus lStatus = noErr;
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
@@ -536,7 +528,7 @@ void condition_impl::enter_wait()
assert(lStatus == noErr);
}
void condition_impl::do_wait()
void condition::do_wait()
{
OSStatus lStatus = noErr;
lStatus = safe_wait_on_semaphore(m_queue, kDurationForever);
@@ -591,7 +583,7 @@ void condition_impl::do_wait()
}
}
bool condition_impl::do_timed_wait(const xtime& xt)
bool condition::do_timed_wait(const xtime& xt)
{
int milliseconds;
to_duration(xt, milliseconds);
@@ -661,11 +653,8 @@ bool condition_impl::do_timed_wait(const xtime& xt)
}
#endif
} // namespace detail
} // namespace boost
// Change Log:
// 8 Feb 01 WEKEMPF Initial version.
// 22 May 01 WEKEMPF Modified to use xtime for time outs.
// 3 Jan 03 WEKEMPF Modified for DLL implementation.

View File

@@ -122,7 +122,7 @@ void call_once(void (*func)(), once_flag& flag)
#else
std::ostringstream strm;
strm << "2AC1A572DB6944B0A65C38C4140AF2F4" << std::hex << GetCurrentProcessId() << &flag;
HANDLE mutex = CreateMutexA(NULL, FALSE, strm.str().c_str());
HANDLE mutex = CreateMutex(NULL, FALSE, strm.str().c_str());
#endif
assert(mutex != NULL);

View File

@@ -1,15 +1,12 @@
// threadmon.cpp : Defines the entry point for the DLL application.
//
#include <boost/config.hpp>
#define BOOST_THREADMON_EXPORTS
#include "threadmon.hpp"
#if defined(BOOST_HAS_WINTHREADS)
#ifdef BOOST_HAS_WINTHREADS
#if defined(BOOST_THREAD_BUILD_DLL)
#include <boost/thread/detail/threadmon.hpp>
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#include <windows.h>
#ifdef BOOST_MSVC
@@ -49,18 +46,13 @@ BOOL WINAPI DllMain(HANDLE module, DWORD reason, LPVOID)
case DLL_THREAD_DETACH:
{
// Call the thread's exit handlers.
exit_handlers* handlers =
static_cast<exit_handlers*>(TlsGetValue(key));
exit_handlers* handlers = static_cast<exit_handlers*>(TlsGetValue(key));
if (handlers)
{
for (exit_handlers::iterator it = handlers->begin();
it != handlers->end(); ++it)
{
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.
// Remove the exit handler list from the registered lists and then destroy it.
EnterCriticalSection(&cs);
registry.erase(handlers);
LeaveCriticalSection(&cs);
@@ -70,31 +62,22 @@ BOOL WINAPI DllMain(HANDLE module, DWORD reason, LPVOID)
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
// 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));
exit_handlers* handlers = static_cast<exit_handlers*>(TlsGetValue(key));
if (handlers)
{
for (exit_handlers::iterator it = handlers->begin();
it != handlers->end(); ++it)
{
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
// 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)
{
for (registered_handlers::iterator it = registry.begin(); it != registry.end(); ++it)
delete (*it);
}
LeaveCriticalSection(&cs);
DeleteCriticalSection(&cs);
TlsFree(key);
@@ -104,7 +87,7 @@ BOOL WINAPI DllMain(HANDLE module, DWORD reason, LPVOID)
return TRUE;
}
extern "C" BOOST_THREAD_DECL int on_thread_exit(void (__cdecl * func)(void))
int on_thread_exit(void (__cdecl * func)(void))
{
// Get the exit handlers for the current thread, creating and registering
// one if it doesn't exist.
@@ -114,7 +97,7 @@ extern "C" BOOST_THREAD_DECL int on_thread_exit(void (__cdecl * func)(void))
try
{
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)
return -1;
}
@@ -146,8 +129,8 @@ extern "C" BOOST_THREAD_DECL int on_thread_exit(void (__cdecl * func)(void))
}
}
// Attempt to add the handler to the list of exit handlers. If it's been
// previously added just report success and exit.
// Attempt to add the handler to the list of exit handlers. If it's been previously
// added just report success and exit.
try
{
handlers->push_front(func);
@@ -160,6 +143,4 @@ extern "C" BOOST_THREAD_DECL int on_thread_exit(void (__cdecl * func)(void))
return 0;
}
#endif // BOOST_THREAD_BUILD_DLL
#endif // BOOST_HAS_WINTHREADS

23
src/threadmon.hpp Normal file
View File

@@ -0,0 +1,23 @@
#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

@@ -83,7 +83,7 @@ namespace {
}
#endif
inline void to_duration(boost::xtime xt, int& milliseconds)
inline void to_duration(const boost::xtime& xt, int& milliseconds)
{
boost::xtime cur;
int res = 0;
@@ -94,11 +94,6 @@ namespace {
milliseconds = 0;
else
{
if (cur.nsec > xt.nsec)
{
xt.nsec += NANOSECONDS_PER_SECOND;
--xt.sec;
}
milliseconds = ((xt.sec - cur.sec) * MILLISECONDS_PER_SECOND) +
(((xt.nsec - cur.nsec) + (NANOSECONDS_PER_MILLISECOND/2)) /
NANOSECONDS_PER_MILLISECOND);

View File

@@ -20,7 +20,7 @@
#endif
#if defined(BOOST_HAS_WINTHREADS)
#include <boost/thread/detail/threadmon.hpp>
#include "threadmon.hpp"
#include <map>
namespace {
typedef std::pair<void(*)(void*), void*> cleanup_info;

View File

@@ -1,10 +1,12 @@
# (C) Copyright William E. Kempf 2001. Permission to copy, use, modify, sell
# and distribute this software is granted provided this copyright notice
# appears in all copies. This software is provided "as is" without express or
# implied warranty, and with no claim as to its suitability for any purpose.
# (C) Copyright William E. Kempf 2001. Permission to copy, use, modify, sell and
# distribute this software is granted provided this copyright notice appears
# in all copies. This software is provided "as is" without express or implied
# warranty, and with no claim as to its suitability for any purpose.
#
# Boost.Threads test Jamfile
#
# Declares the following targets:
# 1. test_thread, a unit test executable.
# 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
@@ -28,25 +30,23 @@ include threads.jam ;
SEARCH on testing.jam = $(BOOST_BUILD_PATH) ;
include testing.jam ;
{
template test
## sources ##
: <template>thread_base
<dll>../build/boost_thread
<lib>../../test/build/boost_unit_test_framework
# $(threadmon)
## requirements ##
:
## default build ##
: # debug release <runtime-link>static/dynamic
;
sources = test.cpp test_thread.cpp test_mutex.cpp test_condition.cpp test_tss.cpp test_once.cpp ;
test-suite "threads"
: [ 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 ]
;
}
template test
## sources ##
: <template>thread_base <lib>../build/boost_thread <lib>../../test/build/unit_test_framework $(threadmon)
## requirements ##
:
## default build ##
: debug release <runtime-link>static/dynamic
;
#######################
# 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

@@ -4,83 +4,100 @@
#include <boost/test/unit_test.hpp>
#include "util.inl"
struct condition_test_data
namespace
{
condition_test_data() : notified(0), awoken(0) { }
struct condition_test_data
{
condition_test_data() : notified(0), awoken(0) { }
boost::mutex mutex;
boost::condition condition;
int notified;
int awoken;
};
boost::mutex mutex;
boost::condition condition;
int notified;
int awoken;
};
void condition_test_thread(condition_test_data* data)
{
boost::mutex::scoped_lock lock(data->mutex);
BOOST_CHECK(lock ? true : false);
while (!(data->notified > 0))
data->condition.wait(lock);
BOOST_CHECK(lock ? true : false);
data->awoken++;
void condition_test_thread(void* param)
{
condition_test_data* data = static_cast<condition_test_data*>(param);
boost::mutex::scoped_lock lock(data->mutex);
BOOST_CHECK(lock ? true : false);
while (!(data->notified > 0))
data->condition.wait(lock);
BOOST_CHECK(lock ? true : false);
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();
}
}
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()
void test_condition_notify_one()
{
condition_test_data data;
boost::thread thread(bind(&condition_test_thread, &data));
boost::thread thread(thread_adapter(&condition_test_thread, &data));
{
boost::mutex::scoped_lock lock(data.mutex);
@@ -93,19 +110,14 @@ void do_test_condition_notify_one()
BOOST_CHECK_EQUAL(data.awoken, 1);
}
void test_condition_notify_one()
{
timed_test(&do_test_condition_notify_one, 2, execution_monitor::use_mutex);
}
void do_test_condition_notify_all()
void test_condition_notify_all()
{
const int NUMTHREADS = 5;
boost::thread_group threads;
condition_test_data data;
for (int i = 0; i < NUMTHREADS; ++i)
threads.create_thread(bind(&condition_test_thread, &data));
threads.create_thread(thread_adapter(&condition_test_thread, &data));
{
boost::mutex::scoped_lock lock(data.mutex);
@@ -118,25 +130,21 @@ void do_test_condition_notify_all()
BOOST_CHECK_EQUAL(data.awoken, NUMTHREADS);
}
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()
void test_condition_waits()
{
condition_test_data data;
boost::thread thread(bind(&condition_test_waits, &data));
boost::thread thread(thread_adapter(&condition_test_waits, &data));
boost::xtime xt;
{
boost::mutex::scoped_lock lock(data.mutex);
BOOST_CHECK(lock ? true : false);
boost::thread::sleep(delay(1));
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
xt.sec += 1;
boost::thread::sleep(xt);
data.notified++;
data.condition.notify_one();
while (data.awoken != 1)
@@ -144,7 +152,9 @@ void do_test_condition_waits()
BOOST_CHECK(lock ? true : false);
BOOST_CHECK_EQUAL(data.awoken, 1);
boost::thread::sleep(delay(1));
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
xt.sec += 1;
boost::thread::sleep(xt);
data.notified++;
data.condition.notify_one();
while (data.awoken != 2)
@@ -152,7 +162,9 @@ void do_test_condition_waits()
BOOST_CHECK(lock ? true : false);
BOOST_CHECK_EQUAL(data.awoken, 2);
boost::thread::sleep(delay(1));
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
xt.sec += 1;
boost::thread::sleep(xt);
data.notified++;
data.condition.notify_one();
while (data.awoken != 3)
@@ -160,7 +172,9 @@ void do_test_condition_waits()
BOOST_CHECK(lock ? true : false);
BOOST_CHECK_EQUAL(data.awoken, 3);
boost::thread::sleep(delay(1));
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
xt.sec += 1;
boost::thread::sleep(xt);
data.notified++;
data.condition.notify_one();
while (data.awoken != 4)
@@ -169,22 +183,16 @@ void do_test_condition_waits()
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();
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* 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_all));

View File

@@ -6,8 +6,22 @@
#include <boost/test/unit_test.hpp>
#include <boost/test/unit_test_suite_ex.hpp>
#define DEFAULT_EXECUTION_MONITOR_TYPE execution_monitor::use_sleep_only
#include "util.inl"
namespace
{
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>
struct test_lock
@@ -29,7 +43,9 @@ struct test_lock
BOOST_CHECK(lock ? true : false);
// Construct and initialize an xtime for a fast time out.
boost::xtime xt = delay(0, 100);
boost::xtime xt;
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.
// No one is going to notify this condition variable. We expect to
@@ -69,7 +85,9 @@ struct test_trylock
BOOST_CHECK(lock ? true : false);
// Construct and initialize an xtime for a fast time out.
boost::xtime xt = delay(0, 100);
boost::xtime xt;
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.
// No one is going to notify this condition variable. We expect to
@@ -103,7 +121,9 @@ struct test_timedlock
// Test the lock's constructors.
{
// Construct and initialize an xtime for a fast time out.
boost::xtime xt = delay(0, 100);
boost::xtime xt;
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);
BOOST_CHECK(lock ? true : false);
@@ -116,14 +136,16 @@ struct test_timedlock
BOOST_CHECK(lock ? true : false);
// Construct and initialize an xtime for a fast time out.
boost::xtime xt = delay(0, 100);
boost::xtime xt;
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.
// No one is going to notify this condition variable. We expect to
// time out.
BOOST_CHECK(!condition.timed_wait(lock, xt));
BOOST_CHECK(lock ? true : false);
BOOST_CHECK(in_range(xt));
BOOST_CHECK(xtime_in_range(xt, -1, 0));
// Test the lock, unlock and timedlock methods.
lock.unlock();
@@ -132,7 +154,8 @@ struct test_timedlock
BOOST_CHECK(lock ? true : false);
lock.unlock();
BOOST_CHECK(!lock);
xt = delay(0, 100);
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
xt.nsec += 100000000;
BOOST_CHECK(lock.timed_lock(xt));
BOOST_CHECK(lock ? true : false);
}
@@ -152,63 +175,38 @@ struct test_recursive_lock
}
};
void do_test_mutex()
void test_mutex()
{
test_lock<boost::mutex>()();
}
void test_mutex()
{
timed_test(&do_test_mutex, 3);
}
void do_test_try_mutex()
void test_try_mutex()
{
test_lock<boost::try_mutex>()();
test_trylock<boost::try_mutex>()();
}
void test_try_mutex()
{
timed_test(&do_test_try_mutex, 3);
}
void do_test_timed_mutex()
void test_timed_mutex()
{
test_lock<boost::timed_mutex>()();
test_trylock<boost::timed_mutex>()();
test_timedlock<boost::timed_mutex>()();
}
void test_timed_mutex()
{
timed_test(&do_test_timed_mutex, 3);
}
void do_test_recursive_mutex()
void test_recursive_mutex()
{
test_lock<boost::recursive_mutex>()();
test_recursive_lock<boost::recursive_mutex>()();
}
void test_recursive_mutex()
{
timed_test(&do_test_recursive_mutex, 3);
}
void do_test_recursive_try_mutex()
void test_recursive_try_mutex()
{
test_lock<boost::recursive_try_mutex>()();
test_trylock<boost::recursive_try_mutex>()();
test_recursive_lock<boost::recursive_try_mutex>()();
}
void test_recursive_try_mutex()
{
timed_test(&do_test_recursive_try_mutex, 3);
}
void do_test_recursive_timed_mutex()
void test_recursive_timed_mutex()
{
test_lock<boost::recursive_timed_mutex>()();
test_trylock<boost::recursive_timed_mutex>()();
@@ -216,11 +214,6 @@ void do_test_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* test = BOOST_TEST_SUITE("Boost.Threads: mutex test suite");

View File

@@ -3,22 +3,23 @@
#include <boost/test/unit_test.hpp>
#include "util.inl"
int once_value = 0;
boost::once_flag once = BOOST_ONCE_INIT;
void init_once_value()
namespace
{
once_value++;
int once_value = 0;
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_thread()
{
boost::call_once(init_once_value, once);
}
void do_test_once()
void test_once()
{
const int NUMTHREADS=5;
boost::thread_group threads;
@@ -28,11 +29,6 @@ void do_test_once()
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* test = BOOST_TEST_SUITE("Boost.Threads: once test suite");

View File

@@ -3,33 +3,66 @@
#include <boost/test/unit_test.hpp>
#define DEFAULT_EXECUTION_MONITOR_TYPE execution_monitor::use_sleep_only
#include "util.inl"
int test_value;
void simple_thread()
namespace
{
test_value = 999;
}
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));
void comparison_thread(boost::thread* parent)
{
boost::thread thrd;
BOOST_TEST(thrd != *parent);
BOOST_TEST(thrd == boost::thread());
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);
}
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()
{
boost::xtime xt = delay(3);
boost::xtime xt;
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
xt.sec += 3;
boost::thread::sleep(xt);
// Insure it's in a range instead of checking actual equality due to time lapse
BOOST_CHECK(in_range(xt));
BOOST_CHECK(xtime_in_range(xt, -1, 0));
}
void do_test_creation()
void test_creation()
{
test_value = 0;
boost::thread thrd(&simple_thread);
@@ -37,21 +70,11 @@ void do_test_creation()
BOOST_CHECK_EQUAL(test_value, 999);
}
void test_creation()
{
timed_test(&do_test_creation, 1);
}
void do_test_comparison()
{
boost::thread self;
boost::thread thrd(bind(&comparison_thread, &self));
thrd.join();
}
void test_comparison()
{
timed_test(&do_test_comparison, 1);
boost::thread self;
boost::thread thrd(thread_adapter(comparison_thread, self));
thrd.join();
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])

View File

@@ -4,41 +4,42 @@
#include <boost/test/unit_test.hpp>
#include "util.inl"
boost::mutex tss_mutex;
int tss_instances = 0;
struct tss_value_t
namespace
{
tss_value_t()
{
boost::mutex::scoped_lock lock(tss_mutex);
++tss_instances;
value = 0;
}
~tss_value_t()
{
boost::mutex::scoped_lock lock(tss_mutex);
--tss_instances;
}
int value;
};
boost::mutex tss_mutex;
int tss_instances = 0;
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)
struct tss_value_t
{
int& n = tss_value->value;
BOOST_CHECK_EQUAL(n, i);
++n;
tss_value_t()
{
boost::mutex::scoped_lock lock(tss_mutex);
++tss_instances;
value = 0;
}
~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());
for (int i=0; i<1000; ++i)
{
int& n = tss_value->value;
BOOST_CHECK_EQUAL(n, i);
++n;
}
}
}
void do_test_tss()
void test_tss()
{
const int NUMTHREADS=5;
boost::thread_group threads;
@@ -48,11 +49,6 @@ void do_test_tss()
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* test = BOOST_TEST_SUITE("Boost.Threads: tss test suite");

View File

@@ -1,150 +0,0 @@
#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

@@ -26,10 +26,5 @@ template tutorial
exe helloworld : <template>tutorial helloworld.cpp ;
exe helloworld2 : <template>tutorial helloworld2.cpp ;
exe helloworld3 : <template>tutorial helloworld3.cpp ;
exe helloworld4 : <template>tutorial helloworld4.cpp ;
exe factorial : <template>tutorial factorial.cpp ;
exe factorial2 : <template>tutorial factorial2.cpp ;
exe factorial3 : <template>tutorial factorial3.cpp ;
exe counter : <template>tutorial counter.cpp ;
exe bounded_buffer : <template>tutorial bounded_buffer.cpp ;
exe once : <template>tutorial once.cpp ;

View File

@@ -1,63 +0,0 @@
#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();
}

View File

@@ -1,22 +0,0 @@
#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,30 +0,0 @@
#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 i=0; i < NUM_CALCS; ++i)
std::cout << i*10 << "! = " << results[i] << std::endl;
}

View File

@@ -3,12 +3,13 @@
struct helloworld
{
helloworld() { }
void operator()() { std::cout << "Hello World." << std::endl; }
helloworld(const char* who) : m_who(who) { }
void operator()() { std::cout << m_who << "says, \"Hello World.\"" << std::endl; }
const char* m_who;
};
int main()
{
boost::thread thrd(helloworld());
boost::thread thrd(helloworld("Bob"));
thrd.join();
}

View File

@@ -1,15 +1,14 @@
#include <boost/thread/thread.hpp>
#include <boost/bind.hpp>
#include <iostream>
struct helloworld
void helloworld(const char* who)
{
helloworld(const char* who) : m_who(who) { }
void operator()() { std::cout << m_who << "says, \"Hello World.\"" << std::endl; }
const char* m_who;
};
std::cout << who << "says, \"Hello World.\"" << std::endl;
}
int main()
{
boost::thread thrd(helloworld("Bob"));
boost::thread thrd(boost::bind(&helloworld, "Bob"));
thrd.join();
}

View File

@@ -1,14 +0,0 @@
#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();
}

View File

@@ -1,25 +0,0 @@
#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);
}

View File

@@ -1,30 +0,0 @@
#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();
}