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

Compare commits

..

1 Commits

Author SHA1 Message Date
nobody
f25e80b47c This commit was manufactured by cvs2svn to create branch
'python-v2-dev'.

[SVN r14785]
2002-08-12 13:35:54 +00:00
92 changed files with 3306 additions and 4499 deletions

View File

@@ -1,11 +1,17 @@
# (C) Copyright William E. Kempf 2001. Permission to copy, use, modify, # (C) Copyright William E. Kempf 2001. Permission to copy, use, modify, sell and
# sell and distribute this software is granted provided this copyright # distribute this software is granted provided this copyright notice appears
# notice appears in all copies. This software is provided "as is" without # in all copies. This software is provided "as is" without express or implied
# express or implied warranty, and with no claim as to its suitability for # warranty, and with no claim as to its suitability for any purpose.
# 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
@@ -25,29 +31,40 @@ subproject libs/thread/build ;
SEARCH on <module@>threads.jam = $(SUBDIR) ; SEARCH on <module@>threads.jam = $(SUBDIR) ;
include <module@>threads.jam ; include <module@>threads.jam ;
#######################
# Conditionally declare the Boost.Threads dynamic link library boost_threadmon.
if $(NT) && ! $(PTW32)
{ {
template thread_libs dll boost_threadmon
## sources ## : ../src/threadmon.cpp
: <template>thread_base : <sysinclude>$(BOOST_ROOT)
## requirements ## <threading>multi
: : debug release <runtime-link>static/dynamic
## 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
: ../src/$(CPP_SOURCES).cpp
: <sysinclude>$(BOOST_ROOT)
<threading>multi
$(pthreads-win32)
: debug release <runtime-link>static/dynamic
;
#######################
# 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,5 +1,6 @@
# Do some OS-specific setup # Do some OS-specific setup
{
threadmon = ;
pthreads-win32 = ; pthreads-win32 = ;
if $(NT) if $(NT)
@@ -15,15 +16,8 @@
<library-file>$(install-path)/pre-built/lib/$(lib) <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)
<borland><*><cxxflags>-w-8004
## default build ##
:
;
} }

Binary file not shown.

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), Kevin S. Van Horn (for several updates/corrections build to work on other platforms), and Kevin S. Van Horn (for several updates/corrections
to the documentation), and Martin Johnson (shared library implementation).</p> to the documentation).</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

@@ -1,77 +0,0 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<link rel="stylesheet" type="text/css" href="../../../boost.css">
<title>{{Library}} - Overview</title>
</head>
<body link="#0000ff" vlink="#800080">
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
"header">
<tr>
<td valign="top" width="300">
<h3><a href="../../../index.htm"><img height="86" width="277" alt="C++ Boost" src="../../../c++boost.gif" border="0"></a></h3>
</td>
<td valign="top">
<h1 align="center">Boost.Threads</h1>
<h2 align="center">Building and Testing</h2>
</td>
</tr>
</table>
<hr>
<dl class="index">
<dt><a href="#introduction">Introduction</a></dt>
<dt><a href="#topic1">First topic</a></dt>
<dt><a href="#topic2">Second topic</a></dt>
<dt><a href="#footnotes">Footnotes</a></dt>
</dl>
<h2><a name="introduction"></a>Introduction</h2>
<p>How you build the Boost.Threads libraries, and how you build your own applications
that use those libraries, are some of the most frequently asked questions. Build
processes are difficult to deal with in a portable manner. That's one reason
why Boost.Threads makes use of <a href="../../../tools/build/index.html">Boost.Build</a>.
In general you should refer to the documentation for <a href="../../../tools/build/index.html">Boost.Build</a>.
This document will only supply you with some simple usage examples for how to
use <em>bjam</em> to build and test Boost.Threads. In addition, this document
will try and explain the build requirements so that users may create their own
build processes (for instance, create an IDE specific project), both for building
and testing Boost.Threads, as well as for building their own projects using
Boost.Threads. </p>
<h2><a name="topic1"></a>Building the Boost.Threads Libraries</h2>
<p>To build the Boost.Thread libraries using Boost.Build, simply change to the
directory <em>boost_root</em>/libs/thread/build and execute the command:</p>
<pre>bjam -sTOOLS=<em>toolset</em></pre>
<p>This will create four variants of the Boost.Threads library with the permuations
of debug/release and runtime-link-dynamic/runtime-link-static. <em><strong>Note:</strong></em>
Invoking the above command in <em>boost_root</em> will build all of the Boost
distribution, including Boost.Threads.</p>
<p>The Jamfile supplied with Boost.Threads produces a static library named <em>libboostthread</em>.
In addition, on Win32 platforms a <em>boostthreadmon.dll</em> and a coresponding
import library are created. The source files that are used to create the <em>libboostthread</em>
library are all of the *.cpp files found in <em>boost_root</em>/libs/thread/src,
except for <em>threadmon.cpp</em>. These need to be built with the compiler's
and linker's multi-threading support enabled. On Win32 platforms the <em>boostthreadmon.dll</em>
is created from <em>boost_root</em>/libs/thread/src/threadmon.cpp. This, too,
needs to be built with the compiler's and linker's multi-threading support enabled.
If you want to create your own build solution you'll have to follow these same
guidelines. One of the most frequently reported problems when trying to do this
occurs from not enabling the compiler's and linker's support for multi-threading.</p>
<h2><a name="topic2"></a>Testing the Boost.Threads Libraries</h2>
<p>To test the Boost.Threads libraries using Boost.Build, simply change to the
directory <em>boost_root</em>/libs/thread/test and execute the command:</p>
<pre><code>bjam -sTOOLS=<em>toolset</em> test</code></pre>
<p> </p>
<h2><a name="footnotes"></a>Footnotes</h2>
<dl>
<dt><a name="footnote1" class="footnote">(1)</a> {{text}}</dt>
<dt><a name="footnote2" class="footnote">(2)</a> {{text}}</dt>
</dl>
<hr>
<p>Revised
<!--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:{{address}}">{{author}}</a>
2002. All Rights Reserved.</i></p>
</body>
</html>

View File

@@ -61,9 +61,10 @@
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>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. // Class condition meets the <a href="overview.html#non-copyable">NonCopyable</a> requirement.
{ {
public: public:
@@ -85,19 +86,22 @@
</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>condition(); <pre>
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>~condition(); <pre>
~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>void notify_one(); <pre>
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
@@ -107,14 +111,16 @@
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>void notify_all(); <pre>
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>template &lt;typename ScopedLock&gt; <pre>
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">
@@ -132,7 +138,8 @@
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>Template&lt;typename ScopedLock, typename Pr&gt; <pre>
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">
@@ -142,7 +149,8 @@
<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>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); 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">
@@ -163,14 +171,16 @@
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>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); 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>while (!pred()) <pre>
while (!pred())
{ {
if (!timed_wait(lock, XT)) if (!timed_wait(lock, XT))
return false; return false;
@@ -184,9 +194,79 @@ return true;
if <code>!lock.locked()</code></dt> if <code>!lock.locked()</code></dt>
</dl> </dl>
<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> <pre>
#include &lt;iostream&gt;
#include &lt;vector&gt;
#include <a href="../../../boost/utility.hpp">&lt;boost/utility.hpp&gt;</a>
#include <a href="../../../boost/thread/condition.hpp">&lt;boost/thread/condition.hpp&gt;</a>
#include <a href="../../../boost/thread/thread.hpp">&lt;boost/thread/thread.hpp&gt;</a>
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&lt;int&gt; circular_buf;
boost::condition buffer_not_full, buffer_not_empty;
boost::mutex monitor;
};
bounded_buffer buf(2);
void sender() {
int n = 0;
while (n &lt; 100) {
buf.send(n);
std::cout &lt;&lt; &quot;sent: &quot; &lt;&lt; n &lt;&lt; std::endl;
++n;
}
buf.send(-1);
}
void receiver() {
int n;
do {
n = buf.receive();
std::cout &lt;&lt; &quot;received: &quot; &lt;&lt; n &lt;&lt; std::endl;
} while (n != -1); // -1 indicates end of buffer
}
int main(int, char*[])
{
boost::thread thrd1(&amp;sender);
boost::thread thrd2(&amp;receiver);
thrd1.join();
thrd2.join();
return 0;
}
</pre>
<p>Typical output (dependent on scheduling policies) is:</p> <p>Typical output (dependent on scheduling policies) is:</p>
<pre>sent: 0 <pre>
sent: 0
sent: 1 sent: 1
received: 0 received: 0
received: 1 received: 1
@@ -198,7 +278,9 @@ sent: 4
received: 4 received: 4
</pre> </pre>
<p>Revised <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>
<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>

View File

@@ -241,17 +241,18 @@
there is no matching exception handler in a program [15.3/9]. That is, terminate() 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> is called, and it is implementation defined whether or not the stack is unwound.</p>
<h2><a name="acknowledgements"></a>Acknowledgments</h2> <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 <p>This document has been much improved by the incorporation of comments from
William Kempf, who now maintains the contents.</p> William Kempf.</p>
<p>The visibility rules are based on <a href= <p>The visibility rules are based on <a href=
"bibliography.html#Butenhof-97">[Butenhof 97]</a>.</p> "bibliography.html#Butenhof-97">[Butenhof 97]</a>.</p>
<hr> <hr>
<p>Revised <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>
<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.<br> All Rights Reserved.</i></p>
</i>© Copyright Beman Dawes, 2001</p>
<p>Permission to use, copy, modify, distribute and sell this software and its <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 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 above copyright notice appear in all copies and that both that copyright notice

View File

@@ -86,7 +86,8 @@
"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>class counter <pre>
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
@@ -144,8 +145,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 <p>Condition variables result in user code much less prone to <a href=
<a href="definitions.html#definition-race-condition">race conditions</a> than event variables. "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 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
@@ -166,7 +167,9 @@ 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 -->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>
<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>

View File

@@ -130,7 +130,6 @@
</dl> </dl>
</dl> </dl>
<dt><a href="configuration.html">Configuration Information</a></dt> <dt><a href="configuration.html">Configuration Information</a></dt>
<dt><a href="build.html">Building and Testing</a></dt>
<dt><a href="introduction.html">Introduction to Design</a></dt> <dt><a href="introduction.html">Introduction to Design</a></dt>
<dt><a href="rationale.html">Rationale</a></dt> <dt><a href="rationale.html">Rationale</a></dt>
<dt><a href="definitions.html">Definitions</a></dt> <dt><a href="definitions.html">Definitions</a></dt>

View File

@@ -217,7 +217,52 @@ timed_mutex();
resulting in undefined behavior such as a program crash.</dt> resulting in undefined behavior such as a program crash.</dt>
</dl> </dl>
<h2><a name="examples"></a>Example(s)</h2> <h2><a name="examples"></a>Example(s)</h2>
<p><a href="../example/mutex.cpp">libs/thread/example/mutex.cpp</a></p> <pre>
#include <a href=
"../../../boost/thread/mutex.hpp">&lt;boost/thread/mutex.hpp&gt;</a>
#include <a href=
"../../../boost/thread/thread.hpp">&lt;boost/thread/thread.hpp&gt;</a>
#include &lt;iostream&gt;
boost::mutex io_mutex; // The iostreams are not guaranteed to be <a href=
"definitions.html#Thread-safe">thread-safe</a>!
class counter
{
public:
counter() : count(0) { }
int increment() {
boost::mutex::scoped_lock scoped_lock(mutex);
return ++count;
}
private:
boost::mutex mutex;
int count;
};
counter c;
void change_count()
{
int i = c.increment();
boost::mutex::scoped_lock scoped_lock(io_mutex);
std::cout &lt;&lt; &quot;count == &quot; &lt;&lt; i &lt;&lt; std::endl;
}
int main(int, char*[])
{
const int num_threads = 4;
boost::thread_group thrds;
for (int i=0; i &lt; num_threads; ++i)
thrds.create_thread(&amp;change_count);
thrds.join_all();
return 0;
}
</pre>
<p>The output is:</p> <p>The output is:</p>
<pre> <pre>
count == 1 count == 1

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,7 +223,9 @@
</table> </table>
<hr> <hr>
<p>Revised <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>
<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>

View File

@@ -71,7 +71,33 @@ if (flag == BOOST_ONCE_INIT)
<dt><b>Postconditions:</b> <code>flag != BOOST_ONCE_INIT</code></dt> <dt><b>Postconditions:</b> <code>flag != BOOST_ONCE_INIT</code></dt>
</dl> </dl>
<h2><a name="examples"></a>Example(s)</h2> <h2><a name="examples"></a>Example(s)</h2>
<p><a href="../example/once.cpp">libs/thread/example/once.cpp</a></p> <pre>
#include <a href="../../../boost/thread/thread.hpp">&lt;boost/thread/thread.hpp&gt;</a>
#include <a href="../../../boost/thread/tss.hpp">&lt;boost/thread/once.hpp&gt;</a>
#include &lt;cassert&gt;
int value=0;
boost::once_flag once = BOOST_ONCE_INIT;
void init()
{
++value;
}
void thread_proc()
{
boost::call_once(&amp;init, once);
}
int main(int argc, char* argv[])
{
boost::thread_group threads;
for (int i=0; i&lt;5; ++i)
threads.create_thread(&amp;thread_proc);
threads.join_all();
assert(value == 1);
}
</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 -->

View File

@@ -110,8 +110,7 @@
<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 for the C++ Standard Library. Otherwise <a href="definitions.html#Race condition">race
<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>
@@ -158,7 +157,9 @@
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 -->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>
<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>

View File

@@ -144,27 +144,31 @@
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>void foo() <pre>
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>Void foo() <pre>
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>Void foo() <pre>
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>Void foo() <pre>
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);
@@ -173,14 +177,16 @@
} }
</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>Void foo() <pre>
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>Void foo() <pre>
Void foo()
{ {
thread = create_thread(&amp;bar); thread = create_thread(&amp;bar);
manager1.add(thread); manager1.add(thread);
@@ -205,7 +211,8 @@
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>void foo() <pre>
void foo()
{ {
thread thrd(&amp;bar); thread thrd(&amp;bar);
} }
@@ -216,7 +223,8 @@ void foo()
} }
</pre> </pre>
<h3>2.</h3> <h3>2.</h3>
<pre>void foo() <pre>
void foo()
{ {
thread thrd(&amp;bar); thread thrd(&amp;bar);
thrd.join(); thrd.join();
@@ -229,7 +237,8 @@ void foo()
} }
</pre> </pre>
<h3>3.</h3> <h3>3.</h3>
<pre>void foo() <pre>
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);
@@ -242,7 +251,8 @@ void foo()
} }
</pre> </pre>
<h3>4.</h3> <h3>4.</h3>
<pre>void foo() <pre>
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)
@@ -261,7 +271,8 @@ void foo()
} }
</pre> </pre>
<h3>5.</h3> <h3>5.</h3>
<pre>void foo() <pre>
void foo()
{ {
thread thrd* = new thread(&amp;bar); thread thrd* = new thread(&amp;bar);
manager.owns(thread); manager.owns(thread);
@@ -274,7 +285,8 @@ void foo()
} }
</pre> </pre>
<h3>6.</h3> <h3>6.</h3>
<pre>void foo() <pre>
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);
@@ -296,7 +308,8 @@ 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>void foo() <pre>
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)
@@ -353,7 +366,8 @@ 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="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 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
@@ -369,7 +383,9 @@ 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 -->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>
<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>

View File

@@ -218,7 +218,51 @@ recursive_timed_mutex();
resulting in undefined behavior such as a program crash.</dt> resulting in undefined behavior such as a program crash.</dt>
</dl> </dl>
<h2><a name="examples"></a>Example(s)</h2> <h2><a name="examples"></a>Example(s)</h2>
<p><a href="../example/recursive_mutex.cpp">libs/thread/example/recursive_mutex.cpp</a></p> <pre>
#include <a href="../../../boost/thread/recursive_mutex.hpp">&lt;boost/thread/recursive_mutex.hpp&gt;</a>
#include <a href="../../../boost/thread/thread.hpp">&lt;boost/thread/thread.hpp&gt;</a>
#include &lt;iostream&gt;
class counter
{
public:
counter() : count(0) { }
int add(int val) {
boost::recursive_mutex::scoped_lock scoped_lock(mutex);
count += val;
return count;
}
int increment() {
boost::recursive_mutex::scoped_lock scoped_lock(mutex);
return add(1);
}
private:
boost::recursive_mutex mutex;
int count;
};
counter c;
void change_count(void*)
{
std::cout &lt;&lt; &quot;count == &quot; &lt;&lt; c.increment() &lt;&lt; std::endl;
}
int main(int, char*[])
{
const int num_threads=4;
boost::thread_group threads;
for (int i=0; i &lt; num_threads; ++i)
threads.create_thread(&amp;change_count, 0);
threads.join_all();
return 0;
}
</pre>
<p>The output is:</p> <p>The output is:</p>
<pre> <pre>
count == 1 count == 1

View File

@@ -85,8 +85,10 @@
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>namespace boost { <pre>
class thread : <a href="../../utility/utility.htm#Class_noncopyable">boost::noncopyable</a> // Exposition only. namespace boost {
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.
{ {
@@ -107,7 +109,8 @@ 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>thread(); <pre>
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
@@ -115,7 +118,8 @@ public:
<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>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> </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>
@@ -128,7 +132,8 @@ public:
<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>~Thread(); <pre>
~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
@@ -141,21 +146,24 @@ public:
</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>bool operator==(const thread&amp; rhs) const; <pre>
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>bool operator!=(const thread&amp; rhs) const; <pre>
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>void join(); <pre>
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>
@@ -168,13 +176,15 @@ public:
<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>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> </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>static void yield(); <pre>
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;
@@ -190,9 +200,10 @@ public:
"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>namespace boost { <pre>
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();
@@ -207,12 +218,14 @@ public:
</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>thread_group(); <pre>
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>~thread_group(); <pre>
~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>
@@ -221,7 +234,8 @@ public:
</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>thread* create_thread(const boost::function0&lt;void&gt;&amp; threadfunc); <pre>
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>
@@ -229,14 +243,16 @@ public:
<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>void add_thread(thread* thrd); <pre>
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>Void remove_thread(thread* thrd); <pre>
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>
@@ -244,14 +260,16 @@ public:
<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>Void join_all(); <pre>
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><a name="function-spec"></a>{{function}} <pre>
<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>
@@ -266,15 +284,66 @@ public:
<p><a name="object-spec"></a>{{Object specifications}}</p> <p><a name="object-spec"></a>{{Object specifications}}</p>
<h2><a name="examples"></a>Example(s)</h2> <h2><a name="examples"></a>Example(s)</h2>
<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> <pre>
#include &lt;boost/thread/thread.hpp&gt;
#include &lt;iostream&gt;
struct thread_alarm
{
thread_alarm(int secs) : m_secs(secs) { }
void operator()()
{
boost::xtime XT;
boost::xtime_get(&amp;XT, boost::TIME_UTC);
xt.sec += m_secs;
boost::thread::sleep(XT);
std::cout &lt;&lt; &quot;alarm sounded...&quot; &lt;&lt; std::endl;
}
int m_secs;
};
int main(int argc, char* argv[])
{
int secs = 5;
std::cout &lt;&lt; &quot;setting alarm for 5 seconds...&quot; &lt;&lt; std::endl;
thread_alarm alarm(secs);
boost::thread thrd(alarm);
thrd.join();
}
</pre>
<p>The output is:</p> <p>The output is:</p>
<pre>setting alarm for 5 seconds... <pre>
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> <pre>
#include &lt;boost/thread/thread.hpp&gt;
#include &lt;iostream&gt;
int count = 0;
boost::mutex mutex;
void increment_count()
{
boost::mutex::lock lock(mutex);
std::cout &lt;&lt; &quot;count = &quot; &lt;&lt; ++count &lt;&lt; std::endl;
}
int main(int argc, char* argv[])
{
boost::thread_group threads;
for (int i = 0; i &lt; 10; ++i)
threads.create_thread(&amp;increment_count);
threads.join_all();
}
</pre>
<p>The output is:</p> <p>The output is:</p>
<pre>count = 1 <pre>
count = 1
count = 2 count = 2
count = 3 count = 3
count = 4 count = 4
@@ -287,7 +356,9 @@ count = 10
</pre> </pre>
<hr> <hr>
<p>Revised <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>
<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>

View File

@@ -150,7 +150,38 @@ T& operator*() const;
<dt><b>Returns:</b> <code>this-&lt;get()</code>.</dt> <dt><b>Returns:</b> <code>this-&lt;get()</code>.</dt>
</dl> </dl>
<h2><a name="examples"></a>Example(s)</h2> <h2><a name="examples"></a>Example(s)</h2>
<p><a href="../example/tss.cpp">libs/thread/example/tss.cpp</a></p> <pre>
#include <a href="../../../boost/thread/thread.hpp">&lt;boost/thread/thread.hpp&gt;</a>
#include <a href="../../../boost/thread/tss.hpp">&lt;boost/thread/tss.hpp&gt;</a>
#include &lt;cassert&gt;
boost::thread_specific_ptr&lt;int&gt; value;
void increment()
{
int* p = value.get();
++*p;
}
void thread_proc()
{
value.reset(new int(0)); // initialize the thread&#39;s storage
for (int i=0; i&lt;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&lt;5; ++i)
threads.create_thread(&amp;thread_proc);
threads.join_all();
}
</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 -->

View File

@@ -91,7 +91,18 @@ namespace boost
one second.</dt> one second.</dt>
</dl> </dl>
<h2><a name="examples"></a>Example(s)</h2> <h2><a name="examples"></a>Example(s)</h2>
<p><a href="../example/xtime.cpp">libs/thread/example/xtime.cpp</a></p> <pre>
#include <a href="../../../boost/thread/thread.hpp">&lt;boost/thread/thread.hpp&gt;</a>
#include <a href="../../../boost/thread/tss.hpp">&lt;boost/thread/xtime.hpp&gt;</a>
int main(int argc, char* argv[])
{
boost::xtime xt;
boost::xtime_get(&amp;XT, boost::TIME_UTC);
xt.sec += 1;
boost::thread::sleep(XT); // Sleep for 1 second
}
</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 -->

View File

@@ -1,10 +1,14 @@
# (C) Copyright William E. Kempf 2001. Permission to copy, use, modify, sell # (C) Copyright William E. Kempf 2001. Permission to copy, use, modify, sell and
# and distribute this software is granted provided this copyright notice # distribute this software is granted provided this copyright notice appears
# appears in all copies. This software is provided "as is" without express or # in all copies. This software is provided "as is" without express or implied
# implied warranty, and with no claim as to its suitability for any purpose. # warranty, and with no claim as to its suitability for any purpose.
# #
# Boost.Threads example Jamfile # Boost.Threads build and test Jamfile
# #
# Declares the following targets:
# 1. monitor, an example program.
# 2. starvephil, an example program.
# 3. tennis, an example program.
# 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
@@ -24,26 +28,41 @@ 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 # Declare the Boost.Threads example program monitor.
## sources ##
: <template>thread_base exe monitor
<dll>../build/boost_thread : monitor/monitor.cpp
## requirements ## <lib>../build/boost_thread
: $(threadmon)
## default build ## : <sysinclude>$(BOOST_ROOT)
: $(pthreads-win32)
<threading>multi
: debug release <runtime-link>static/dynamic
; ;
exe monitor : <template>example monitor.cpp ; #######################
exe starvephil : <template>example starvephil.cpp ; # Declare the Boost.Threads example program starvephil.
exe tennis : <template>example tennis.cpp ;
exe condition : <template>example condition.cpp ; exe starvephil
exe mutex : <template>example mutex.cpp ; : starvephil/starvephil.cpp
exe once : <template>example once.cpp ; <lib>../build/boost_thread
exe recursive_mutex : <template>example recursive_mutex.cpp ; $(threadmon)
exe thread : <template>example thread.cpp ; : <sysinclude>$(BOOST_ROOT)
exe thread_group : <template>example thread_group.cpp ; $(pthreads-win32)
exe tss : <template>example tss.cpp ; <threading>multi
exe xtime : <template>example xtime.cpp ; : debug release <runtime-link>static/dynamic
} ;
#######################
# Declare the Boost.Threads example program tennis.
exe tennis
: tennis/tennis.cpp
<lib>../build/boost_thread
$(threadmon)
: <sysinclude>$(BOOST_ROOT)
$(pthreads-win32)
<threading>multi
: debug release <runtime-link>static/dynamic
;

View File

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

View File

@@ -1,79 +0,0 @@
// 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 <vector>
#include <boost/utility.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/thread.hpp>
class bounded_buffer : private boost::noncopyable
{
public:
typedef boost::mutex::scoped_lock lock;
bounded_buffer(int n) : begin(0), end(0), buffered(0), circular_buf(n) { }
void send (int m) {
lock lk(monitor);
while (buffered == circular_buf.size())
buffer_not_full.wait(lk);
circular_buf[end] = m;
end = (end+1) % circular_buf.size();
++buffered;
buffer_not_empty.notify_one();
}
int receive() {
lock lk(monitor);
while (buffered == 0)
buffer_not_empty.wait(lk);
int i = circular_buf[begin];
begin = (begin+1) % circular_buf.size();
--buffered;
buffer_not_full.notify_one();
return i;
}
private:
int begin, end, buffered;
std::vector<int> circular_buf;
boost::condition buffer_not_full, buffer_not_empty;
boost::mutex monitor;
};
bounded_buffer buf(2);
void sender() {
int n = 0;
while (n < 100) {
buf.send(n);
std::cout << "sent: " << n << std::endl;
++n;
}
buf.send(-1);
}
void receiver() {
int n;
do {
n = buf.receive();
std::cout << "received: " << n << std::endl;
} while (n != -1); // -1 indicates end of buffer
}
int main(int, char*[])
{
boost::thread thrd1(&sender);
boost::thread thrd2(&receiver);
thrd1.join();
thrd2.join();
return 0;
}

1
example/monitor/Carbon.r Normal file
View File

@@ -0,0 +1 @@
/*

View File

@@ -1,14 +1,3 @@
// 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>
@@ -17,11 +6,9 @@
#include <boost/thread/thread.hpp> #include <boost/thread/thread.hpp>
namespace { namespace {
const int ITERS = 100; const int ITERS = 100;
boost::mutex io_mutex; boost::mutex io_mutex;
}
} // namespace
template <typename M> template <typename M>
class buffer_t class buffer_t

BIN
example/monitor/monitor.mcp Normal file

Binary file not shown.

View File

@@ -1,52 +0,0 @@
// 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 io_mutex; // The iostreams are not guaranteed to be thread-safe!
class counter
{
public:
counter() : count(0) { }
int increment() {
boost::mutex::scoped_lock scoped_lock(mutex);
return ++count;
}
private:
boost::mutex mutex;
int count;
};
counter c;
void change_count()
{
int i = c.increment();
boost::mutex::scoped_lock scoped_lock(io_mutex);
std::cout << "count == " << i << std::endl;
}
int main(int, char*[])
{
const int num_threads = 4;
boost::thread_group thrds;
for (int i=0; i < num_threads; ++i)
thrds.create_thread(&change_count);
thrds.join_all();
return 0;
}

View File

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

View File

@@ -1,54 +0,0 @@
// 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/thread.hpp>
#include <iostream>
class counter
{
public:
counter() : count(0) { }
int add(int val) {
boost::recursive_mutex::scoped_lock scoped_lock(mutex);
count += val;
return count;
}
int increment() {
boost::recursive_mutex::scoped_lock scoped_lock(mutex);
return add(1);
}
private:
boost::recursive_mutex mutex;
int count;
};
counter c;
void change_count()
{
std::cout << "count == " << c.increment() << std::endl;
}
int main(int, char*[])
{
const int num_threads=4;
boost::thread_group threads;
for (int i=0; i < num_threads; ++i)
threads.create_thread(&change_count);
threads.join_all();
return 0;
}

View File

@@ -0,0 +1 @@
/*

View File

@@ -1,14 +1,3 @@
// 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>
@@ -16,10 +5,9 @@
#include <iostream> #include <iostream>
#include <time.h> #include <time.h>
namespace { namespace
{
boost::mutex iomx; boost::mutex iomx;
} }
class canteen class canteen
@@ -51,9 +39,8 @@ 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 " ") Chef: ouch ... make room ... this dish is very hot ..." << std::endl;
<< "very hot ..." << std::endl;
} }
boost::xtime xt; boost::xtime xt;
boost::xtime_get(&xt, boost::TIME_UTC); boost::xtime_get(&xt, boost::TIME_UTC);
@@ -109,8 +96,7 @@ struct phil
void run() { void run() {
{ {
boost::mutex::scoped_lock lock(iomx); boost::mutex::scoped_lock lock(iomx);
std::cout << "(" << clock() << ") Phil" << m_id std::cout << "(" << clock() << ") Phil" << m_id << ": starting ..." << std::endl;
<< ": starting ..." << std::endl;
} }
for (;;) for (;;)
{ {
@@ -143,10 +129,7 @@ struct phil
struct thread_adapt struct thread_adapt
{ {
thread_adapt(void (*func)(void*), void* param) thread_adapt(void (*func)(void*), void* param) : _func(func), _param(param) { }
: _func(func), _param(param)
{
}
int operator()() const int operator()() const
{ {
_func(_param); _func(_param);
@@ -160,10 +143,7 @@ struct thread_adapt
class thread_adapter class thread_adapter
{ {
public: public:
thread_adapter(void (*func)(void*), void* param) thread_adapter(void (*func)(void*), void* param) : _func(func), _param(param) { }
: _func(func), _param(param)
{
}
void operator()() const { _func(_param); } void operator()() const { _func(_param); }
private: private:
void (*_func)(void*); void (*_func)(void*);

Binary file not shown.

1
example/tennis/Carbon.r Normal file
View File

@@ -0,0 +1 @@
/*

View File

@@ -1,14 +1,3 @@
// 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>
@@ -60,8 +49,7 @@ void player(void* param)
{ {
cond.wait(lock); cond.wait(lock);
if (state == other) if (state == other)
std::cout << "---" << player_name(active) std::cout << "---" << player_name(active) << ": Spurious wakeup!" << std::endl;
<< ": Spurious wakeup!" << std::endl;
} while (state == other); } while (state == other);
} }
@@ -72,10 +60,7 @@ void player(void* param)
struct thread_adapt struct thread_adapt
{ {
thread_adapt(void (*func)(void*), void* param) thread_adapt(void (*func)(void*), void* param) : _func(func), _param(param) { }
: _func(func), _param(param)
{
}
int operator()() const int operator()() const
{ {
_func(_param); _func(_param);
@@ -89,10 +74,7 @@ struct thread_adapt
class thread_adapter class thread_adapter
{ {
public: public:
thread_adapter(void (*func)(void*), void* param) thread_adapter(void (*func)(void*), void* param) : _func(func), _param(param) { }
: _func(func), _param(param)
{
}
void operator()() const { _func(_param); } void operator()() const { _func(_param); }
private: private:
void (*_func)(void*); void (*_func)(void*);

BIN
example/tennis/tennis.mcp Normal file

Binary file not shown.

View File

@@ -1,40 +0,0 @@
// 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/xtime.hpp>
#include <iostream>
struct thread_alarm
{
thread_alarm(int secs) : m_secs(secs) { }
void operator()()
{
boost::xtime xt;
boost::xtime_get(&xt, boost::TIME_UTC);
xt.sec += m_secs;
boost::thread::sleep(xt);
std::cout << "alarm sounded..." << std::endl;
}
int m_secs;
};
int main(int argc, char* argv[])
{
int secs = 5;
std::cout << "setting alarm for 5 seconds..." << std::endl;
thread_alarm alarm(secs);
boost::thread thrd(alarm);
thrd.join();
}

View File

@@ -1,30 +0,0 @@
// 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>
int count = 0;
boost::mutex mutex;
void increment_count()
{
boost::mutex::scoped_lock lock(mutex);
std::cout << "count = " << ++count << std::endl;
}
int main(int argc, char* argv[])
{
boost::thread_group threads;
for (int i = 0; i < 10; ++i)
threads.create_thread(&increment_count);
threads.join_all();
}

View File

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

View File

@@ -1,21 +0,0 @@
// 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/xtime.hpp>
int main(int argc, char* argv[])
{
boost::xtime xt;
boost::xtime_get(&xt, boost::TIME_UTC);
xt.sec += 1;
boost::thread::sleep(xt); // Sleep for 1 second
}

View File

@@ -1,24 +0,0 @@
// 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-2003 // Copyright (C) 2001
// 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,7 +20,6 @@
#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>
@@ -32,60 +31,14 @@ namespace boost {
struct xtime; 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 class condition : private noncopyable
{ {
public: public:
condition() { } condition();
~condition() { } ~condition();
void notify_one() { m_impl.notify_one(); } void notify_one();
void notify_all() { m_impl.notify_all(); } void notify_all();
template <typename L> template <typename L>
void wait(L& lock) void wait(L& lock)
@@ -131,63 +84,79 @@ 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))
m_impl.enter_wait(); enter_wait();
#endif #endif
typedef detail::thread::lock_ops<M> typedef typename detail::thread::lock_ops<M> lock_ops;
#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)
m_impl.do_wait(state.pmutex); do_wait(state.pmutex);
#elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS)) #elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
m_impl.do_wait(); 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))
m_impl.enter_wait(); enter_wait();
#endif #endif
typedef detail::thread::lock_ops<M> typedef typename detail::thread::lock_ops<M> lock_ops;
#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 = m_impl.do_timed_wait(xt, state.pmutex); ret = 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 = m_impl.do_timed_wait(xt); ret = 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
@@ -195,8 +164,7 @@ 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 // 23 May 01 WEKEMPF Removed "duration" timed_waits, as they are too difficult
// difficult to use with spurious wakeups. // 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

@@ -1,25 +0,0 @@
// 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

@@ -47,8 +47,8 @@ inline singleton<T>::~singleton()
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 // function-local static to force this to work correctly at static initialization
// initialization time. // time.
static singleton<T> s_oT; static singleton<T> s_oT;
return(s_oT); return(s_oT);
} }

View File

@@ -1,25 +0,0 @@
// 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-2003 // Copyright (C) 2001
// 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,9 +12,6 @@
#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
@@ -25,13 +22,13 @@
namespace boost { namespace boost {
class BOOST_THREAD_DECL lock_error : public std::logic_error class lock_error : public std::logic_error
{ {
public: public:
lock_error(); lock_error();
}; };
class BOOST_THREAD_DECL thread_resource_error : public std::runtime_error class thread_resource_error : public std::runtime_error
{ {
public: public:
thread_resource_error(); thread_resource_error();
@@ -39,7 +36,4 @@ 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-2003 // Copyright (C) 2001
// 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,7 +19,6 @@
#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>
@@ -33,7 +32,7 @@ namespace boost {
struct xtime; struct xtime;
class BOOST_THREAD_DECL mutex : private noncopyable class mutex : private noncopyable
{ {
public: public:
friend class detail::thread::lock_ops<mutex>; friend class detail::thread::lock_ops<mutex>;
@@ -71,7 +70,7 @@ private:
#endif #endif
}; };
class BOOST_THREAD_DECL try_mutex : private noncopyable class try_mutex : private noncopyable
{ {
public: public:
friend class detail::thread::lock_ops<try_mutex>; friend class detail::thread::lock_ops<try_mutex>;
@@ -111,7 +110,7 @@ private:
#endif #endif
}; };
class BOOST_THREAD_DECL timed_mutex : private noncopyable class timed_mutex : private noncopyable
{ {
public: public:
friend class detail::thread::lock_ops<timed_mutex>; friend class detail::thread::lock_ops<timed_mutex>;
@@ -161,6 +160,5 @@ 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-2003 // Copyright (C) 2001
// 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,8 +17,6 @@
# 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
@@ -32,12 +30,12 @@ typedef pthread_once_t once_flag;
#elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS)) #elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
typedef long once_flag; typedef bool once_flag;
#define BOOST_ONCE_INIT 0 #define BOOST_ONCE_INIT false
#endif #endif
void BOOST_THREAD_DECL call_once(void (*func)(), once_flag& flag); void call_once(void (*func)(), once_flag& flag);
} // namespace boost } // namespace boost

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2001-2003 // Copyright (C) 2001
// 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,7 +19,6 @@
#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,7 +30,7 @@ namespace boost {
struct xtime; struct xtime;
class BOOST_THREAD_DECL recursive_mutex : private noncopyable class recursive_mutex : private noncopyable
{ {
public: public:
friend class detail::thread::lock_ops<recursive_mutex>; friend class detail::thread::lock_ops<recursive_mutex>;
@@ -74,14 +73,13 @@ private:
#endif #endif
}; };
class BOOST_THREAD_DECL recursive_try_mutex : private noncopyable class 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< typedef detail::thread::scoped_try_lock<recursive_try_mutex> scoped_try_lock;
recursive_try_mutex> scoped_try_lock;
recursive_try_mutex(); recursive_try_mutex();
~recursive_try_mutex(); ~recursive_try_mutex();
@@ -120,16 +118,14 @@ private:
#endif #endif
}; };
class BOOST_THREAD_DECL recursive_timed_mutex : private noncopyable class 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< typedef detail::thread::scoped_try_lock<recursive_timed_mutex> scoped_try_lock;
recursive_timed_mutex> scoped_try_lock; typedef detail::thread::scoped_timed_lock<recursive_timed_mutex> scoped_timed_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();
@@ -174,7 +170,5 @@ 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-2003 // Copyright (C) 2001
// 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,7 +20,6 @@
#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>
@@ -35,7 +34,7 @@ namespace boost {
struct xtime; struct xtime;
class BOOST_THREAD_DECL thread : private noncopyable class thread : private noncopyable
{ {
public: public:
thread(); thread();
@@ -64,7 +63,7 @@ private:
bool m_joinable; bool m_joinable;
}; };
class BOOST_THREAD_DECL thread_group : private noncopyable class thread_group : private noncopyable
{ {
public: public:
thread_group(); thread_group();

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2001-2003 // Copyright (C) 2001
// 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,7 +18,6 @@
#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>
@@ -29,7 +28,7 @@
namespace boost { namespace boost {
namespace detail { namespace detail {
class BOOST_THREAD_DECL tss : private noncopyable class tss : private noncopyable
{ {
public: public:
tss(void (*cleanup)(void*)=0); tss(void (*cleanup)(void*)=0);
@@ -65,13 +64,7 @@ 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) void reset(T* p=0) { T* cur = get(); if (cur == p) return; delete cur; m_tss.set(p); }
{
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-2003 // Copyright (C) 2001
// 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,9 +12,8 @@
#ifndef BOOST_XTIME_WEK070601_HPP #ifndef BOOST_XTIME_WEK070601_HPP
#define BOOST_XTIME_WEK070601_HPP #define BOOST_XTIME_WEK070601_HPP
#include <boost/config.hpp>
#include <boost/cstdint.hpp> #include <boost/cstdint.hpp>
#include <boost/thread/detail/config.hpp> #include <boost/config.hpp>
namespace boost { namespace boost {
@@ -40,7 +39,7 @@ struct xtime
int_fast32_t nsec; 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) 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,8 +0,0 @@
<html>
<head>
<meta http-equiv="refresh" content="0; URL=doc/index.html">
</head>
<body>
Automatic redirection failed, please go to <a href="doc/index.html">doc/index.html</a>
</body>
</html>

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2001-2003 // Copyright (C) 2001
// 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
@@ -32,16 +32,12 @@
namespace boost { namespace boost {
namespace detail {
#if defined(BOOST_HAS_WINTHREADS) #if defined(BOOST_HAS_WINTHREADS)
condition_impl::condition_impl() condition::condition()
: 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, m_queue = reinterpret_cast<void*>(CreateSemaphore(0, 0, std::numeric_limits<long>::max(), 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)
@@ -67,7 +63,7 @@ condition_impl::condition_impl()
} }
} }
condition_impl::~condition_impl() condition::~condition()
{ {
int res = 0; int res = 0;
res = CloseHandle(reinterpret_cast<HANDLE>(m_gate)); res = CloseHandle(reinterpret_cast<HANDLE>(m_gate));
@@ -78,7 +74,7 @@ condition_impl::~condition_impl()
assert(res); assert(res);
} }
void condition_impl::notify_one() void condition::notify_one()
{ {
unsigned signals = 0; unsigned signals = 0;
@@ -130,7 +126,7 @@ void condition_impl::notify_one()
} }
} }
void condition_impl::notify_all() void condition::notify_all()
{ {
unsigned signals = 0; unsigned signals = 0;
@@ -169,20 +165,19 @@ void condition_impl::notify_all()
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0); res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
assert(res); 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, res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_queue), signals, 0);
0);
assert(res); assert(res);
} }
} }
}
void condition_impl::enter_wait() void condition::enter_wait()
{ {
int res = 0; int res = 0;
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE); res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
@@ -192,7 +187,7 @@ void condition_impl::enter_wait()
assert(res); assert(res);
} }
void condition_impl::do_wait() void condition::do_wait()
{ {
int res = 0; int res = 0;
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue), INFINITE); res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue), INFINITE);
@@ -211,8 +206,7 @@ void condition_impl::do_wait()
{ {
if (m_blocked != 0) if (m_blocked != 0)
{ {
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0); // open m_gate
0); // open m_gate
assert(res); assert(res);
was_waiting = 0; was_waiting = 0;
} }
@@ -240,8 +234,7 @@ void condition_impl::do_wait()
for (/**/ ; was_gone; --was_gone) for (/**/ ; was_gone; --was_gone)
{ {
// better now than spurious later // better now than spurious later
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue), res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue), INFINITE);
INFINITE);
assert(res == WAIT_OBJECT_0); assert(res == WAIT_OBJECT_0);
} }
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0); res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
@@ -249,31 +242,16 @@ 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;
for (;;)
{ {
int milliseconds; int milliseconds;
to_duration(xt, milliseconds); to_duration(xt, milliseconds);
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue), unsigned int res = 0;
milliseconds); res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue), milliseconds);
assert(res != WAIT_FAILED && res != WAIT_ABANDONED); assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
ret = (res == WAIT_OBJECT_0);
if (res == WAIT_TIMEOUT) bool ret = (res == WAIT_OBJECT_0);
{
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;
@@ -295,8 +273,7 @@ bool condition_impl::do_timed_wait(const xtime& xt)
{ {
if (m_blocked != 0) if (m_blocked != 0)
{ {
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0); // open m_gate
0); // open m_gate
assert(res); assert(res);
was_waiting = 0; was_waiting = 0;
} }
@@ -324,8 +301,7 @@ bool condition_impl::do_timed_wait(const xtime& xt)
for (/**/ ; was_gone; --was_gone) for (/**/ ; was_gone; --was_gone)
{ {
// better now than spurious later // better now than spurious later
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue), res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue), INFINITE);
INFINITE);
assert(res == WAIT_OBJECT_0); assert(res == WAIT_OBJECT_0);
} }
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0); res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
@@ -335,7 +311,7 @@ bool condition_impl::do_timed_wait(const xtime& xt)
return ret; return ret;
} }
#elif defined(BOOST_HAS_PTHREADS) #elif defined(BOOST_HAS_PTHREADS)
condition_impl::condition_impl() condition::condition()
{ {
int res = 0; int res = 0;
res = pthread_cond_init(&m_condition, 0); res = pthread_cond_init(&m_condition, 0);
@@ -343,35 +319,35 @@ condition_impl::condition_impl()
throw thread_resource_error(); throw thread_resource_error();
} }
condition_impl::~condition_impl() condition::~condition()
{ {
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_impl::notify_one() void condition::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_impl::notify_all() void condition::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_impl::do_wait(pthread_mutex_t* pmutex) void condition::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_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; timespec ts;
to_timespec(xt, ts); to_timespec(xt, ts);
@@ -387,7 +363,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_enter_critical_region;
using threads::mac::detail::safe_wait_on_semaphore; using threads::mac::detail::safe_wait_on_semaphore;
condition_impl::condition_impl() condition::condition()
: 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();
@@ -415,7 +391,7 @@ condition_impl::condition_impl()
} }
} }
condition_impl::~condition_impl() condition::~condition()
{ {
OSStatus lStatus = noErr; OSStatus lStatus = noErr;
lStatus = MPDeleteSemaphore(m_gate); lStatus = MPDeleteSemaphore(m_gate);
@@ -424,13 +400,12 @@ condition_impl::~condition_impl()
assert(lStatus == noErr); assert(lStatus == noErr);
} }
void condition_impl::notify_one() void condition::notify_one()
{ {
unsigned signals = 0; unsigned signals = 0;
OSStatus lStatus = noErr; OSStatus lStatus = noErr;
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
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
@@ -477,13 +452,12 @@ void condition_impl::notify_one()
} }
} }
void condition_impl::notify_all() void condition::notify_all()
{ {
unsigned signals = 0; unsigned signals = 0;
OSStatus lStatus = noErr; OSStatus lStatus = noErr;
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
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
@@ -530,7 +504,7 @@ void condition_impl::notify_all()
} }
} }
void condition_impl::enter_wait() void condition::enter_wait()
{ {
OSStatus lStatus = noErr; OSStatus lStatus = noErr;
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever); lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
@@ -540,7 +514,7 @@ void condition_impl::enter_wait()
assert(lStatus == noErr); assert(lStatus == noErr);
} }
void condition_impl::do_wait() void condition::do_wait()
{ {
OSStatus lStatus = noErr; OSStatus lStatus = noErr;
lStatus = safe_wait_on_semaphore(m_queue, kDurationForever); lStatus = safe_wait_on_semaphore(m_queue, kDurationForever);
@@ -549,8 +523,7 @@ void condition_impl::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, lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
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;
@@ -596,7 +569,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; int milliseconds;
to_duration(xt, milliseconds); to_duration(xt, milliseconds);
@@ -610,8 +583,7 @@ bool condition_impl::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, lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
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;
@@ -667,11 +639,8 @@ bool condition_impl::do_timed_wait(const xtime& xt)
} }
#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-2003 // Copyright (C) 2001
// 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,13 +14,11 @@
namespace boost { namespace boost {
lock_error::lock_error() lock_error::lock_error() : std::logic_error("thread lock error")
: std::logic_error("thread lock error")
{ {
} }
thread_resource_error::thread_resource_error() thread_resource_error::thread_resource_error() : std::runtime_error("thread resource error")
: std::runtime_error("thread resource error")
{ {
} }

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2001-2003 // Copyright (C) 2001
// 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,6 +16,7 @@
#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,6 +26,7 @@
# 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
@@ -32,15 +34,9 @@
namespace boost { namespace boost {
#if defined(BOOST_HAS_WINTHREADS) #if defined(BOOST_HAS_WINTHREADS)
mutex::mutex() : m_mutex(0) mutex::mutex()
{ {
try m_mutex = reinterpret_cast<void*>(new(std::nothrow) CRITICAL_SECTION);
{
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));
@@ -148,28 +144,14 @@ bool timed_mutex::do_trylock()
} }
bool timed_mutex::do_timedlock(const xtime& xt) bool timed_mutex::do_timedlock(const xtime& xt)
{
unsigned int res = 0;
for (;;)
{ {
int milliseconds; int milliseconds;
to_duration(xt, milliseconds); to_duration(xt, milliseconds);
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), unsigned int res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), milliseconds);
milliseconds);
assert(res != WAIT_FAILED && res != WAIT_ABANDONED); assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
if (res == WAIT_TIMEOUT)
{
xtime cur;
xtime_get(&cur, TIME_UTC);
if (xtime_cmp(xt, cur) > 0)
continue;
}
return res == WAIT_OBJECT_0; return res == WAIT_OBJECT_0;
} }
}
void timed_mutex::do_unlock() void timed_mutex::do_unlock()
{ {
@@ -432,8 +414,7 @@ mutex::~mutex()
void mutex::do_lock() void mutex::do_lock()
{ {
OSStatus lStatus = noErr; OSStatus lStatus = noErr;
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
m_mutex_mutex);
assert(lStatus == noErr); assert(lStatus == noErr);
} }
@@ -465,8 +446,7 @@ 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, lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
m_mutex_mutex);
assert(lStatus == noErr); assert(lStatus == noErr);
} }
@@ -506,8 +486,7 @@ 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, lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
m_mutex_mutex);
assert(lStatus == noErr); assert(lStatus == noErr);
} }

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2001-2003 // Copyright (C) 2001
// 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,7 +17,6 @@
# 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: public:
@@ -26,7 +25,6 @@ public:
private: private:
std::ostrstream& m_stream; std::ostrstream& m_stream;
}; };
# else # else
# include <sstream> # include <sstream>
# endif # endif
@@ -55,18 +53,15 @@ extern "C" {
static void do_once() static void do_once()
{ {
once_callback* cb = reinterpret_cast<once_callback*>( once_callback* cb = reinterpret_cast<once_callback*>(pthread_getspecific(key));
pthread_getspecific(key));
(**cb)(); (**cb)();
} }
} }
#elif defined(BOOST_HAS_MPTASKS) #elif defined(BOOST_HAS_MPTASKS)
namespace {
void *remote_call_proxy(void *pData) void *remote_call_proxy(void *pData)
{ {
std::pair<void (*)(), boost::once_flag *> &rData( std::pair<void (*)(), boost::once_flag *> &rData(*reinterpret_cast<std::pair<void (*)(), boost::once_flag *> *>(pData));
*reinterpret_cast<std::pair<void (*)(), boost::once_flag *> *>(pData));
if(*rData.second == false) if(*rData.second == false)
{ {
@@ -76,43 +71,6 @@ void *remote_call_proxy(void *pData)
return(NULL); return(NULL);
} }
}
#elif defined(BOOST_HAS_WINTHREADS)
namespace {
// The signature for InterlockedCompareExchange has changed with the
// addition of Win64 support. I can't determine any (consistent and
// portable) way of using conditional compilation to detect this, so
// we use these type wrappers. Unfortunately, the various vendors
// use different calling conventions and other signature anamolies,
// and thus have unique types as well. This is known to work on VC6,
// VC7, Borland 5.5.2 and gcc 3.2. Are there other signatures for
// other platforms?
inline LONG ice_wrapper(LONG (__stdcall *ice)(LONG*, LONG, LONG),
volatile LONG* dest, LONG exch, LONG cmp)
{
return (*ice)(const_cast<LONG*>(dest), exch, cmp);
}
inline LONG ice_wrapper(LONG (__stdcall *ice)(volatile LONG*, LONG, LONG),
volatile LONG* dest, LONG exch, LONG cmp)
{
return (*ice)(dest, exch, cmp);
}
inline LONG ice_wrapper(LPVOID (__stdcall *ice)(LPVOID*, LPVOID, LPVOID),
volatile LONG* dest, LONG exch, LONG cmp)
{
return (LONG)(*ice)((LPVOID*)dest, (LPVOID)exch, (LPVOID)cmp);
}
// The friendly form of InterlockedCompareExchange that defers
// according to the above function type wrappers.
inline LONG compare_exchange(volatile LPLONG dest, LONG exch, LONG cmp)
{
return ice_wrapper(&InterlockedCompareExchange, dest, exch, cmp);
}
}
#endif #endif
namespace boost { namespace boost {
@@ -120,19 +78,22 @@ namespace boost {
void call_once(void (*func)(), once_flag& flag) void call_once(void (*func)(), once_flag& flag)
{ {
#if defined(BOOST_HAS_WINTHREADS) #if defined(BOOST_HAS_WINTHREADS)
if (compare_exchange(&flag, 1, 1) == 0) once_flag tmp = flag;
// Memory barrier would be needed here to prevent race conditions on some platforms with
// partial ordering.
if (!tmp)
{ {
#if defined(BOOST_NO_STRINGSTREAM) #if defined(BOOST_NO_STRINGSTREAM)
std::ostrstream strm; std::ostrstream strm;
strm << "2AC1A572DB6944B0A65C38C4140AF2F4" << std::hex strm << "2AC1A572DB6944B0A65C38C4140AF2F4" << std::hex << GetCurrentProcessId() << &flag << std::ends;
<< 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 strm << "2AC1A572DB6944B0A65C38C4140AF2F4" << std::hex << GetCurrentProcessId() << &flag;
<< GetCurrentProcessId() << &flag; HANDLE mutex = CreateMutex(NULL, FALSE, strm.str().c_str());
HANDLE mutex = CreateMutexA(NULL, FALSE, strm.str().c_str());
#endif #endif
assert(mutex != NULL); assert(mutex != NULL);
@@ -140,10 +101,16 @@ void call_once(void (*func)(), once_flag& flag)
res = WaitForSingleObject(mutex, INFINITE); res = WaitForSingleObject(mutex, INFINITE);
assert(res == WAIT_OBJECT_0); assert(res == WAIT_OBJECT_0);
if (compare_exchange(&flag, 1, 1) == 0) tmp = flag;
if (!tmp)
{ {
func(); func();
InterlockedExchange(&flag, 1); tmp = true;
// Memory barrier would be needed here to prevent race conditions on some platforms
// with partial ordering.
flag = tmp;
} }
res = ReleaseMutex(mutex); res = ReleaseMutex(mutex);
@@ -158,8 +125,7 @@ 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 // all we do here is make a remote call to blue, as blue is not reentrant.
// 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-2003 // Copyright (C) 2001
// 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
@@ -31,15 +31,9 @@ namespace boost {
#if defined(BOOST_HAS_WINTHREADS) #if defined(BOOST_HAS_WINTHREADS)
recursive_mutex::recursive_mutex() recursive_mutex::recursive_mutex()
: m_mutex(0), m_count(0) : m_count(0)
{ {
try m_mutex = reinterpret_cast<void*>(new(std::nothrow) CRITICAL_SECTION);
{
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));
@@ -200,25 +194,14 @@ bool recursive_timed_mutex::do_trylock()
} }
bool recursive_timed_mutex::do_timedlock(const xtime& xt) bool recursive_timed_mutex::do_timedlock(const xtime& xt)
{
for (;;)
{ {
int milliseconds; int milliseconds;
to_duration(xt, milliseconds); to_duration(xt, milliseconds);
unsigned int res = 0; unsigned int res = 0;
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), milliseconds);
milliseconds);
assert(res != WAIT_FAILED && res != WAIT_ABANDONED); assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
if (res == WAIT_TIMEOUT)
{
xtime cur;
xtime_get(&cur, TIME_UTC);
if (xtime_cmp(xt, cur) > 0)
continue;
}
if (res == WAIT_OBJECT_0) if (res == WAIT_OBJECT_0)
{ {
if (++m_count > 1) if (++m_count > 1)
@@ -228,10 +211,8 @@ bool recursive_timed_mutex::do_timedlock(const xtime& xt)
} }
return true; return true;
} }
return false; return false;
} }
}
void recursive_timed_mutex::do_unlock() void recursive_timed_mutex::do_unlock()
{ {
@@ -805,8 +786,7 @@ 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, lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
m_mutex_mutex);
assert(lStatus == noErr); assert(lStatus == noErr);
if (++m_count > 1) if (++m_count > 1)
@@ -829,8 +809,7 @@ 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, lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
m_mutex_mutex);
assert(lStatus == noErr); assert(lStatus == noErr);
m_count = state; m_count = state;
@@ -858,8 +837,7 @@ 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, lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
m_mutex_mutex);
assert(lStatus == noErr); assert(lStatus == noErr);
if (++m_count > 1) if (++m_count > 1)
@@ -900,8 +878,7 @@ 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, lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
m_mutex_mutex);
assert(lStatus == noErr); assert(lStatus == noErr);
m_count = state; m_count = state;
@@ -929,8 +906,7 @@ 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, lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
m_mutex_mutex);
assert(lStatus == noErr); assert(lStatus == noErr);
if (++m_count > 1) if (++m_count > 1)
@@ -993,8 +969,7 @@ 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, lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
m_mutex_mutex);
assert(lStatus == noErr); assert(lStatus == noErr);
m_count = state; m_count = state;

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2001-2003 // Copyright (C) 2001
// 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
@@ -32,10 +32,7 @@ namespace {
class thread_param class thread_param
{ {
public: public:
thread_param(const boost::function0<void>& threadfunc) thread_param(const boost::function0<void>& threadfunc) : m_threadfunc(threadfunc), m_started(false) { }
: 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);
@@ -107,8 +104,7 @@ 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, m_thread = reinterpret_cast<void*>(_beginthreadex(0, 0, &thread_proxy, &param, 0, &m_id));
&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)
@@ -127,8 +123,8 @@ thread::thread(const function0<void>& threadfunc)
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, lStatus = MPCreateTask(&thread_proxy, &param, 0UL, m_pJoinQueueID, NULL, NULL,
NULL, 0UL, &m_pTaskID); 0UL, &m_pTaskID);
if(lStatus != noErr) if(lStatus != noErr)
{ {
lStatus = MPDeleteQueue(m_pJoinQueueID); lStatus = MPDeleteQueue(m_pJoinQueueID);
@@ -185,8 +181,7 @@ 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( OSStatus lStatus = threads::mac::detail::safe_wait_on_queue(m_pJoinQueueID, NULL, NULL, NULL, kDurationForever);
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
@@ -196,12 +191,14 @@ void thread::join()
void thread::sleep(const xtime& xt) void thread::sleep(const xtime& xt)
{ {
for (int foo=0; foo < 5; ++foo) for (;;)
{ {
#if defined(BOOST_HAS_WINTHREADS) #if defined(BOOST_HAS_WINTHREADS)
int milliseconds; int milliseconds;
to_duration(xt, milliseconds); to_duration(xt, milliseconds);
Sleep(milliseconds); Sleep(milliseconds);
xtime xt2;
xtime_get(&xt2, TIME_UTC);
#elif defined(BOOST_HAS_PTHREADS) #elif defined(BOOST_HAS_PTHREADS)
# if defined(BOOST_HAS_PTHREAD_DELAY_NP) # if defined(BOOST_HAS_PTHREAD_DELAY_NP)
timespec ts; timespec ts;
@@ -229,9 +226,7 @@ void thread::sleep(const xtime& xt)
AbsoluteTime sWakeTime(DurationToAbsolute(lMicroseconds)); AbsoluteTime sWakeTime(DurationToAbsolute(lMicroseconds));
threads::mac::detail::safe_delay_until(&sWakeTime); threads::mac::detail::safe_delay_until(&sWakeTime);
#endif #endif
xtime cur; if (xtime_cmp(xt, xt2) >= 0)
xtime_get(&cur, TIME_UTC);
if (xtime_cmp(xt, cur) <= 0)
return; return;
} }
} }
@@ -265,20 +260,17 @@ thread_group::thread_group()
thread_group::~thread_group() thread_group::~thread_group()
{ {
// We shouldn't have to scoped_lock here, since referencing this object // We shouldn't have to scoped_lock here, since referencing this object from another thread
// from another thread while we're deleting it in the current thread is // while we're deleting it in the current thread is going to lead to undefined behavior
// going to lead to undefined behavior any way. // any way.
for (std::list<thread*>::iterator it = m_threads.begin(); for (std::list<thread*>::iterator it = m_threads.begin(); it != m_threads.end(); ++it)
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 // No scoped_lock required here since the only "shared data" that's modified here occurs
// modified here occurs inside add_thread which does scoped_lock. // 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();
@@ -288,11 +280,9 @@ 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 // For now we'll simply ignore requests to add a thread object multiple times.
// times. Should we consider this an error and either throw or return an // Should we consider this an error and either throw or return an error value?
// error value? std::list<thread*>::iterator it = std::find(m_threads.begin(), m_threads.end(), thrd);
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);
@@ -302,11 +292,9 @@ 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 // For now we'll simply ignore requests to remove a thread object that's not in the group.
// not in the group. Should we consider this an error and either throw or // Should we consider this an error and either throw or return an error value?
// return an error value? std::list<thread*>::iterator it = std::find(m_threads.begin(), m_threads.end(), thrd);
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);
@@ -315,12 +303,9 @@ 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(); for (std::list<thread*>::iterator it = m_threads.begin(); it != m_threads.end(); ++it)
it != m_threads.end(); ++it)
{
(*it)->join(); (*it)->join();
} }
}
} // namespace boost } // namespace boost

View File

@@ -1,21 +1,10 @@
// Copyright (C) 2001-2003 // threadmon.cpp : Defines the entry point for the DLL application.
// 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> #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> #include <windows.h>
@@ -44,7 +33,7 @@ registered_handlers registry;
#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)
{ {
@@ -57,18 +46,13 @@ BOOL WINAPI DllMain(HANDLE /*module*/, DWORD reason, LPVOID)
case DLL_THREAD_DETACH: case DLL_THREAD_DETACH:
{ {
// Call the thread's exit handlers. // Call the thread's exit handlers.
exit_handlers* handlers = exit_handlers* handlers = static_cast<exit_handlers*>(TlsGetValue(key));
static_cast<exit_handlers*>(TlsGetValue(key));
if (handlers) if (handlers)
{ {
for (exit_handlers::iterator it = handlers->begin(); for (exit_handlers::iterator it = handlers->begin(); it != handlers->end(); ++it)
it != handlers->end(); ++it)
{
(*it)(); (*it)();
}
// Remove the exit handler list from the registered lists // Remove the exit handler list from the registered lists and then destroy it.
// and then destroy it.
EnterCriticalSection(&cs); EnterCriticalSection(&cs);
registry.erase(handlers); registry.erase(handlers);
LeaveCriticalSection(&cs); LeaveCriticalSection(&cs);
@@ -78,31 +62,22 @@ BOOL WINAPI DllMain(HANDLE /*module*/, DWORD reason, LPVOID)
break; break;
case DLL_PROCESS_DETACH: case DLL_PROCESS_DETACH:
{ {
// Assume the main thread is ending (call its handlers) and // Assume the main thread is ending (call its handlers) and all other threads
// all other threads have already ended. If this DLL is // have already ended. If this DLL is loaded and unloaded dynamically at run time
// loaded and unloaded dynamically at run time
// this is a bad assumption, but this is the best we can do. // this is a bad assumption, but this is the best we can do.
exit_handlers* handlers = exit_handlers* handlers = static_cast<exit_handlers*>(TlsGetValue(key));
static_cast<exit_handlers*>(TlsGetValue(key));
if (handlers) if (handlers)
{ {
for (exit_handlers::iterator it = handlers->begin(); for (exit_handlers::iterator it = handlers->begin(); it != handlers->end(); ++it)
it != handlers->end(); ++it)
{
(*it)(); (*it)();
} }
}
// Destroy any remaining exit handlers. Above we assumed // Destroy any remaining exit handlers. Above we assumed there'd only be the main
// there'd only be the main thread left, but to insure we // thread left, but to insure we don't get memory leaks we won't make that assumption
// don't get memory leaks we won't make that assumption
// here. // here.
EnterCriticalSection(&cs); EnterCriticalSection(&cs);
for (registered_handlers::iterator it = registry.begin(); for (registered_handlers::iterator it = registry.begin(); it != registry.end(); ++it)
it != registry.end(); ++it)
{
delete (*it); delete (*it);
}
LeaveCriticalSection(&cs); LeaveCriticalSection(&cs);
DeleteCriticalSection(&cs); DeleteCriticalSection(&cs);
TlsFree(key); TlsFree(key);
@@ -112,7 +87,7 @@ BOOL WINAPI DllMain(HANDLE /*module*/, DWORD reason, LPVOID)
return TRUE; 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 // Get the exit handlers for the current thread, creating and registering
// one if it doesn't exist. // one if it doesn't exist.
@@ -122,7 +97,7 @@ extern "C" BOOST_THREAD_DECL 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;
} }
@@ -154,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 // Attempt to add the handler to the list of exit handlers. If it's been previously
// previously added just report success and exit. // added just report success and exit.
try try
{ {
handlers->push_front(func); handlers->push_front(func);
@@ -168,6 +143,4 @@ extern "C" BOOST_THREAD_DECL 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

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

@@ -1,4 +1,4 @@
// Copyright (C) 2001-2003 // Copyright (C) 2001
// 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
@@ -24,8 +24,7 @@ inline void to_time(int milliseconds, boost::xtime& xt)
assert(res == boost::TIME_UTC); assert(res == boost::TIME_UTC);
xt.sec += (milliseconds / MILLISECONDS_PER_SECOND); xt.sec += (milliseconds / MILLISECONDS_PER_SECOND);
xt.nsec += ((milliseconds % MILLISECONDS_PER_SECOND) * xt.nsec += ((milliseconds % MILLISECONDS_PER_SECOND) * NANOSECONDS_PER_MILLISECOND);
NANOSECONDS_PER_MILLISECOND);
if (xt.nsec > static_cast<const int>(NANOSECONDS_PER_SECOND)) if (xt.nsec > static_cast<const int>(NANOSECONDS_PER_SECOND))
{ {
@@ -60,7 +59,7 @@ inline void to_timespec_duration(const boost::xtime& xt, timespec& ts)
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 (xt.sec < cur.sec || (xt.sec == cur.sec && xt.nsec < cur.nsec))
{ {
ts.tv_sec = 0; ts.tv_sec = 0;
ts.tv_nsec = 0; ts.tv_nsec = 0;
@@ -84,23 +83,18 @@ inline void to_timespec_duration(const boost::xtime& xt, timespec& ts)
} }
#endif #endif
inline void to_duration(boost::xtime xt, int& milliseconds) inline void to_duration(const 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 (xt.sec < cur.sec || (xt.sec == cur.sec && xt.nsec < cur.nsec))
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.sec;
}
milliseconds = (int)((xt.sec - cur.sec) * MILLISECONDS_PER_SECOND) +
(((xt.nsec - cur.nsec) + (NANOSECONDS_PER_MILLISECOND/2)) / (((xt.nsec - cur.nsec) + (NANOSECONDS_PER_MILLISECOND/2)) /
NANOSECONDS_PER_MILLISECOND); NANOSECONDS_PER_MILLISECOND);
} }
@@ -113,11 +107,11 @@ inline void to_microduration(const boost::xtime& xt, int& microseconds)
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_get(&cur, boost::TIME_UTC) <= 0) if (xt.sec < cur.sec || (xt.sec == cur.sec && xt.nsec < cur.nsec))
microseconds = 0; microseconds = 0;
else else
{ {
microseconds = (int)((xt.sec - cur.sec) * MICROSECONDS_PER_SECOND) + microseconds = ((xt.sec - cur.sec) * MICROSECONDS_PER_SECOND) +
(((xt.nsec - cur.nsec) + (NANOSECONDS_PER_MICROSECOND/2)) / (((xt.nsec - cur.nsec) + (NANOSECONDS_PER_MICROSECOND/2)) /
NANOSECONDS_PER_MICROSECOND); NANOSECONDS_PER_MICROSECOND);
} }

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2001-2003 // Copyright (C) 2001
// 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,7 +20,7 @@
#endif #endif
#if defined(BOOST_HAS_WINTHREADS) #if defined(BOOST_HAS_WINTHREADS)
#include <boost/thread/detail/threadmon.hpp> #include "threadmon.hpp"
#include <map> #include <map>
namespace { namespace {
typedef std::pair<void(*)(void*), void*> cleanup_info; typedef std::pair<void(*)(void*), void*> cleanup_info;
@@ -37,10 +37,8 @@ void init_cleanup_key()
void __cdecl cleanup() void __cdecl cleanup()
{ {
cleanup_handlers* handlers = static_cast<cleanup_handlers*>( cleanup_handlers* handlers = static_cast<cleanup_handlers*>(TlsGetValue(key));
TlsGetValue(key)); 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)
@@ -53,8 +51,7 @@ cleanup_handlers* get_handlers()
{ {
boost::call_once(&init_cleanup_key, once); boost::call_once(&init_cleanup_key, once);
cleanup_handlers* handlers = static_cast<cleanup_handlers*>( cleanup_handlers* handlers = static_cast<cleanup_handlers*>(TlsGetValue(key));
TlsGetValue(key));
if (!handlers) if (!handlers)
{ {
try try
@@ -94,8 +91,7 @@ cleanup_handlers* get_handlers()
{ {
boost::call_once(&init_cleanup_key, once); boost::call_once(&init_cleanup_key, once);
cleanup_handlers* handlers = reinterpret_cast<cleanup_handlers*>( cleanup_handlers* handlers = reinterpret_cast<cleanup_handlers*>(MPGetTaskStorageValue(key));
MPGetTaskStorageValue(key));
if (!handlers) if (!handlers)
{ {
try try
@@ -107,16 +103,14 @@ cleanup_handlers* get_handlers()
return 0; return 0;
} }
OSStatus lStatus = noErr; OSStatus lStatus = noErr;
lStatus = MPSetTaskStorageValue(key, lStatus = MPSetTaskStorageValue(key, reinterpret_cast<TaskStorageValue>(handlers));
reinterpret_cast<TaskStorageValue>(handlers));
assert(lStatus == noErr); assert(lStatus == noErr);
// TODO - create a generalized mechanism for registering thread exit // TODO - create a generalized mechanism for registering thread exit functions
// functions and use it here. // and use it here.
} }
return handlers; return handlers;
} }
} }
namespace boost { namespace boost {
@@ -126,12 +120,10 @@ namespace detail {
void thread_cleanup() void thread_cleanup()
{ {
cleanup_handlers* handlers = reinterpret_cast<cleanup_handlers*>( cleanup_handlers* handlers = reinterpret_cast<cleanup_handlers*>(MPGetTaskStorageValue(key));
MPGetTaskStorageValue(key));
if(handlers != NULL) if(handlers != NULL)
{ {
for (cleanup_handlers::iterator it = handlers->begin(); for (cleanup_handlers::iterator it = handlers->begin(); it != handlers->end(); ++it)
it != handlers->end(); ++it)
{ {
cleanup_info info = it->second; cleanup_info info = it->second;
if (info.second) if (info.second)
@@ -243,8 +235,7 @@ 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, OSStatus lStatus = MPSetTaskStorageValue(m_key, reinterpret_cast<TaskStorageValue>(value));
reinterpret_cast<TaskStorageValue>(value));
return(lStatus == noErr); return(lStatus == noErr);
} }
#endif #endif

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2001-2003 // Copyright (C) 2001
// 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
@@ -39,15 +39,14 @@ struct startup_time_info
if(s_ulUNIXBaseSeconds == 0UL) if(s_ulUNIXBaseSeconds == 0UL)
{ {
// calculate the number of seconds between the Mac OS base and the // calculate the number of seconds between the Mac OS base and the UNIX base
// UNIX base the first time we enter this constructor. // 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 // get the time in UpTime units twice, with the time in seconds in the middle.
// 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());
@@ -78,11 +77,8 @@ 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 = const boost::uint64_t TIMESPEC_TO_FILETIME_OFFSET = ((boost::uint64_t)27111902UL << 32) + (boost::uint64_t)3577643008UL;
((boost::uint64_t)27111902UL << 32) + xtp->sec = (int)((*(__int64*)&ft - TIMESPEC_TO_FILETIME_OFFSET) / 10000000);
(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;
@@ -100,16 +96,12 @@ 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, // the Mac OS does not have an MP-safe way of getting the date/time, so we use a
// so we use a delta from the startup time. We _could_ defer this // delta from the startup time. We _could_ defer this and use something that is
// and use something that is interrupt-safe, but this would be _SLOW_, // interrupt-safe, but this would be _SLOW_, and we need speed here.
// 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( uint64_t ullNanoseconds(force_cast<uint64_t>(AbsoluteDeltaToNanoseconds(sUpTime, detail::g_sStartupTimeInfo.m_sStartupAbsoluteTime)));
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,10 +1,12 @@
# (C) Copyright William E. Kempf 2001. Permission to copy, use, modify, sell # (C) Copyright William E. Kempf 2001. Permission to copy, use, modify, sell and
# and distribute this software is granted provided this copyright notice # distribute this software is granted provided this copyright notice appears
# appears in all copies. This software is provided "as is" without express or # in all copies. This software is provided "as is" without express or implied
# implied warranty, and with no claim as to its suitability for any purpose. # 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
@@ -21,31 +23,21 @@ subproject libs/thread/test ;
# Include threads.jam for Boost.Threads global build information. # Include threads.jam for Boost.Threads global build information.
# This greatly simplifies the Jam code needed to configure the build # This greatly simplifies the Jam code needed to configure the build
# for the various Win32 build types. # for the various Win32 build types.
SEARCH on threads.jam = $(BOOST_ROOT)/libs/thread/build ; SEARCH on <module@>threads.jam = $(BOOST_ROOT)/libs/thread/build ;
include threads.jam ; include <module@>threads.jam ;
# bring in rules for testing sources = test.cpp test_thread.cpp test_mutex.cpp test_condition.cpp test_tss.cpp test_once.cpp ;
SEARCH on testing.jam = $(BOOST_BUILD_PATH) ;
include testing.jam ;
{ #######################
template test # Declare the Boost.Threads unit test program test_thread.
## sources ##
: <template>thread_base unit-test test_thread
<dll>../build/boost_thread : $(sources)
<lib>../../test/build/boost_unit_test_framework <lib>../build/boost_thread
## requirements ## <lib>../../test/build/unit_test_framework
: $(threadmon)
## default build ## : <sysinclude>$(BOOST_ROOT)
: $(pthreads-win32)
<threading>multi
: debug release <runtime-link>static/dynamic
; ;
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 ]
;
}

20
test/test.cpp Normal file
View File

@@ -0,0 +1,20 @@
#include <boost/test/unit_test.hpp>
extern boost::unit_test_framework::test_suite* thread_tests();
extern boost::unit_test_framework::test_suite* mutex_tests();
extern boost::unit_test_framework::test_suite* condition_tests();
extern boost::unit_test_framework::test_suite* tss_tests();
extern boost::unit_test_framework::test_suite* once_tests();
boost::unit_test_framework::test_suite* init_unit_test_suite(int argc, char* argv[])
{
boost::unit_test_framework::test_suite* test = BOOST_TEST_SUITE("Boost.Threads test suite");
test->add(thread_tests());
test->add(mutex_tests());
test->add(condition_tests());
test->add(tss_tests());
test->add(once_tests());
return test;
}

Binary file not shown.

View File

@@ -1,22 +1,11 @@
// 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>
#include "util.inl" namespace
{
struct condition_test_data struct condition_test_data
{ {
condition_test_data() : notified(0), awoken(0) { } condition_test_data() : notified(0), awoken(0) { }
@@ -27,16 +16,27 @@ struct condition_test_data
int awoken; int awoken;
}; };
void condition_test_thread(condition_test_data* data) void condition_test_thread(void* param)
{ {
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);
while (!(data->notified > 0)) while (!(data->notified > 0))
data->condition.wait(lock); data->condition.wait(lock);
BOOST_CHECK(lock ? true : false); BOOST_CHECK(lock);
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 struct cond_predicate
{ {
cond_predicate(int& var, int val) : _var(var), _val(val) { } cond_predicate(int& var, int val) : _var(var), _val(val) { }
@@ -47,55 +47,58 @@ struct cond_predicate
int _val; int _val;
}; };
void condition_test_waits(condition_test_data* data) void condition_test_waits(void* param)
{ {
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);
// Test wait. // Test wait.
while (data->notified != 1) while (data->notified != 1)
data->condition.wait(lock); data->condition.wait(lock);
BOOST_CHECK(lock ? true : false); BOOST_CHECK(lock);
BOOST_CHECK_EQUAL(data->notified, 1); BOOST_CHECK_EQUAL(data->notified, 1);
data->awoken++; data->awoken++;
data->condition.notify_one(); data->condition.notify_one();
// Test predicate wait. // Test predicate wait.
data->condition.wait(lock, cond_predicate(data->notified, 2)); data->condition.wait(lock, cond_predicate(data->notified, 2));
BOOST_CHECK(lock ? true : false); BOOST_CHECK(lock);
BOOST_CHECK_EQUAL(data->notified, 2); BOOST_CHECK_EQUAL(data->notified, 2);
data->awoken++; data->awoken++;
data->condition.notify_one(); data->condition.notify_one();
// Test timed_wait. // Test timed_wait.
boost::xtime xt = delay(10); boost::xtime xt;
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), boost::TIME_UTC);
xt.nsec += 100000000;
while (data->notified != 3) while (data->notified != 3)
data->condition.timed_wait(lock, xt); data->condition.timed_wait(lock, xt);
BOOST_CHECK(lock ? true : false); BOOST_CHECK(lock);
BOOST_CHECK_EQUAL(data->notified, 3); BOOST_CHECK_EQUAL(data->notified, 3);
data->awoken++; data->awoken++;
data->condition.notify_one(); data->condition.notify_one();
// Test predicate timed_wait. // Test predicate timed_wait.
xt = delay(10); BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), boost::TIME_UTC);
cond_predicate pred(data->notified, 4); xt.sec += 2;
BOOST_CHECK(data->condition.timed_wait(lock, xt, pred)); BOOST_CHECK(data->condition.timed_wait(lock, xt, cond_predicate(data->notified, 4)));
BOOST_CHECK(lock ? true : false); BOOST_CHECK(lock);
BOOST_CHECK(pred());
BOOST_CHECK_EQUAL(data->notified, 4); BOOST_CHECK_EQUAL(data->notified, 4);
data->awoken++; data->awoken++;
data->condition.notify_one(); }
} }
void do_test_condition_notify_one() void test_condition_notify_one()
{ {
condition_test_data data; 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); boost::mutex::scoped_lock lock(data.mutex);
BOOST_CHECK(lock ? true : false); BOOST_CHECK(lock);
data.notified++; data.notified++;
data.condition.notify_one(); data.condition.notify_one();
} }
@@ -104,23 +107,18 @@ void do_test_condition_notify_one()
BOOST_CHECK_EQUAL(data.awoken, 1); BOOST_CHECK_EQUAL(data.awoken, 1);
} }
void test_condition_notify_one() void test_condition_notify_all()
{
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(bind(&condition_test_thread, &data)); threads.create_thread(thread_adapter(&condition_test_thread, &data));
{ {
boost::mutex::scoped_lock lock(data.mutex); boost::mutex::scoped_lock lock(data.mutex);
BOOST_CHECK(lock ? true : false); BOOST_CHECK(lock);
data.notified++; data.notified++;
data.condition.notify_all(); data.condition.notify_all();
} }
@@ -129,73 +127,61 @@ void do_test_condition_notify_all()
BOOST_CHECK_EQUAL(data.awoken, NUMTHREADS); BOOST_CHECK_EQUAL(data.awoken, NUMTHREADS);
} }
void test_condition_notify_all() 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_notify_all, 3);
}
void do_test_condition_waits()
{ {
condition_test_data data; 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::mutex::scoped_lock lock(data.mutex);
BOOST_CHECK(lock ? true : false); BOOST_CHECK(lock);
boost::thread::sleep(delay(1)); BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), boost::TIME_UTC);
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)
data.condition.wait(lock); data.condition.wait(lock);
BOOST_CHECK(lock ? true : false);
BOOST_CHECK_EQUAL(data.awoken, 1); BOOST_CHECK_EQUAL(data.awoken, 1);
boost::thread::sleep(delay(1)); BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), boost::TIME_UTC);
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)
data.condition.wait(lock); data.condition.wait(lock);
BOOST_CHECK(lock ? true : false);
BOOST_CHECK_EQUAL(data.awoken, 2); BOOST_CHECK_EQUAL(data.awoken, 2);
boost::thread::sleep(delay(1)); BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), boost::TIME_UTC);
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)
data.condition.wait(lock); data.condition.wait(lock);
BOOST_CHECK(lock ? true : false);
BOOST_CHECK_EQUAL(data.awoken, 3); BOOST_CHECK_EQUAL(data.awoken, 3);
boost::thread::sleep(delay(1));
data.notified++;
data.condition.notify_one();
while (data.awoken != 4)
data.condition.wait(lock);
BOOST_CHECK(lock ? true : false);
BOOST_CHECK_EQUAL(data.awoken, 4);
} }
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), boost::TIME_UTC);
xt.sec += 1;
boost::thread::sleep(xt);
data.notified++;
data.condition.notify_one();
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), 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() boost::unit_test_framework::test_suite* condition_tests()
{ {
// We should have already tested notify_one here, so boost::unit_test_framework::test_suite* test = BOOST_TEST_SUITE("Boost.Threads: condition test suite");
// 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");
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,14 +1,3 @@
// 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>
@@ -17,9 +6,6 @@
#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>
#define DEFAULT_EXECUTION_MONITOR_TYPE execution_monitor::use_sleep_only
#include "util.inl"
template <typename M> template <typename M>
struct test_lock struct test_lock
{ {
@@ -37,22 +23,24 @@ struct test_lock
BOOST_CHECK(!lock); BOOST_CHECK(!lock);
} }
lock_type lock(mutex); lock_type lock(mutex);
BOOST_CHECK(lock ? true : false); BOOST_CHECK(lock);
// Construct and initialize an xtime for a fast time out. // 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), 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);
// Test the lock and unlock methods. // Test the lock and unlock methods.
lock.unlock(); lock.unlock();
BOOST_CHECK(!lock); BOOST_CHECK(!lock);
lock.lock(); lock.lock();
BOOST_CHECK(lock ? true : false); BOOST_CHECK(lock);
} }
}; };
@@ -70,33 +58,35 @@ struct test_trylock
// Test the lock's constructors. // Test the lock's constructors.
{ {
try_lock_type lock(mutex); try_lock_type lock(mutex);
BOOST_CHECK(lock ? true : false); BOOST_CHECK(lock);
} }
{ {
try_lock_type lock(mutex, false); try_lock_type lock(mutex, false);
BOOST_CHECK(!lock); BOOST_CHECK(!lock);
} }
try_lock_type lock(mutex, true); try_lock_type lock(mutex, true);
BOOST_CHECK(lock ? true : false); BOOST_CHECK(lock);
// Construct and initialize an xtime for a fast time out. // 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), 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);
// Test the lock, unlock and trylock methods. // Test the lock, unlock and trylock methods.
lock.unlock(); lock.unlock();
BOOST_CHECK(!lock); BOOST_CHECK(!lock);
lock.lock(); lock.lock();
BOOST_CHECK(lock ? true : false); BOOST_CHECK(lock);
lock.unlock(); lock.unlock();
BOOST_CHECK(!lock); BOOST_CHECK(!lock);
BOOST_CHECK(lock.try_lock()); BOOST_CHECK(lock.try_lock());
BOOST_CHECK(lock ? true : false); BOOST_CHECK(lock);
} }
}; };
@@ -114,135 +104,81 @@ 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 = delay(0, 100); boost::xtime xt;
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), 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);
} }
{ {
timed_lock_type lock(mutex, false); timed_lock_type lock(mutex, false);
BOOST_CHECK(!lock); BOOST_CHECK(!lock);
} }
timed_lock_type lock(mutex, true); timed_lock_type lock(mutex, true);
BOOST_CHECK(lock ? true : false); BOOST_CHECK(lock);
// Construct and initialize an xtime for a fast time out. // 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), 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);
BOOST_CHECK(in_range(xt));
// Test the lock, unlock and timedlock methods. // Test the lock, unlock and timedlock methods.
lock.unlock(); lock.unlock();
BOOST_CHECK(!lock); BOOST_CHECK(!lock);
lock.lock(); lock.lock();
BOOST_CHECK(lock ? true : false); BOOST_CHECK(lock);
lock.unlock(); lock.unlock();
BOOST_CHECK(!lock); BOOST_CHECK(!lock);
xt = delay(0, 100); BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), boost::TIME_UTC);
xt.nsec += 100000000;
BOOST_CHECK(lock.timed_lock(xt)); BOOST_CHECK(lock.timed_lock(xt));
BOOST_CHECK(lock ? true : false);
} }
}; };
template <typename M> template <typename M>
struct test_recursive_lock struct test_recursive_lock
{ {
typedef M mutex_type; typedef M mutex;
typedef typename M::scoped_lock lock_type;
void operator()() void operator()()
{ {
mutex_type mx; mutex mx;
lock_type lock1(mx); mutex::scoped_lock lock1(mx);
lock_type lock2(mx); mutex::scoped_lock lock2(mx);
} }
}; };
void do_test_mutex() boost::unit_test_framework::test_suite* mutex_tests()
{ {
test_lock<boost::mutex>()(); boost::unit_test_framework::test_suite* test = BOOST_TEST_SUITE("Boost.Threads: mutex test suite");
}
void test_mutex() test->add(BOOST_TEST_CASE(test_lock<boost::mutex>()));
{
timed_test(&do_test_mutex, 3);
}
void do_test_try_mutex() test->add(BOOST_TEST_CASE(test_lock<boost::try_mutex>()));
{ test->add(BOOST_TEST_CASE(test_trylock<boost::try_mutex>()));
test_lock<boost::try_mutex>()();
test_trylock<boost::try_mutex>()();
}
void test_try_mutex() test->add(BOOST_TEST_CASE(test_lock<boost::timed_mutex>()));
{ test->add(BOOST_TEST_CASE(test_trylock<boost::timed_mutex>()));
timed_test(&do_test_try_mutex, 3); test->add(BOOST_TEST_CASE(test_timedlock<boost::timed_mutex>()));
}
void do_test_timed_mutex() test->add(BOOST_TEST_CASE(test_lock<boost::recursive_mutex>()));
{ test->add(BOOST_TEST_CASE(test_recursive_lock<boost::recursive_mutex>()));
test_lock<boost::timed_mutex>()();
test_trylock<boost::timed_mutex>()();
test_timedlock<boost::timed_mutex>()();
}
void test_timed_mutex() test->add(BOOST_TEST_CASE(test_lock<boost::recursive_try_mutex>()));
{ test->add(BOOST_TEST_CASE(test_trylock<boost::recursive_try_mutex>()));
timed_test(&do_test_timed_mutex, 3); test->add(BOOST_TEST_CASE(test_recursive_lock<boost::recursive_try_mutex>()));
}
void do_test_recursive_mutex() test->add(BOOST_TEST_CASE(test_lock<boost::recursive_timed_mutex>()));
{ test->add(BOOST_TEST_CASE(test_trylock<boost::recursive_timed_mutex>()));
test_lock<boost::recursive_mutex>()(); test->add(BOOST_TEST_CASE(test_timedlock<boost::recursive_timed_mutex>()));
test_recursive_lock<boost::recursive_mutex>()(); test->add(BOOST_TEST_CASE(test_recursive_lock<boost::recursive_timed_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_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()
{
test_lock<boost::recursive_timed_mutex>()();
test_trylock<boost::recursive_timed_mutex>()();
test_timedlock<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* test =
BOOST_TEST_SUITE("Boost.Threads: mutex test suite");
test->add(BOOST_TEST_CASE(&test_mutex));
test->add(BOOST_TEST_CASE(&test_try_mutex));
test->add(BOOST_TEST_CASE(&test_timed_mutex));
test->add(BOOST_TEST_CASE(&test_recursive_mutex));
test->add(BOOST_TEST_CASE(&test_recursive_try_mutex));
test->add(BOOST_TEST_CASE(&test_recursive_timed_mutex));
return test; return test;
} }

View File

@@ -1,21 +1,10 @@
// 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>
#include "util.inl" namespace
{
int once_value = 0; int once_value = 0;
boost::once_flag once = BOOST_ONCE_INIT; boost::once_flag once = BOOST_ONCE_INIT;
@@ -26,10 +15,11 @@ void init_once_value()
void test_once_thread() void test_once_thread()
{ {
boost::call_once(init_once_value, once); boost::call_once(&init_once_value, once);
}
} }
void do_test_once() void test_once()
{ {
const int NUMTHREADS=5; const int NUMTHREADS=5;
boost::thread_group threads; boost::thread_group threads;
@@ -39,17 +29,11 @@ void do_test_once()
BOOST_CHECK_EQUAL(once_value, 1); BOOST_CHECK_EQUAL(once_value, 1);
} }
void test_once() boost::unit_test_framework::test_suite* once_tests()
{ {
timed_test(&do_test_once, 2); boost::unit_test_framework::test_suite* test = BOOST_TEST_SUITE("Boost.Threads: once test suite");
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) test->add(BOOST_TEST_CASE(&test_once));
{
boost::unit_test_framework::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: once test suite");
test->add(BOOST_TEST_CASE(test_once));
return test; return test;
} }

View File

@@ -1,21 +1,23 @@
// 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>
#define DEFAULT_EXECUTION_MONITOR_TYPE execution_monitor::use_sleep_only namespace
#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), 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);
}
int test_value; int test_value;
@@ -24,24 +26,43 @@ void simple_thread()
test_value = 999; test_value = 999;
} }
void comparison_thread(boost::thread* parent) 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::thread thrd;
BOOST_TEST(thrd != *parent); BOOST_TEST(thrd != parent);
BOOST_TEST(thrd == boost::thread()); BOOST_TEST(thrd == boost::thread());
} }
}
void test_sleep() void test_sleep()
{ {
boost::xtime xt = delay(3); boost::xtime xt;
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), boost::TIME_UTC);
xt.sec += 5;
boost::thread::sleep(xt); boost::thread::sleep(xt);
// Ensure it's in a range instead of checking actual equality due to time // Insure it's in a range instead of checking actual equality due to time lapse
// lapse BOOST_CHECK(xtime_in_range(xt, -1, 1));
BOOST_CHECK(in_range(xt));
} }
void do_test_creation() void test_creation()
{ {
test_value = 0; test_value = 0;
boost::thread thrd(&simple_thread); boost::thread thrd(&simple_thread);
@@ -49,31 +70,20 @@ void do_test_creation()
BOOST_CHECK_EQUAL(test_value, 999); BOOST_CHECK_EQUAL(test_value, 999);
} }
void test_creation() void test_comparison()
{
timed_test(&do_test_creation, 1);
}
void do_test_comparison()
{ {
boost::thread self; boost::thread self;
boost::thread thrd(bind(&comparison_thread, &self)); boost::thread thrd(thread_adapter(&comparison_thread, self));
thrd.join(); thrd.join();
} }
void test_comparison() boost::unit_test_framework::test_suite* thread_tests()
{ {
timed_test(&do_test_comparison, 1); boost::unit_test_framework::test_suite* test = BOOST_TEST_SUITE("Boost.Threads: thread test suite");
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) test->add(BOOST_TEST_CASE(&test_sleep));
{ test->add(BOOST_TEST_CASE(&test_creation));
boost::unit_test_framework::test_suite* test = test->add(BOOST_TEST_CASE(&test_comparison));
BOOST_TEST_SUITE("Boost.Threads: thread test suite");
test->add(BOOST_TEST_CASE(test_sleep));
test->add(BOOST_TEST_CASE(test_creation));
test->add(BOOST_TEST_CASE(test_comparison));
return test; return test;
} }

View File

@@ -1,22 +1,11 @@
// 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>
#include "util.inl" namespace
{
boost::mutex tss_mutex; boost::mutex tss_mutex;
int tss_instances = 0; int tss_instances = 0;
@@ -48,8 +37,9 @@ void test_tss_thread()
++n; ++n;
} }
} }
}
void do_test_tss() void test_tss()
{ {
const int NUMTHREADS=5; const int NUMTHREADS=5;
boost::thread_group threads; boost::thread_group threads;
@@ -59,17 +49,11 @@ void do_test_tss()
BOOST_CHECK_EQUAL(tss_instances, 0); BOOST_CHECK_EQUAL(tss_instances, 0);
} }
void test_tss() boost::unit_test_framework::test_suite* tss_tests()
{ {
timed_test(&do_test_tss, 2); boost::unit_test_framework::test_suite* test = BOOST_TEST_SUITE("Boost.Threads: tss test suite");
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) test->add(BOOST_TEST_CASE(&test_tss));
{
boost::unit_test_framework::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: tss test suite");
test->add(BOOST_TEST_CASE(test_tss));
return test; return test;
} }

View File

@@ -1,68 +0,0 @@
// 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/test/unit_test.hpp>
void test_xtime_cmp()
{
boost::xtime xt1, xt2, cur;
BOOST_CHECK_EQUAL(
boost::xtime_get(&cur, boost::TIME_UTC),
static_cast<int>(boost::TIME_UTC));
xt1 = xt2 = cur;
xt1.nsec -= 1;
xt2.nsec += 1;
BOOST_CHECK(boost::xtime_cmp(xt1, cur) < 0);
BOOST_CHECK(boost::xtime_cmp(xt2, cur) > 0);
BOOST_CHECK(boost::xtime_cmp(cur, cur) == 0);
xt1 = xt2 = cur;
xt1.sec -= 1;
xt2.sec += 1;
BOOST_CHECK(boost::xtime_cmp(xt1, cur) < 0);
BOOST_CHECK(boost::xtime_cmp(xt2, cur) > 0);
BOOST_CHECK(boost::xtime_cmp(cur, cur) == 0);
}
void test_xtime_get()
{
boost::xtime orig, cur, old;
BOOST_CHECK_EQUAL(
boost::xtime_get(&orig,
boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
old = orig;
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(boost::xtime_cmp(cur, orig) >= 0);
BOOST_CHECK(boost::xtime_cmp(cur, old) >= 0);
old = cur;
}
}
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");
test->add(BOOST_TEST_CASE(&test_xtime_cmp));
test->add(BOOST_TEST_CASE(&test_xtime_get));
return test;
}

View File

@@ -1,162 +0,0 @@
// 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,49 +0,0 @@
# (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 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.
subproject libs/thread/tutorial ;
# Include threads.jam for Boost.Threads global build information.
# This greatly simplifies the Jam code needed to configure the build
# for the various Win32 build types.
SEARCH on <module@>threads.jam = $(BOOST_ROOT)/libs/thread/build ;
include <module@>threads.jam ;
{
template tutorial
## sources ##
: <template>thread_base
<dll>../build/boost_thread
## requirements ##
:
## default build ##
:
;
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,74 +0,0 @@
// 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();
}

View File

@@ -1,33 +0,0 @@
// 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,37 +0,0 @@
// 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>
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 result;
factorial f(10, result);
boost::thread thrd(f);
thrd.join();
std::cout << "10! = " << result << std::endl;
}

View File

@@ -1,37 +0,0 @@
// 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/ref.hpp>
#include <iostream>
class factorial
{
public:
factorial(int x) : x(x), res(0) { }
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()
{
factorial f(10);
boost::thread thrd(boost::ref(f));
thrd.join();
std::cout << "10! = " << f.result() << std::endl;
}

View File

@@ -1,41 +0,0 @@
// 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,24 +0,0 @@
// 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>
void helloworld()
{
std::cout << "Hello World!" << std::endl;
}
int main()
{
boost::thread thrd(&helloworld);
thrd.join();
}

View File

@@ -1,25 +0,0 @@
// 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>
struct helloworld
{
helloworld() { }
void operator()() { std::cout << "Hello World." << std::endl; }
};
int main()
{
boost::thread thrd(helloworld());
thrd.join();
}

View File

@@ -1,26 +0,0 @@
// 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>
struct helloworld
{
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("Bob"));
thrd.join();
}

View File

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

View File

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

View File

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