mirror of
https://github.com/boostorg/thread.git
synced 2026-02-03 09:42:16 +00:00
Compare commits
38 Commits
svn-branch
...
boost-1.31
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1d0f292908 | ||
|
|
3ef8e9f6a0 | ||
|
|
bd65d75841 | ||
|
|
515590495a | ||
|
|
7221bca909 | ||
|
|
ed64a8cd12 | ||
|
|
cbd30d22ff | ||
|
|
0c74dbd436 | ||
|
|
49356cc931 | ||
|
|
ceee6e8b17 | ||
|
|
61ab2754d2 | ||
|
|
2de3df61e8 | ||
|
|
b84d7aa06d | ||
|
|
ed48f900a3 | ||
|
|
d197a49707 | ||
|
|
b8ccaa3bf6 | ||
|
|
507a684b21 | ||
|
|
c969c9387a | ||
|
|
1709db4953 | ||
|
|
4d1c9ba316 | ||
|
|
45b0396355 | ||
|
|
1df2169e48 | ||
|
|
2c056b3621 | ||
|
|
680119006c | ||
|
|
c4ac4b7538 | ||
|
|
ff5d3b49ca | ||
|
|
e101c878f0 | ||
|
|
125193dcfa | ||
|
|
77efa9810d | ||
|
|
7f03d1917b | ||
|
|
55b4ca9350 | ||
|
|
7196a0f9d2 | ||
|
|
2caabde5ca | ||
|
|
137d7663c1 | ||
|
|
508b71a921 | ||
|
|
5d90820005 | ||
|
|
84727e90b1 | ||
|
|
9a1e3d3320 |
@@ -6,13 +6,6 @@
|
||||
#
|
||||
# Boost.Threads build Jamfile
|
||||
#
|
||||
# Declares the following targets:
|
||||
# 1. libboost_thread, a static link library.
|
||||
# 1a. On Win32 (when PTW32 is not defined), a dynamic link library
|
||||
# boost_threadmon, which must be used in conjunction with
|
||||
# libboost_thread. Note that this DLL *must* be used through static
|
||||
# linking to the import library. Dynamic loading will cause undefined
|
||||
# behavior.
|
||||
# Additional configuration variables used:
|
||||
# 1. PTW32 may be used on Win32 platforms to specify that the pthreads-win32
|
||||
# library should be used instead of "native" threads. This feature is
|
||||
@@ -29,46 +22,40 @@ subproject libs/thread/build ;
|
||||
# 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 = $(SUBDIR) ;
|
||||
include <module@>threads.jam ;
|
||||
import ./threads ;
|
||||
|
||||
template thread_libs
|
||||
## sources ##
|
||||
: <template>thread_base
|
||||
## requirements ##
|
||||
:
|
||||
## default build ##
|
||||
: debug release <runtime-link>static/dynamic
|
||||
;
|
||||
{
|
||||
template thread_libs
|
||||
## sources ##
|
||||
: <template>thread_base
|
||||
## requirements ##
|
||||
: <sysinclude>$(BOOST_ROOT)
|
||||
## 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 ;
|
||||
|
||||
#######################
|
||||
# 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 threadmon ;
|
||||
|
||||
#if $(NT) && ! $(PTW32)
|
||||
#{
|
||||
dll boost_thread
|
||||
: <template>thread_libs ../src/$(CPP_SOURCES).cpp
|
||||
: <define>BOOST_THREAD_BUILD_DLL=1
|
||||
<runtime-link>dynamic
|
||||
# the common names rule ensures that the library will
|
||||
# be named according to the rules used by the install
|
||||
# and auto-link features:
|
||||
common-variant-tag
|
||||
;
|
||||
#}
|
||||
#else
|
||||
#{
|
||||
# lib boost_thread
|
||||
# : <template>thread_libs ../src/$(CPP_SOURCES).cpp
|
||||
# ;
|
||||
#}
|
||||
|
||||
#######################
|
||||
# Stage the generated targets.
|
||||
stage bin-stage
|
||||
: <dll>boost_thread
|
||||
: #<tag><runtime-link-static>"s"
|
||||
<tag><debug>"d"
|
||||
: debug release
|
||||
;
|
||||
|
||||
#stage bin-stage
|
||||
# : <lib>boost_thread $(threadmon)
|
||||
# : <tag><runtime-link-static>"s"
|
||||
# <tag><debug>"d"
|
||||
# : debug release <runtime-link>static/dynamic
|
||||
#;
|
||||
install thread lib
|
||||
: <dll>boost_thread
|
||||
;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,26 @@
|
||||
import os ;
|
||||
|
||||
if [ os.name ] = NT
|
||||
{
|
||||
reqts = <link>shared:<define>BOOST_THREAD_BUILD_DLL=1 ;
|
||||
}
|
||||
else
|
||||
{
|
||||
# Declare the uses system library
|
||||
lib pthread : : <name>pthread ;
|
||||
usage = <library>pthread ;
|
||||
}
|
||||
|
||||
project boost/thread
|
||||
: source-location ../src
|
||||
: use-requirements <find-library>pthread
|
||||
: usage-requirements $(usage)
|
||||
: requirements $(reqts) <threading>multi
|
||||
: default-build <threading>multi
|
||||
;
|
||||
|
||||
CPP_SOURCES = condition mutex recursive_mutex thread tss xtime once exceptions ;
|
||||
CPP_SOURCES = condition mutex recursive_mutex thread tss xtime once
|
||||
exceptions threadmon ;
|
||||
|
||||
lib boost_thread : $(CPP_SOURCES).cpp ;
|
||||
lib boost_thread
|
||||
: $(CPP_SOURCES).cpp
|
||||
;
|
||||
|
||||
@@ -1,28 +1,29 @@
|
||||
# Do some OS-specific setup
|
||||
|
||||
threadmon = ;
|
||||
pthreads-win32 = ;
|
||||
|
||||
if $(NT)
|
||||
{
|
||||
if $(PTW32)
|
||||
{
|
||||
local install-path = $(PTW32[1]) ;
|
||||
local lib = $(PTW32[2]) ;
|
||||
pthreads-win32 =
|
||||
<define>BOOST_HAS_PTHREADS
|
||||
<define>PtW32NoCatchWarn
|
||||
<include>$(install-path)/pre-built/include
|
||||
<library-file>$(install-path)/pre-built/lib/$(lib)
|
||||
;
|
||||
}
|
||||
}
|
||||
pthreads-win32 = ;
|
||||
|
||||
template thread_base
|
||||
## sources ##
|
||||
:
|
||||
## requirements ##
|
||||
: <sysinclude>$(BOOST_ROOT) <threading>multi $(pthreads-win32)
|
||||
## default build ##
|
||||
:
|
||||
;
|
||||
if $(NT)
|
||||
{
|
||||
if $(PTW32)
|
||||
{
|
||||
local install-path = $(PTW32[1]) ;
|
||||
local lib = $(PTW32[2]) ;
|
||||
pthreads-win32 =
|
||||
<define>BOOST_HAS_PTHREADS
|
||||
<define>PtW32NoCatchWarn
|
||||
<include>$(install-path)/pre-built/include
|
||||
<library-file>$(install-path)/pre-built/lib/$(lib)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
template thread_base
|
||||
## sources ##
|
||||
:
|
||||
## requirements ##
|
||||
: <sysinclude>$(BOOST_ROOT) <threading>multi $(pthreads-win32)
|
||||
<borland><*><cxxflags>-w-8004
|
||||
## default build ##
|
||||
:
|
||||
;
|
||||
}
|
||||
@@ -27,8 +27,8 @@
|
||||
Win32 implementation, especially in regards to boost::condition, as well as
|
||||
a lot of explanation of POSIX behavior), Greg Colvin (lots of input on the design),
|
||||
Paul Mclachlan, Thomas Matelich and Iain Hanson (for help in trying to get the
|
||||
build to work on other platforms), and Kevin S. Van Horn (for several updates/corrections
|
||||
to the documentation).</p>
|
||||
build to work on other platforms), Kevin S. Van Horn (for several updates/corrections
|
||||
to the documentation), and Martin Johnson (shared library implementation).</p>
|
||||
<p>The documentation was written by William E. Kempf. Beman Dawes provided additional
|
||||
documentation material and editing.</p>
|
||||
<p>Discussions on the boost.org mailing list were essential in the development
|
||||
|
||||
@@ -28,7 +28,8 @@
|
||||
"http://www.acm.org/pubs/citations/journals/surveys/1983-15-1/p3-andrews/">
|
||||
http://www.acm.org/pubs/citations/journals/surveys/1983-15-1/p3-andrews/</a>
|
||||
<p>Good general background reading. Includes descriptions of Path Expressions,
|
||||
Message Passing, and Remote Procedure Call in addition to the basics.</p>
|
||||
Message Passing, and Remote Procedure Call in addition to the basics.
|
||||
Section 3.3 explains why semaphores are considered error prone.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -53,12 +54,28 @@
|
||||
from event queues and semaphores to critical regions and monitors."
|
||||
Includes analysis of why <i>events</i> are considered error-prone. Also
|
||||
noteworthy because of an introductory quotation from Christopher Alexander;
|
||||
Brinch Hansen was years ahead of others in recognizing pattern concepts
|
||||
Brinch Hansen was years ahead of others in recognizing that pattern concepts
|
||||
applied to software too.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="102" valign="top" align="left"><b>]<a name=
|
||||
<td width="102" valign="top" align="left"><b>[<a name="Brinch-Hansen-02">Brinch
|
||||
Hansen 02</a>]</b></td>
|
||||
<td width="645">
|
||||
Per Brinch Hansen, Ed., <i>The Origin of Concurrent Programming,
|
||||
from Semaphores to Remote Procedure Calls</i>, Springer-Verlag, 2002. ISBN
|
||||
0-387-95401-5.
|
||||
<a href="http://www.springer-ny.com/detail.tpl?isbn=0387954015">
|
||||
http://www.springer-ny.com/detail.tpl?isbn=0387954015</a><p>Nineteen of
|
||||
the original seminal papers by Dijkstra, Brinch Hansen, and Hoare, plus a
|
||||
current (2001) Overview by Brinch Hansen. Although expensive, it is hard
|
||||
to imagine anyone who is interested in understanding the underpinnings of
|
||||
any form of concurrent programming who would not want to own this book.
|
||||
May not be of interest for those who just want to use Boost.Threads and
|
||||
don't care about the design issues hidden behind the curtain.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="102" valign="top" align="left"><b>[<a name=
|
||||
"Butenhof-97">Butenhof 97</a>]</b></td>
|
||||
<td width="645">
|
||||
<p>David R. Butenhof, <cite>Programming with POSIX Threads</cite>, Addison-Wesley
|
||||
@@ -80,7 +97,8 @@
|
||||
"http://www.acm.org/classics/feb96/"> http://www.acm.org/classics/feb96/</a></p>
|
||||
<p>Hoare and Brinch Hansen's work on Monitors is the basis for reliable
|
||||
multithreading patterns. This is one of the most often referenced papers
|
||||
in all of computer science, and with good reason.</p>
|
||||
in all of computer science, and with good reason. It is included in [<a href="#Brinch-Hansen-02">Brinch
|
||||
Hansen 02</a>]</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -149,12 +167,10 @@
|
||||
be visible on printed copies of this document.</p>
|
||||
<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" -->
|
||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->19 July, 2003<!--webbot bot="Timestamp" endspan i-checksum="21111" -->
|
||||
</p>
|
||||
<p><i>© Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> and
|
||||
Beman Dawes 2001-2002. All Rights Reserved.</i></p>
|
||||
<a href="../../../people/beman_dawes.html">Beman Dawes</a> 2001-2003. All Rights Reserved.</i></p>
|
||||
<p>Permission to use, copy, modify, distribute and sell this software and its
|
||||
documentation for any purpose is hereby granted without fee, provided that the
|
||||
above copyright notice appear in all copies and that both that copyright notice
|
||||
@@ -162,4 +178,4 @@
|
||||
makes no representations about the suitability of this software for any purpose.
|
||||
It is provided "as is" without express or implied warranty.</p>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
@@ -61,10 +61,9 @@
|
||||
states <a href="definitions.html#state"> blocked</a> and <a href="definitions.html#state">ready</a>.
|
||||
Note that "waiting" is a synonym for blocked.</p>
|
||||
<h4><a name="class-condition-synopsis"></a>Class <code>condition</code> synopsis</h4>
|
||||
<pre>
|
||||
namespace boost
|
||||
<pre>namespace boost
|
||||
{
|
||||
class condition : private <a href="../../utility/utility.htm#Class noncopyable">boost::noncopyable</a> // Exposition only.
|
||||
class condition : private <a href="../../utility/utility.htm#Class_noncopyable">boost::noncopyable</a> // Exposition only.
|
||||
// Class condition meets the <a href="overview.html#non-copyable">NonCopyable</a> requirement.
|
||||
{
|
||||
public:
|
||||
@@ -86,22 +85,19 @@ namespace boost
|
||||
</pre>
|
||||
<h4><a name="class-condition-ctors"></a>Class <code>condition</code> constructors
|
||||
and destructor</h4>
|
||||
<pre>
|
||||
condition();
|
||||
<pre>condition();
|
||||
</pre>
|
||||
<dl class="function-semantics">
|
||||
<dt><b>Effects:</b> Constructs a <code>condition</code> object.</dt>
|
||||
</dl>
|
||||
<pre>
|
||||
~condition();
|
||||
<pre>~condition();
|
||||
</pre>
|
||||
<dl class="function-semantics">
|
||||
<dt><b>Effects:</b> Destroys <code>*this</code>.</dt>
|
||||
</dl>
|
||||
<h4><a name="class-condition-modifiers"></a>Class <code>condition</code> modifier
|
||||
functions</h4>
|
||||
<pre>
|
||||
void notify_one();
|
||||
<pre>void notify_one();
|
||||
</pre>
|
||||
<dl class="function-semantics">
|
||||
<dt><b>Effects:</b> If there is a thread waiting on <code>*this</code>, change
|
||||
@@ -111,16 +107,14 @@ void notify_one();
|
||||
thread must still acquire the mutex again (which occurs within the call to
|
||||
one of the <code>condition</code> object's wait functions).</dt>
|
||||
</dl>
|
||||
<pre>
|
||||
void notify_all();
|
||||
<pre>void notify_all();
|
||||
</pre>
|
||||
<dl class="function-semantics">
|
||||
<dt><b>Effects:</b> Change the state of all threads waiting on <code> *this</code>
|
||||
to ready. If there are no waiting threads, <code> notify_all()</code> has
|
||||
no effect.</dt>
|
||||
</dl>
|
||||
<pre>
|
||||
template <typename ScopedLock>
|
||||
<pre>template <typename ScopedLock>
|
||||
void wait(ScopedLock& lock);
|
||||
</pre>
|
||||
<dl class="function-semantics">
|
||||
@@ -138,8 +132,7 @@ template <typename ScopedLock>
|
||||
wake ups". The second version encapsulates this loop idiom internally
|
||||
and is generally the preferred method.</dt>
|
||||
</dl>
|
||||
<pre>
|
||||
Template<typename ScopedLock, typename Pr>
|
||||
<pre>Template<typename ScopedLock, typename Pr>
|
||||
void wait(ScopedLock& lock, Pr pred);
|
||||
</pre>
|
||||
<dl class="function-semantics">
|
||||
@@ -149,8 +142,7 @@ Template<typename ScopedLock, typename Pr>
|
||||
<dt><b>Throws:</b> <code><a href="exceptions.html#class-lock_error">lock_error</a></code>
|
||||
if <code>!lock.locked()</code></dt>
|
||||
</dl>
|
||||
<pre>
|
||||
template <typename ScopedLock>
|
||||
<pre>template <typename ScopedLock>
|
||||
bool timed_wait(ScopedLock& lock, const <a href="xtime.html">xtime</a>& XT);
|
||||
</pre>
|
||||
<dl class="function-semantics">
|
||||
@@ -171,16 +163,14 @@ template <typename ScopedLock>
|
||||
ups". The second version encapsulates this loop idiom internally and
|
||||
is generally the preferred method.</dt>
|
||||
</dl>
|
||||
<pre>
|
||||
Template<typename ScopedLock, typename Pr>
|
||||
<pre>Template<typename ScopedLock, typename Pr>
|
||||
bool timed_wait(ScopedLock& lock, const <a href="xtime.html">xtime</a>& XT, Pr pred);
|
||||
</pre>
|
||||
<dl class="function-semantics">
|
||||
<dt><b>Requires:</b> <code>ScopedLock</code> meets the <a href="lock_concept.html#ScopedLock">ScopedLock</a>
|
||||
requirements, return from <code>pred()</code> convertible to bool.</dt>
|
||||
<dt><b>Effects:</b> As if:<br>
|
||||
<pre>
|
||||
while (!pred())
|
||||
<pre>while (!pred())
|
||||
{
|
||||
if (!timed_wait(lock, XT))
|
||||
return false;
|
||||
@@ -196,8 +186,7 @@ return true;
|
||||
<h2><a name="examples"></a>Example(s)</h2>
|
||||
<p><a href="../example/condition.cpp">libs/thread/example/condition.cpp</a></p>
|
||||
<p>Typical output (dependent on scheduling policies) is:</p>
|
||||
<pre>
|
||||
sent: 0
|
||||
<pre>sent: 0
|
||||
sent: 1
|
||||
received: 0
|
||||
received: 1
|
||||
@@ -209,9 +198,7 @@ sent: 4
|
||||
received: 4
|
||||
</pre>
|
||||
<p>Revised
|
||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
||||
05 November, 2001
|
||||
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
|
||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->09 January, 2003<!--webbot bot="Timestamp" endspan i-checksum="38582" -->
|
||||
</p>
|
||||
<p><i>© Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
|
||||
All Rights Reserved.</i></p>
|
||||
@@ -222,4 +209,4 @@ received: 4
|
||||
makes no representations about the suitability of this software for any purpose.
|
||||
It is provided "as is" without express or implied warranty.</p>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
24
doc/faq.html
24
doc/faq.html
@@ -86,8 +86,7 @@
|
||||
"definitions.html#Thread-safe">thread-safe</a>. The following is a simple
|
||||
example of a class with copyable semantics and internal synchronization through
|
||||
a mutex member.</p>
|
||||
<pre>
|
||||
class counter
|
||||
<pre>class counter
|
||||
{
|
||||
public:
|
||||
// Doesn't need synchronization since there can be no references to *this
|
||||
@@ -145,8 +144,8 @@ private:
|
||||
a mutex member as mutable clearly documents the intended semantics.</p>
|
||||
<h2><a name="question7"></a>7. Why supply <a href="condition.html">condition variables</a>
|
||||
rather than <a href="rationale.html#Events">event variables</a>?</h2>
|
||||
<p>Condition variables result in user code much less prone to <a href=
|
||||
"definitions.html#Race condition">race conditions</a> than event variables.
|
||||
<p>Condition variables result in user code much less prone to
|
||||
<a href="definitions.html#definition-race-condition">race conditions</a> than event variables.
|
||||
See <a href="rationale.html#Events">Rationale</a> for analysis. Also see <a href="bibliography.html#Hoare-74">[Hoare
|
||||
74]</a> and <a href="bibliography.html#Schmidt-00">[Schmidt 00]</a>.</p>
|
||||
<h2><a name="question8"></a>8. Why isn't thread cancellation or termination
|
||||
@@ -164,12 +163,19 @@ private:
|
||||
by Darryl Green).</p>
|
||||
<h2><a name="question10"></a>10. Why has class semaphore disappeared?</h2>
|
||||
<p>Semaphore was removed as too error prone. The same effect can be achieved with
|
||||
greater safety by the combination of a mutex and a condition variable.</p>
|
||||
greater safety by the combination of a mutex and a condition variable.
|
||||
Dijkstra (the semaphore's inventor), Hoare, and Brinch Hansen all depreciated
|
||||
semaphores and advocated more structured alternatives. In a 1969 letter to
|
||||
Brinch Hansen, Wirth said "semaphores ... are not suitable for higher level
|
||||
languages." [<a href="bibliography.html#Andrews-83">Andrews-83]</a>
|
||||
summarizes typical errors as "omitting a <b>P</b> or a <b>V</b>, or accidentally
|
||||
coding a <b>P</b> on one semaphore and a <b>V </b>on on another", forgetting to
|
||||
include all references to shared objects in critical sections, and confusion
|
||||
caused by using the same primitive for "both condition synchronization and
|
||||
mutual exclusion".</p>
|
||||
<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" -->
|
||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->19 July, 2003<!--webbot bot="Timestamp" endspan i-checksum="21111" -->
|
||||
</p>
|
||||
<p><i>© Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
|
||||
All Rights Reserved.</i></p>
|
||||
@@ -180,4 +186,4 @@ private:
|
||||
makes no representations about the suitability of this software for any purpose.
|
||||
It is provided "as is" without express or implied warranty.</p>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
@@ -145,7 +145,7 @@
|
||||
<p>A Mutex object has two states: locked and unlocked. Mutex object state can
|
||||
only be determined by an object meeting the <a href="lock_concept.html#ScopedLock">ScopedLock</a>
|
||||
requirements and constructed for the Mutex object.</p>
|
||||
<p>A Mutex is <a href="../../utility/utility.htm#Class noncopyable">NonCopyable</a>.</p>
|
||||
<p>A Mutex is <a href="../../utility/utility.htm#Class_noncopyable">NonCopyable</a>.</p>
|
||||
<p>For a Mutex type M and an object m of that type, the following expressions
|
||||
must be well-formed and have the indicated effects.</p>
|
||||
<table summary="Mutex expressions" border="1" cellpadding="5">
|
||||
@@ -223,9 +223,7 @@
|
||||
</table>
|
||||
<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" -->
|
||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->09 January, 2003<!--webbot bot="Timestamp" endspan i-checksum="38582" -->
|
||||
</p>
|
||||
<p><i>© Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
|
||||
All Rights Reserved.</i></p>
|
||||
@@ -236,4 +234,4 @@
|
||||
makes no representations about the suitability of this software for any purpose.
|
||||
It is provided "as is" without express or implied warranty.</p>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
@@ -110,7 +110,8 @@
|
||||
<p><b>Warning:</b> Multithreaded programs such as those using <b> Boost.Threads</b>
|
||||
must link to <a href="definitions.html#Thread-safe"> thread-safe</a> versions
|
||||
of all runtime libraries used by the program, including the runtime library
|
||||
for the C++ Standard Library. Otherwise <a href="definitions.html#Race condition">race
|
||||
for the C++ Standard Library. Otherwise
|
||||
<a href="definitions.html#definition-race-condition">race
|
||||
conditions</a> will occur when multiple threads simultaneously execute runtime
|
||||
library functions for <i>new</i>, <i>delete</i>, or other language features
|
||||
which imply shared state.</p>
|
||||
@@ -135,7 +136,7 @@
|
||||
<p><b>Recommendation:</b> For the most portable, yet thread-safe code, use Boost
|
||||
replacements for the problem functions. See the <a href=
|
||||
"../../random/index.html">Boost Random Number Library</a> and <a href=
|
||||
"../../tokenizer/index.htm">Boost Tokenizer Library</a>.</p>
|
||||
"../../tokenizer/index.html">Boost Tokenizer Library</a>.</p>
|
||||
<h2><a name="common-gaurantees"></a>Common guarantees for all Boost.Threads components</h2>
|
||||
<h3><a name="exceptions"></a>Exceptions</h3>
|
||||
<p><b>Boost.Threads</b> destructors never throw exceptions. Unless otherwise specified,
|
||||
@@ -157,9 +158,7 @@
|
||||
as implementations are free to meet the NonCopyable requirement in other ways.</p>
|
||||
<hr>
|
||||
<p>Revised
|
||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
||||
05 November, 2001
|
||||
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
|
||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->09 January, 2003<!--webbot bot="Timestamp" endspan i-checksum="38582" -->
|
||||
</p>
|
||||
<p><i>© Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
|
||||
All Rights Reserved.</i></p>
|
||||
@@ -170,4 +169,4 @@
|
||||
makes no representations about the suitability of this software for any purpose.
|
||||
It is provided "as is" without express or implied warranty.</p>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
@@ -144,31 +144,27 @@
|
||||
appear to bear them out. To illustrate the analysis we'll first provide
|
||||
pseudo-code illustrating the six typical usage patterns of a thread object.</p>
|
||||
<h3>1. Simple creation of a thread.</h3>
|
||||
<pre>
|
||||
void foo()
|
||||
<pre>void foo()
|
||||
{
|
||||
create_thread(&bar);
|
||||
}
|
||||
</pre>
|
||||
<h3>2. Creation of a thread that's later joined.</h3>
|
||||
<pre>
|
||||
Void foo()
|
||||
<pre>Void foo()
|
||||
{
|
||||
thread = create_thread(&bar);
|
||||
join(thread);
|
||||
}
|
||||
</pre>
|
||||
<h3>3. Simple creation of several threads in a loop.</h3>
|
||||
<pre>
|
||||
Void foo()
|
||||
<pre>Void foo()
|
||||
{
|
||||
for (int i=0; i<NUM_THREADS; ++i)
|
||||
create_thread(&bar);
|
||||
}
|
||||
</pre>
|
||||
<h3>4. Creation of several threads in a loop which are later joined.</h3>
|
||||
<pre>
|
||||
Void foo()
|
||||
<pre>Void foo()
|
||||
{
|
||||
for (int i=0; i<NUM_THREADS; ++i)
|
||||
threads[i] = create_thread(&bar);
|
||||
@@ -177,16 +173,14 @@ Void foo()
|
||||
}
|
||||
</pre>
|
||||
<h3>5. Creation of a thread whose ownership is passed to another object/method.</h3>
|
||||
<pre>
|
||||
Void foo()
|
||||
<pre>Void foo()
|
||||
{
|
||||
thread = create_thread(&bar);
|
||||
manager.owns(thread);
|
||||
}
|
||||
</pre>
|
||||
<h3>6. Creation of a thread whose ownership is shared between multiple objects.</h3>
|
||||
<pre>
|
||||
Void foo()
|
||||
<pre>Void foo()
|
||||
{
|
||||
thread = create_thread(&bar);
|
||||
manager1.add(thread);
|
||||
@@ -211,8 +205,7 @@ Void foo()
|
||||
for any of the usage patterns there would be a good argument for choosing the
|
||||
other design. So we'll code all six usage patterns using both designs.</p>
|
||||
<h3>1.</h3>
|
||||
<pre>
|
||||
void foo()
|
||||
<pre>void foo()
|
||||
{
|
||||
thread thrd(&bar);
|
||||
}
|
||||
@@ -223,8 +216,7 @@ void foo()
|
||||
}
|
||||
</pre>
|
||||
<h3>2.</h3>
|
||||
<pre>
|
||||
void foo()
|
||||
<pre>void foo()
|
||||
{
|
||||
thread thrd(&bar);
|
||||
thrd.join();
|
||||
@@ -237,8 +229,7 @@ void foo()
|
||||
}
|
||||
</pre>
|
||||
<h3>3.</h3>
|
||||
<pre>
|
||||
void foo()
|
||||
<pre>void foo()
|
||||
{
|
||||
for (int i=0; i<NUM_THREADS; ++i)
|
||||
thread thrd(&bar);
|
||||
@@ -251,8 +242,7 @@ void foo()
|
||||
}
|
||||
</pre>
|
||||
<h3>4.</h3>
|
||||
<pre>
|
||||
void foo()
|
||||
<pre>void foo()
|
||||
{
|
||||
std::auto_ptr<thread> threads[NUM_THREADS];
|
||||
for (int i=0; i<NUM_THREADS; ++i)
|
||||
@@ -271,8 +261,7 @@ void foo()
|
||||
}
|
||||
</pre>
|
||||
<h3>5.</h3>
|
||||
<pre>
|
||||
void foo()
|
||||
<pre>void foo()
|
||||
{
|
||||
thread thrd* = new thread(&bar);
|
||||
manager.owns(thread);
|
||||
@@ -285,8 +274,7 @@ void foo()
|
||||
}
|
||||
</pre>
|
||||
<h3>6.</h3>
|
||||
<pre>
|
||||
void foo()
|
||||
<pre>void foo()
|
||||
{
|
||||
boost::shared_ptr<thread> thrd(new thread(&bar));
|
||||
manager1.add(thrd);
|
||||
@@ -308,8 +296,7 @@ void foo()
|
||||
the presence of operator new in user code, but this can be eliminated by proper
|
||||
design of higher level concepts, such as the boost::thread_group class that
|
||||
simplifies example (4) down to:</p>
|
||||
<pre>
|
||||
void foo()
|
||||
<pre>void foo()
|
||||
{
|
||||
thread_group threads;
|
||||
for (int i=0; i<NUM_THREADS; ++i)
|
||||
@@ -366,8 +353,7 @@ void foo()
|
||||
variables are a continuing source of errors, even after previous bad experiences
|
||||
caused them to be very careful in their use of event variables. Overt problems
|
||||
can be avoided, for example, by teaming the event variable with a mutex, but
|
||||
that may just convert a <a href=
|
||||
"definitions.html#Race condition">race condition</a> into another problem,
|
||||
that may just convert a <a href="definitions.html#definition-race-condition">race condition</a> into another problem,
|
||||
such as excessive resource use. One of the most distressing aspects of the experience
|
||||
reports is the claim that many defects are latent. That is, the programs appear
|
||||
to work correctly, but contain hidden timing dependencies which will cause them
|
||||
@@ -383,9 +369,7 @@ void foo()
|
||||
<p>[Rationale provided by Beman Dawes]</p>
|
||||
<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" -->
|
||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->09 January, 2003<!--webbot bot="Timestamp" endspan i-checksum="38582" -->
|
||||
</p>
|
||||
<p><i>© Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
|
||||
All Rights Reserved.</i></p>
|
||||
@@ -396,4 +380,4 @@ void foo()
|
||||
makes no representations about the suitability of this software for any purpose.
|
||||
It is provided "as is" without express or implied warranty.</p>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
@@ -85,10 +85,8 @@
|
||||
having first been called, the thread of execution continues until its initial
|
||||
function completes.</p>
|
||||
<h4><a name="class-thread-synopsis"></a>Class <code>thread</code> synopsis</h4>
|
||||
<pre>
|
||||
namespace boost {
|
||||
class thread : <a href=
|
||||
"../../utility/utility.htm#Class noncopyable">boost::noncopyable</a> // Exposition only.
|
||||
<pre>namespace boost {
|
||||
class thread : <a href="../../utility/utility.htm#Class_noncopyable">boost::noncopyable</a> // Exposition only.
|
||||
// Class thread meets the <a href=
|
||||
"overview.html#non-copyable">NonCopyable</a> requirement.
|
||||
{
|
||||
@@ -109,8 +107,7 @@ public:
|
||||
</pre>
|
||||
<h4><a name="class-thread-ctors"></a>Class <code>thread</code> constructors and
|
||||
destructor</h4>
|
||||
<pre>
|
||||
thread();
|
||||
<pre>thread();
|
||||
</pre>
|
||||
<dl class="function-semantics">
|
||||
<dt><b>Effects:</b> Constructs a <code>thread</code> object representing the
|
||||
@@ -118,8 +115,7 @@ thread();
|
||||
<dt><b>Postconditions:</b> <code>*this</code> is non-joinable.</dt>
|
||||
<dt><b>Danger:</b> <code>*this</code> is valid only within the current thread.</dt>
|
||||
</dl>
|
||||
<pre>
|
||||
thread(const <a href="../../function/index.html">boost::function0</a><void>& threadfunc);
|
||||
<pre>thread(const <a href="../../function/index.html">boost::function0</a><void>& threadfunc);
|
||||
</pre>
|
||||
<dl class="function-semantics">
|
||||
<dt><b>Effects:</b> Starts a new thread of execution and constructs a <code>thread</code>
|
||||
@@ -132,8 +128,7 @@ thread(const <a href="../../function/index.html">boost::function0</a><void>
|
||||
<dt><b>Throws:</b> <code>boost::thread_resource_error</code> if a new thread
|
||||
of execution cannot be started.</dt>
|
||||
</dl>
|
||||
<pre>
|
||||
~Thread();
|
||||
<pre>~Thread();
|
||||
</pre>
|
||||
<dl class="function-semantics">
|
||||
<dt><b>Effects:</b> Destroys <code>*this</code>. The actual thread of execution
|
||||
@@ -146,24 +141,21 @@ thread(const <a href="../../function/index.html">boost::function0</a><void>
|
||||
</dl>
|
||||
<h4><a name="class-thread-comparisons"></a>Class <code>thread</code> comparison
|
||||
functions</h4>
|
||||
<pre>
|
||||
bool operator==(const thread& rhs) const;
|
||||
<pre>bool operator==(const thread& rhs) const;
|
||||
</pre>
|
||||
<dl class="function-semantics">
|
||||
<dt><b>Requires:</b> The thread is non-terminated or <code>*this</code> is joinable.</dt>
|
||||
<dt><b>Returns:</b> <code>true</code> if <code>*this</code> and <code> rhs</code>
|
||||
represent the same thread of execution.</dt>
|
||||
</dl>
|
||||
<pre>
|
||||
bool operator!=(const thread& rhs) const;
|
||||
<pre>bool operator!=(const thread& rhs) const;
|
||||
</pre>
|
||||
<dl class="function-semantics">
|
||||
<dt><b>Requires:</b> The thread is non-terminated or <code>*this</code> is joinable.</dt>
|
||||
<dt><b>Returns:</b> <code>!(*this==rhs)</code>.</dt>
|
||||
</dl>
|
||||
<h4><a name="class-thread-modifiers"></a>Class <code>thread</code> modifier functions</h4>
|
||||
<pre>
|
||||
void join();
|
||||
<pre>void join();
|
||||
</pre>
|
||||
<dl class="function-semantics">
|
||||
<dt><b>Requires:</b> <code>*this</code> is joinable.</dt>
|
||||
@@ -176,15 +168,13 @@ void join();
|
||||
<a href="definitions.html#Deadlock"> deadlock</a>.</dt>
|
||||
</dl>
|
||||
<h4><a name="class-thread-statics"></a>Class <code>thread</code> static functions</h4>
|
||||
<pre>
|
||||
static void sleep(const <a href="xtime.html">xtime</a>& XT);
|
||||
<pre>static void sleep(const <a href="xtime.html">xtime</a>& XT);
|
||||
</pre>
|
||||
<dl class="function-semantics">
|
||||
<dt><b>Effects:</b> The current thread of execution blocks until <code> XT</code>
|
||||
is reached.</dt>
|
||||
</dl>
|
||||
<pre>
|
||||
static void yield();
|
||||
<pre>static void yield();
|
||||
</pre>
|
||||
<dl class="function-semantics">
|
||||
<dt><b>Effects:</b> The current thread of execution is placed in the "ready"
|
||||
@@ -200,10 +190,9 @@ static void yield();
|
||||
"definitions.html#thread-safe">thread-safe</a>, except destruction.</p>
|
||||
<h4><a name="class-thread_group-synopsis"></a>Class <code>thread_group</code>
|
||||
synopsis</h4>
|
||||
<pre>
|
||||
namespace boost {
|
||||
<pre>namespace boost {
|
||||
class thread_group : <a href=
|
||||
"../../utility/utility.htm#Class noncopyable">boost::noncopyable</a>
|
||||
"../../utility/utility.htm#Class_noncopyable">boost::noncopyable</a>
|
||||
{
|
||||
public:
|
||||
thread_group();
|
||||
@@ -218,14 +207,12 @@ namespace boost {
|
||||
</pre>
|
||||
<h4><a name="class-thread_group-ctors"></a>Class <code>thread_group</code> constructors
|
||||
and destructor</h4>
|
||||
<pre>
|
||||
thread_group();
|
||||
<pre>thread_group();
|
||||
</pre>
|
||||
<dl class="function-semantics">
|
||||
<dt><b>Effects:</b> Constructs an empty <code>thread_group</code> container.</dt>
|
||||
</dl>
|
||||
<pre>
|
||||
~thread_group();
|
||||
<pre>~thread_group();
|
||||
</pre>
|
||||
<dl class="function-semantics">
|
||||
<dt><b>Effects:</b> Destroys each contained thread object. Destroys <code>*this</code>.</dt>
|
||||
@@ -234,8 +221,7 @@ thread_group();
|
||||
</dl>
|
||||
<h4><a name="class-thread_group-modifiers"></a>Class <code>thread_group</code>
|
||||
modifier functions</h4>
|
||||
<pre>
|
||||
thread* create_thread(const boost::function0<void>& threadfunc);
|
||||
<pre>thread* create_thread(const boost::function0<void>& threadfunc);
|
||||
</pre>
|
||||
<dl class="function-semantics">
|
||||
<dt><b>Effects:</b> Creates a new <tt>thread</tt> object that executes <tt>threadfunc</tt>
|
||||
@@ -243,16 +229,14 @@ thread* create_thread(const boost::function0<void>& threadfunc);
|
||||
<tt>thread</tt> objects.</dt>
|
||||
<dt><b>Returns:</b> Pointer to the newly created thread.</dt>
|
||||
</dl>
|
||||
<pre>
|
||||
void add_thread(thread* thrd);
|
||||
<pre>void add_thread(thread* thrd);
|
||||
</pre>
|
||||
<dl class="function-semantics">
|
||||
<dt><b>Effects:</b> Adds <tt>thrd</tt> to the <tt>thread_group</tt> object's
|
||||
list of managed <tt>thread</tt> objects. The <tt>thrd</tt> object must have
|
||||
been allocated via operator new and will be deleted when the group is destroyed.</dt>
|
||||
</dl>
|
||||
<pre>
|
||||
Void remove_thread(thread* thrd);
|
||||
<pre>Void remove_thread(thread* thrd);
|
||||
</pre>
|
||||
<dl class="function-semantics">
|
||||
<dt><b>Effects:</b> Removes <code>*this</code>'s list of managed <tt>thread</tt>
|
||||
@@ -260,16 +244,14 @@ Void remove_thread(thread* thrd);
|
||||
<dt><b>Throws:</b> ? if <tt>thrd</tt> is not it <code>*this</code>'s list
|
||||
of managed <tt>thread</tt> objects.</dt>
|
||||
</dl>
|
||||
<pre>
|
||||
Void join_all();
|
||||
<pre>Void join_all();
|
||||
</pre>
|
||||
<dl class="function-semantics">
|
||||
<dt><b>Effects:</b> Calls <code>join()</code> on each of the managed <tt>thread</tt>
|
||||
objects.</dt>
|
||||
</dl>
|
||||
<h2><a name="functions"></a>Functions</h2>
|
||||
<pre>
|
||||
<a name="function-spec"></a>{{function}}
|
||||
<pre><a name="function-spec"></a>{{function}}
|
||||
</pre>
|
||||
<dl class="function-semantics">
|
||||
<dt><b>Requires:</b> {{text}}</dt>
|
||||
@@ -286,15 +268,13 @@ Void join_all();
|
||||
<h3><a name="example-thread"></a>Simple usage of <code>boost::thread</code></h3>
|
||||
<p><a href="../example/thread.cpp">libs/thread/example/thread.cpp</a></p>
|
||||
<p>The output is:</p>
|
||||
<pre>
|
||||
setting alarm for 5 seconds...
|
||||
<pre>setting alarm for 5 seconds...
|
||||
alarm sounded...
|
||||
</pre>
|
||||
<h3><a name="example-thread_group"></a>Simple usage of <code>boost::thread_group</code></h3>
|
||||
<p><a href="../example/thread_group.cpp">libs/thread/example/thread_group.cpp</a></p>
|
||||
<p>The output is:</p>
|
||||
<pre>
|
||||
count = 1
|
||||
<pre>count = 1
|
||||
count = 2
|
||||
count = 3
|
||||
count = 4
|
||||
@@ -307,9 +287,7 @@ count = 10
|
||||
</pre>
|
||||
<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" -->
|
||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->09 January, 2003<!--webbot bot="Timestamp" endspan i-checksum="38582" -->
|
||||
</p>
|
||||
<p><i>© Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
|
||||
All Rights Reserved.</i></p>
|
||||
@@ -320,4 +298,4 @@ count = 10
|
||||
makes no representations about the suitability of this software for any purpose.
|
||||
It is provided "as is" without express or implied warranty.</p>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
@@ -1,7 +1,19 @@
|
||||
# (C) Copyright William E. Kempf 2001. Permission to copy, use, modify, sell and
|
||||
# distribute this software is granted provided this copyright notice appears
|
||||
# in all copies. This software is provided "as is" without express or implied
|
||||
# warranty, and with no claim as to its suitability for any purpose.
|
||||
# (C) Copyright William E. Kempf 2001. Permission to copy, use, modify, sell
|
||||
# and distribute this software is granted provided this copyright notice
|
||||
# appears in all copies. This software is provided "as is" without express or
|
||||
# implied warranty, and with no claim as to its suitability for any purpose.
|
||||
#
|
||||
# Boost.Threads 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/example ;
|
||||
@@ -9,28 +21,28 @@ subproject libs/thread/example ;
|
||||
# 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 ;
|
||||
import ../build/threads ;
|
||||
|
||||
template example
|
||||
## sources ##
|
||||
: <template>thread_base
|
||||
<dll>../build/boost_thread
|
||||
$(threadmon)
|
||||
## requirements ##
|
||||
:
|
||||
## default build ##
|
||||
: release <runtime-link>dynamic
|
||||
;
|
||||
{
|
||||
template example
|
||||
## sources ##
|
||||
: <template>thread_base
|
||||
<dll>../build/boost_thread
|
||||
## requirements ##
|
||||
:
|
||||
## default build ##
|
||||
:
|
||||
;
|
||||
|
||||
exe monitor : <template>example monitor.cpp ;
|
||||
exe starvephil : <template>example starvephil.cpp ;
|
||||
exe tennis : <template>example tennis.cpp ;
|
||||
exe condition : <template>example condition.cpp ;
|
||||
exe mutex : <template>example mutex.cpp ;
|
||||
exe once : <template>example once.cpp ;
|
||||
exe recursive_mutex : <template>example recursive_mutex.cpp ;
|
||||
exe thread : <template>example thread.cpp ;
|
||||
exe thread_group : <template>example thread_group.cpp ;
|
||||
exe tss : <template>example tss.cpp ;
|
||||
exe xtime : <template>example xtime.cpp ;
|
||||
exe monitor : <template>example monitor.cpp ;
|
||||
exe starvephil : <template>example starvephil.cpp ;
|
||||
exe tennis : <template>example tennis.cpp ;
|
||||
exe condition : <template>example condition.cpp ;
|
||||
exe mutex : <template>example mutex.cpp ;
|
||||
exe once : <template>example once.cpp ;
|
||||
exe recursive_mutex : <template>example recursive_mutex.cpp ;
|
||||
exe thread : <template>example thread.cpp ;
|
||||
exe thread_group : <template>example thread_group.cpp ;
|
||||
exe tss : <template>example tss.cpp ;
|
||||
exe xtime : <template>example xtime.cpp ;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <boost/utility.hpp>
|
||||
@@ -43,9 +54,9 @@ bounded_buffer buf(2);
|
||||
void sender() {
|
||||
int n = 0;
|
||||
while (n < 100) {
|
||||
buf.send(n);
|
||||
std::cout << "sent: " << n << std::endl;
|
||||
++n;
|
||||
buf.send(n);
|
||||
std::cout << "sent: " << n << std::endl;
|
||||
++n;
|
||||
}
|
||||
buf.send(-1);
|
||||
}
|
||||
@@ -53,8 +64,8 @@ void sender() {
|
||||
void receiver() {
|
||||
int n;
|
||||
do {
|
||||
n = buf.receive();
|
||||
std::cout << "received: " << n << std::endl;
|
||||
n = buf.receive();
|
||||
std::cout << "received: " << n << std::endl;
|
||||
} while (n != -1); // -1 indicates end of buffer
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <boost/thread/condition.hpp>
|
||||
@@ -6,9 +17,11 @@
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
namespace {
|
||||
const int ITERS = 100;
|
||||
boost::mutex io_mutex;
|
||||
}
|
||||
|
||||
const int ITERS = 100;
|
||||
boost::mutex io_mutex;
|
||||
|
||||
} // namespace
|
||||
|
||||
template <typename M>
|
||||
class buffer_t
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <iostream>
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/once.hpp>
|
||||
#include <cassert>
|
||||
@@ -12,14 +23,14 @@ void init()
|
||||
|
||||
void thread_proc()
|
||||
{
|
||||
boost::call_once(&init, once);
|
||||
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);
|
||||
boost::thread_group threads;
|
||||
for (int i=0; i<5; ++i)
|
||||
threads.create_thread(&thread_proc);
|
||||
threads.join_all();
|
||||
assert(value == 1);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <iostream>
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/condition.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
@@ -5,9 +16,10 @@
|
||||
#include <iostream>
|
||||
#include <time.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
boost::mutex iomx;
|
||||
namespace {
|
||||
|
||||
boost::mutex iomx;
|
||||
|
||||
}
|
||||
|
||||
class canteen
|
||||
@@ -39,8 +51,9 @@ public:
|
||||
boost::mutex::scoped_lock lock(m_mutex);
|
||||
{
|
||||
boost::mutex::scoped_lock lock(iomx);
|
||||
std::cout << "(" << clock() <<
|
||||
") Chef: ouch ... make room ... this dish is very hot ..." << std::endl;
|
||||
std::cout << "(" << clock()
|
||||
<< ") Chef: ouch ... make room ... this dish is "
|
||||
<< "very hot ..." << std::endl;
|
||||
}
|
||||
boost::xtime xt;
|
||||
boost::xtime_get(&xt, boost::TIME_UTC);
|
||||
@@ -84,7 +97,7 @@ void chef()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(iomx);
|
||||
std::cout << "(" << clock() << ") Chef: " << chickens
|
||||
<< " chickens, ready-to-go ..." << std::endl;
|
||||
<< " chickens, ready-to-go ..." << std::endl;
|
||||
}
|
||||
g_canteen.put(chickens);
|
||||
}
|
||||
@@ -96,7 +109,8 @@ struct phil
|
||||
void run() {
|
||||
{
|
||||
boost::mutex::scoped_lock lock(iomx);
|
||||
std::cout << "(" << clock() << ") Phil" << m_id << ": starting ..." << std::endl;
|
||||
std::cout << "(" << clock() << ") Phil" << m_id
|
||||
<< ": starting ..." << std::endl;
|
||||
}
|
||||
for (;;)
|
||||
{
|
||||
@@ -110,13 +124,13 @@ struct phil
|
||||
{
|
||||
boost::mutex::scoped_lock lock(iomx);
|
||||
std::cout << "(" << clock() << ") Phil" << m_id
|
||||
<< ": gotta eat ..." << std::endl;
|
||||
<< ": gotta eat ..." << std::endl;
|
||||
}
|
||||
g_canteen.get(m_id);
|
||||
{
|
||||
boost::mutex::scoped_lock lock(iomx);
|
||||
std::cout << "(" << clock() << ") Phil" << m_id
|
||||
<< ": mmm ... that's good ..." << std::endl;
|
||||
<< ": mmm ... that's good ..." << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -129,7 +143,10 @@ struct phil
|
||||
|
||||
struct thread_adapt
|
||||
{
|
||||
thread_adapt(void (*func)(void*), void* param) : _func(func), _param(param) { }
|
||||
thread_adapt(void (*func)(void*), void* param)
|
||||
: _func(func), _param(param)
|
||||
{
|
||||
}
|
||||
int operator()() const
|
||||
{
|
||||
_func(_param);
|
||||
@@ -143,7 +160,10 @@ struct thread_adapt
|
||||
class thread_adapter
|
||||
{
|
||||
public:
|
||||
thread_adapter(void (*func)(void*), void* param) : _func(func), _param(param) { }
|
||||
thread_adapter(void (*func)(void*), void* param)
|
||||
: _func(func), _param(param)
|
||||
{
|
||||
}
|
||||
void operator()() const { _func(_param); }
|
||||
private:
|
||||
void (*_func)(void*);
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/condition.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
@@ -49,7 +60,8 @@ void player(void* param)
|
||||
{
|
||||
cond.wait(lock);
|
||||
if (state == other)
|
||||
std::cout << "---" << player_name(active) << ": Spurious wakeup!" << std::endl;
|
||||
std::cout << "---" << player_name(active)
|
||||
<< ": Spurious wakeup!" << std::endl;
|
||||
} while (state == other);
|
||||
}
|
||||
|
||||
@@ -60,7 +72,10 @@ void player(void* param)
|
||||
|
||||
struct thread_adapt
|
||||
{
|
||||
thread_adapt(void (*func)(void*), void* param) : _func(func), _param(param) { }
|
||||
thread_adapt(void (*func)(void*), void* param)
|
||||
: _func(func), _param(param)
|
||||
{
|
||||
}
|
||||
int operator()() const
|
||||
{
|
||||
_func(_param);
|
||||
@@ -74,7 +89,10 @@ struct thread_adapt
|
||||
class thread_adapter
|
||||
{
|
||||
public:
|
||||
thread_adapter(void (*func)(void*), void* param) : _func(func), _param(param) { }
|
||||
thread_adapter(void (*func)(void*), void* param)
|
||||
: _func(func), _param(param)
|
||||
{
|
||||
}
|
||||
void operator()() const { _func(_param); }
|
||||
private:
|
||||
void (*_func)(void*);
|
||||
|
||||
@@ -1,29 +1,40 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/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;
|
||||
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);
|
||||
boost::thread::sleep(xt);
|
||||
|
||||
std::cout << "alarm sounded..." << std::endl;
|
||||
}
|
||||
std::cout << "alarm sounded..." << std::endl;
|
||||
}
|
||||
|
||||
int m_secs;
|
||||
int m_secs;
|
||||
};
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int secs = 5;
|
||||
std::cout << "setting alarm for 5 seconds..." << std::endl;
|
||||
thread_alarm alarm(secs);
|
||||
boost::thread thrd(alarm);
|
||||
thrd.join();
|
||||
int secs = 5;
|
||||
std::cout << "setting alarm for 5 seconds..." << std::endl;
|
||||
thread_alarm alarm(secs);
|
||||
boost::thread thrd(alarm);
|
||||
thrd.join();
|
||||
}
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <iostream>
|
||||
|
||||
@@ -6,14 +17,14 @@ boost::mutex mutex;
|
||||
|
||||
void increment_count()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
std::cout << "count = " << ++count << std::endl;
|
||||
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();
|
||||
boost::thread_group threads;
|
||||
for (int i = 0; i < 10; ++i)
|
||||
threads.create_thread(&increment_count);
|
||||
threads.join_all();
|
||||
}
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/tss.hpp>
|
||||
#include <cassert>
|
||||
@@ -6,25 +17,25 @@ boost::thread_specific_ptr<int> value;
|
||||
|
||||
void increment()
|
||||
{
|
||||
int* p = value.get();
|
||||
++*p;
|
||||
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);
|
||||
}
|
||||
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();
|
||||
boost::thread_group threads;
|
||||
for (int i=0; i<5; ++i)
|
||||
threads.create_thread(&thread_proc);
|
||||
threads.join_all();
|
||||
}
|
||||
|
||||
@@ -1,10 +1,21 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/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
|
||||
boost::xtime xt;
|
||||
boost::xtime_get(&xt, boost::TIME_UTC);
|
||||
xt.sec += 1;
|
||||
boost::thread::sleep(xt); // Sleep for 1 second
|
||||
}
|
||||
|
||||
24
include/boost/thread.hpp
Normal file
24
include/boost/thread.hpp
Normal file
@@ -0,0 +1,24 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#if !defined(BOOST_THREAD_WEK01082003_HPP)
|
||||
#define BOOST_THREAD_WEK01082003_HPP
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/condition.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/once.hpp>
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
#include <boost/thread/tss.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
|
||||
#endif
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2001
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
@@ -13,9 +13,9 @@
|
||||
#define BOOST_CONDITION_WEK070601_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifndef BOOST_HAS_THREADS
|
||||
# error Thread support is unavailable!
|
||||
#endif
|
||||
|
||||
// insist on threading support being available:
|
||||
#include <boost/config/requires_threads.hpp>
|
||||
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/utility.hpp>
|
||||
@@ -143,9 +143,9 @@ private:
|
||||
typedef detail::thread::lock_ops<M>
|
||||
#if defined(__HP_aCC) && __HP_aCC <= 33900 && !defined(BOOST_STRICT_CONFIG)
|
||||
# define lock_ops lock_ops_ // HP confuses lock_ops witht the template
|
||||
#endif
|
||||
#endif
|
||||
lock_ops;
|
||||
|
||||
|
||||
typename lock_ops::lock_state state;
|
||||
lock_ops::unlock(mutex, state);
|
||||
|
||||
@@ -169,9 +169,9 @@ private:
|
||||
typedef detail::thread::lock_ops<M>
|
||||
#if defined(__HP_aCC) && __HP_aCC <= 33900 && !defined(BOOST_STRICT_CONFIG)
|
||||
# define lock_ops lock_ops_ // HP confuses lock_ops witht the template
|
||||
#endif
|
||||
#endif
|
||||
lock_ops;
|
||||
|
||||
|
||||
typename lock_ops::lock_state state;
|
||||
lock_ops::unlock(mutex, state);
|
||||
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#ifndef BOOST_THREAD_CONFIG_WEK01032003_HPP
|
||||
#define BOOST_THREAD_CONFIG_WEK01032003_HPP
|
||||
|
||||
@@ -11,4 +22,23 @@
|
||||
# define BOOST_THREAD_DECL
|
||||
#endif // BOOST_THREAD_SHARED_LIB
|
||||
|
||||
//
|
||||
// Automatically link to the correct build variant where possible.
|
||||
//
|
||||
#if !defined(BOOST_ALL_NO_LIB) && !defined(BOOST_THREAD_NO_LIB) && !defined(BOOST_THREAD_BUILD_DLL)
|
||||
//
|
||||
// Set the name of our library, this will get undef'ed by auto_link.hpp
|
||||
// once it's done with it:
|
||||
//
|
||||
#define BOOST_LIB_NAME boost_thread
|
||||
//
|
||||
// If we're importing code from a dll, then tell auto_link.hpp about it:
|
||||
//
|
||||
# define BOOST_DYN_LINK
|
||||
//
|
||||
// And include the header that does the work:
|
||||
//
|
||||
#include <boost/config/auto_link.hpp>
|
||||
#endif // auto-linking disabled
|
||||
|
||||
#endif // BOOST_THREAD_CONFIG_WEK1032003_HPP
|
||||
|
||||
@@ -26,12 +26,12 @@ namespace thread {
|
||||
// general case
|
||||
template<class Return_Type, class Argument_Type>
|
||||
inline Return_Type &force_cast(Argument_Type &rSrc)
|
||||
{ return(*reinterpret_cast<Return_Type *>(&rSrc)); }
|
||||
{ return(*reinterpret_cast<Return_Type *>(&rSrc)); }
|
||||
|
||||
// specialization for const
|
||||
template<class Return_Type, class Argument_Type>
|
||||
inline const Return_Type &force_cast(const Argument_Type &rSrc)
|
||||
{ return(*reinterpret_cast<const Return_Type *>(&rSrc)); }
|
||||
{ return(*reinterpret_cast<const Return_Type *>(&rSrc)); }
|
||||
|
||||
|
||||
} // namespace thread
|
||||
|
||||
@@ -20,182 +20,182 @@ namespace boost {
|
||||
class condition;
|
||||
struct xtime;
|
||||
|
||||
namespace detail { namespace thread {
|
||||
namespace detail { namespace thread {
|
||||
|
||||
template <typename Mutex>
|
||||
class lock_ops : private noncopyable
|
||||
template <typename Mutex>
|
||||
class lock_ops : private noncopyable
|
||||
{
|
||||
private:
|
||||
lock_ops() { }
|
||||
|
||||
public:
|
||||
typedef typename Mutex::cv_state lock_state;
|
||||
|
||||
static void lock(Mutex& m)
|
||||
{
|
||||
private:
|
||||
lock_ops() { }
|
||||
|
||||
public:
|
||||
typedef typename Mutex::cv_state lock_state;
|
||||
|
||||
static void lock(Mutex& m)
|
||||
{
|
||||
m.do_lock();
|
||||
}
|
||||
static bool trylock(Mutex& m)
|
||||
{
|
||||
return m.do_trylock();
|
||||
}
|
||||
static bool timedlock(Mutex& m, const xtime& xt)
|
||||
{
|
||||
return m.do_timedlock(xt);
|
||||
}
|
||||
static void unlock(Mutex& m)
|
||||
{
|
||||
m.do_unlock();
|
||||
}
|
||||
static void lock(Mutex& m, lock_state& state)
|
||||
{
|
||||
m.do_lock(state);
|
||||
}
|
||||
static void unlock(Mutex& m, lock_state& state)
|
||||
{
|
||||
m.do_unlock(state);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Mutex>
|
||||
class scoped_lock : private noncopyable
|
||||
m.do_lock();
|
||||
}
|
||||
static bool trylock(Mutex& m)
|
||||
{
|
||||
public:
|
||||
typedef Mutex mutex_type;
|
||||
|
||||
explicit scoped_lock(Mutex& mx, bool initially_locked=true)
|
||||
: m_mutex(mx), m_locked(false)
|
||||
{
|
||||
if (initially_locked) lock();
|
||||
}
|
||||
~scoped_lock()
|
||||
{
|
||||
if (m_locked) unlock();
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
if (m_locked) throw lock_error();
|
||||
lock_ops<Mutex>::lock(m_mutex);
|
||||
m_locked = true;
|
||||
}
|
||||
void unlock()
|
||||
{
|
||||
if (!m_locked) throw lock_error();
|
||||
lock_ops<Mutex>::unlock(m_mutex);
|
||||
m_locked = false;
|
||||
}
|
||||
|
||||
bool locked() const { return m_locked; }
|
||||
operator const void*() const { return m_locked ? this : 0; }
|
||||
|
||||
private:
|
||||
friend class boost::condition;
|
||||
|
||||
Mutex& m_mutex;
|
||||
bool m_locked;
|
||||
};
|
||||
|
||||
template <typename TryMutex>
|
||||
class scoped_try_lock : private noncopyable
|
||||
return m.do_trylock();
|
||||
}
|
||||
static bool timedlock(Mutex& m, const xtime& xt)
|
||||
{
|
||||
public:
|
||||
typedef TryMutex mutex_type;
|
||||
|
||||
explicit scoped_try_lock(TryMutex& mx)
|
||||
: m_mutex(mx), m_locked(false)
|
||||
{
|
||||
try_lock();
|
||||
}
|
||||
scoped_try_lock(TryMutex& mx, bool initially_locked)
|
||||
: m_mutex(mx), m_locked(false)
|
||||
{
|
||||
if (initially_locked) lock();
|
||||
}
|
||||
~scoped_try_lock()
|
||||
{
|
||||
if (m_locked) unlock();
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
if (m_locked) throw lock_error();
|
||||
lock_ops<TryMutex>::lock(m_mutex);
|
||||
m_locked = true;
|
||||
}
|
||||
bool try_lock()
|
||||
{
|
||||
if (m_locked) throw lock_error();
|
||||
return (m_locked = lock_ops<TryMutex>::trylock(m_mutex));
|
||||
}
|
||||
void unlock()
|
||||
{
|
||||
if (!m_locked) throw lock_error();
|
||||
lock_ops<TryMutex>::unlock(m_mutex);
|
||||
m_locked = false;
|
||||
}
|
||||
|
||||
bool locked() const { return m_locked; }
|
||||
operator const void*() const { return m_locked ? this : 0; }
|
||||
|
||||
private:
|
||||
friend class boost::condition;
|
||||
|
||||
TryMutex& m_mutex;
|
||||
bool m_locked;
|
||||
};
|
||||
|
||||
template <typename TimedMutex>
|
||||
class scoped_timed_lock : private noncopyable
|
||||
return m.do_timedlock(xt);
|
||||
}
|
||||
static void unlock(Mutex& m)
|
||||
{
|
||||
public:
|
||||
typedef TimedMutex mutex_type;
|
||||
m.do_unlock();
|
||||
}
|
||||
static void lock(Mutex& m, lock_state& state)
|
||||
{
|
||||
m.do_lock(state);
|
||||
}
|
||||
static void unlock(Mutex& m, lock_state& state)
|
||||
{
|
||||
m.do_unlock(state);
|
||||
}
|
||||
};
|
||||
|
||||
scoped_timed_lock(TimedMutex& mx, const xtime& xt)
|
||||
: m_mutex(mx), m_locked(false)
|
||||
{
|
||||
timed_lock(xt);
|
||||
}
|
||||
scoped_timed_lock(TimedMutex& mx, bool initially_locked)
|
||||
: m_mutex(mx), m_locked(false)
|
||||
{
|
||||
if (initially_locked) lock();
|
||||
}
|
||||
~scoped_timed_lock()
|
||||
{
|
||||
if (m_locked) unlock();
|
||||
}
|
||||
template <typename Mutex>
|
||||
class scoped_lock : private noncopyable
|
||||
{
|
||||
public:
|
||||
typedef Mutex mutex_type;
|
||||
|
||||
void lock()
|
||||
{
|
||||
if (m_locked) throw lock_error();
|
||||
lock_ops<TimedMutex>::lock(m_mutex);
|
||||
m_locked = true;
|
||||
}
|
||||
bool timed_lock(const xtime& xt)
|
||||
{
|
||||
if (m_locked) throw lock_error();
|
||||
return (m_locked = lock_ops<TimedMutex>::timedlock(m_mutex, xt));
|
||||
}
|
||||
void unlock()
|
||||
{
|
||||
if (!m_locked) throw lock_error();
|
||||
lock_ops<TimedMutex>::unlock(m_mutex);
|
||||
m_locked = false;
|
||||
}
|
||||
explicit scoped_lock(Mutex& mx, bool initially_locked=true)
|
||||
: m_mutex(mx), m_locked(false)
|
||||
{
|
||||
if (initially_locked) lock();
|
||||
}
|
||||
~scoped_lock()
|
||||
{
|
||||
if (m_locked) unlock();
|
||||
}
|
||||
|
||||
bool locked() const { return m_locked; }
|
||||
operator const void*() const { return m_locked ? this : 0; }
|
||||
void lock()
|
||||
{
|
||||
if (m_locked) throw lock_error();
|
||||
lock_ops<Mutex>::lock(m_mutex);
|
||||
m_locked = true;
|
||||
}
|
||||
void unlock()
|
||||
{
|
||||
if (!m_locked) throw lock_error();
|
||||
lock_ops<Mutex>::unlock(m_mutex);
|
||||
m_locked = false;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class boost::condition;
|
||||
bool locked() const { return m_locked; }
|
||||
operator const void*() const { return m_locked ? this : 0; }
|
||||
|
||||
TimedMutex& m_mutex;
|
||||
bool m_locked;
|
||||
};
|
||||
private:
|
||||
friend class boost::condition;
|
||||
|
||||
} // namespace thread
|
||||
} // namespace detail
|
||||
Mutex& m_mutex;
|
||||
bool m_locked;
|
||||
};
|
||||
|
||||
template <typename TryMutex>
|
||||
class scoped_try_lock : private noncopyable
|
||||
{
|
||||
public:
|
||||
typedef TryMutex mutex_type;
|
||||
|
||||
explicit scoped_try_lock(TryMutex& mx)
|
||||
: m_mutex(mx), m_locked(false)
|
||||
{
|
||||
try_lock();
|
||||
}
|
||||
scoped_try_lock(TryMutex& mx, bool initially_locked)
|
||||
: m_mutex(mx), m_locked(false)
|
||||
{
|
||||
if (initially_locked) lock();
|
||||
}
|
||||
~scoped_try_lock()
|
||||
{
|
||||
if (m_locked) unlock();
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
if (m_locked) throw lock_error();
|
||||
lock_ops<TryMutex>::lock(m_mutex);
|
||||
m_locked = true;
|
||||
}
|
||||
bool try_lock()
|
||||
{
|
||||
if (m_locked) throw lock_error();
|
||||
return (m_locked = lock_ops<TryMutex>::trylock(m_mutex));
|
||||
}
|
||||
void unlock()
|
||||
{
|
||||
if (!m_locked) throw lock_error();
|
||||
lock_ops<TryMutex>::unlock(m_mutex);
|
||||
m_locked = false;
|
||||
}
|
||||
|
||||
bool locked() const { return m_locked; }
|
||||
operator const void*() const { return m_locked ? this : 0; }
|
||||
|
||||
private:
|
||||
friend class boost::condition;
|
||||
|
||||
TryMutex& m_mutex;
|
||||
bool m_locked;
|
||||
};
|
||||
|
||||
template <typename TimedMutex>
|
||||
class scoped_timed_lock : private noncopyable
|
||||
{
|
||||
public:
|
||||
typedef TimedMutex mutex_type;
|
||||
|
||||
scoped_timed_lock(TimedMutex& mx, const xtime& xt)
|
||||
: m_mutex(mx), m_locked(false)
|
||||
{
|
||||
timed_lock(xt);
|
||||
}
|
||||
scoped_timed_lock(TimedMutex& mx, bool initially_locked)
|
||||
: m_mutex(mx), m_locked(false)
|
||||
{
|
||||
if (initially_locked) lock();
|
||||
}
|
||||
~scoped_timed_lock()
|
||||
{
|
||||
if (m_locked) unlock();
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
if (m_locked) throw lock_error();
|
||||
lock_ops<TimedMutex>::lock(m_mutex);
|
||||
m_locked = true;
|
||||
}
|
||||
bool timed_lock(const xtime& xt)
|
||||
{
|
||||
if (m_locked) throw lock_error();
|
||||
return (m_locked = lock_ops<TimedMutex>::timedlock(m_mutex, xt));
|
||||
}
|
||||
void unlock()
|
||||
{
|
||||
if (!m_locked) throw lock_error();
|
||||
lock_ops<TimedMutex>::unlock(m_mutex);
|
||||
m_locked = false;
|
||||
}
|
||||
|
||||
bool locked() const { return m_locked; }
|
||||
operator const void*() const { return m_locked ? this : 0; }
|
||||
|
||||
private:
|
||||
friend class boost::condition;
|
||||
|
||||
TimedMutex& m_mutex;
|
||||
bool m_locked;
|
||||
};
|
||||
|
||||
} // namespace thread
|
||||
} // namespace detail
|
||||
} // namespace boost
|
||||
|
||||
// Change Log:
|
||||
|
||||
@@ -26,29 +26,29 @@ namespace thread {
|
||||
template<class T>
|
||||
class singleton: private T
|
||||
{
|
||||
private:
|
||||
private:
|
||||
singleton();
|
||||
~singleton();
|
||||
|
||||
public:
|
||||
public:
|
||||
static T &instance();
|
||||
};
|
||||
|
||||
|
||||
template<class T>
|
||||
inline singleton<T>::singleton()
|
||||
{ /* no-op */ }
|
||||
{ /* no-op */ }
|
||||
|
||||
template<class T>
|
||||
inline singleton<T>::~singleton()
|
||||
{ /* no-op */ }
|
||||
{ /* no-op */ }
|
||||
|
||||
|
||||
template<class T>
|
||||
/*static*/ T &singleton<T>::instance()
|
||||
{
|
||||
// function-local static to force this to work correctly at static initialization
|
||||
// time.
|
||||
// function-local static to force this to work correctly at static
|
||||
// initialization time.
|
||||
static singleton<T> s_oT;
|
||||
return(s_oT);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,17 @@
|
||||
// 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
|
||||
// insist on threading support being available:
|
||||
#include <boost/config/requires_threads.hpp>
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2001
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2001
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
@@ -13,9 +13,8 @@
|
||||
#define BOOST_MUTEX_WEK070601_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifndef BOOST_HAS_THREADS
|
||||
# error Thread support is unavailable!
|
||||
#endif
|
||||
// insist on threading support being available:
|
||||
#include <boost/config/requires_threads.hpp>
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/thread/detail/lock.hpp>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2001
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
@@ -13,9 +13,8 @@
|
||||
#define BOOST_ONCE_WEK080101_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifndef BOOST_HAS_THREADS
|
||||
# error Thread support is unavailable!
|
||||
#endif
|
||||
// insist on threading support being available:
|
||||
#include <boost/config/requires_threads.hpp>
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2001
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
@@ -13,9 +13,8 @@
|
||||
#define BOOST_RECURSIVE_MUTEX_WEK070601_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifndef BOOST_HAS_THREADS
|
||||
# error Thread support is unavailable!
|
||||
#endif
|
||||
// insist on threading support being available:
|
||||
#include <boost/config/requires_threads.hpp>
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/thread/detail/lock.hpp>
|
||||
@@ -80,7 +79,8 @@ public:
|
||||
friend class detail::thread::lock_ops<recursive_try_mutex>;
|
||||
|
||||
typedef detail::thread::scoped_lock<recursive_try_mutex> scoped_lock;
|
||||
typedef detail::thread::scoped_try_lock<recursive_try_mutex> scoped_try_lock;
|
||||
typedef detail::thread::scoped_try_lock<
|
||||
recursive_try_mutex> scoped_try_lock;
|
||||
|
||||
recursive_try_mutex();
|
||||
~recursive_try_mutex();
|
||||
@@ -125,8 +125,10 @@ public:
|
||||
friend class detail::thread::lock_ops<recursive_timed_mutex>;
|
||||
|
||||
typedef detail::thread::scoped_lock<recursive_timed_mutex> scoped_lock;
|
||||
typedef detail::thread::scoped_try_lock<recursive_timed_mutex> scoped_try_lock;
|
||||
typedef detail::thread::scoped_timed_lock<recursive_timed_mutex> scoped_timed_lock;
|
||||
typedef detail::thread::scoped_try_lock<
|
||||
recursive_timed_mutex> scoped_try_lock;
|
||||
typedef detail::thread::scoped_timed_lock<
|
||||
recursive_timed_mutex> scoped_timed_lock;
|
||||
|
||||
recursive_timed_mutex();
|
||||
~recursive_timed_mutex();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2001
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
@@ -13,9 +13,8 @@
|
||||
#define BOOST_THREAD_WEK070601_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifndef BOOST_HAS_THREADS
|
||||
# error Thread support is unavailable!
|
||||
#endif
|
||||
// insist on threading support being available:
|
||||
#include <boost/config/requires_threads.hpp>
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/function.hpp>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2001
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
@@ -13,9 +13,8 @@
|
||||
#define BOOST_TSS_WEK070601_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifndef BOOST_HAS_THREADS
|
||||
# error Thread support is unavailable!
|
||||
#endif
|
||||
// insist on threading support being available:
|
||||
#include <boost/config/requires_threads.hpp>
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
@@ -28,32 +27,32 @@
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace detail {
|
||||
class BOOST_THREAD_DECL tss : private noncopyable
|
||||
{
|
||||
public:
|
||||
tss(void (*cleanup)(void*)=0);
|
||||
~tss();
|
||||
namespace detail {
|
||||
class BOOST_THREAD_DECL tss : private noncopyable
|
||||
{
|
||||
public:
|
||||
tss(void (*cleanup)(void*)=0);
|
||||
~tss();
|
||||
|
||||
void* get() const;
|
||||
bool set(void* value);
|
||||
void* get() const;
|
||||
bool set(void* value);
|
||||
|
||||
private:
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
unsigned long m_key;
|
||||
void (*m_cleanup)(void*);
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
pthread_key_t m_key;
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
TaskStorageIndex m_key;
|
||||
void (*m_cleanup)(void*);
|
||||
#endif
|
||||
};
|
||||
private:
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
unsigned long m_key;
|
||||
void (*m_cleanup)(void*);
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
pthread_key_t m_key;
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
TaskStorageIndex m_key;
|
||||
void (*m_cleanup)(void*);
|
||||
#endif
|
||||
};
|
||||
|
||||
#if defined(BOOST_HAS_MPTASKS)
|
||||
void thread_cleanup();
|
||||
#endif
|
||||
}
|
||||
#if defined(BOOST_HAS_MPTASKS)
|
||||
void thread_cleanup();
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class thread_specific_ptr : private noncopyable
|
||||
@@ -65,7 +64,13 @@ public:
|
||||
T* operator->() const { return get(); }
|
||||
T& operator*() const { return *get(); }
|
||||
T* release() { T* temp = get(); m_tss.set(0); return temp; }
|
||||
void reset(T* p=0) { T* cur = get(); if (cur == p) return; delete cur; m_tss.set(p); }
|
||||
void reset(T* p=0)
|
||||
{
|
||||
T* cur = get();
|
||||
if (cur == p) return;
|
||||
delete cur;
|
||||
m_tss.set(p);
|
||||
}
|
||||
|
||||
private:
|
||||
static void cleanup(void* p) { delete static_cast<T*>(p); }
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2001
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2001
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
@@ -25,9 +25,9 @@
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
# include <errno.h>
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
# include <MacErrors.h>
|
||||
# include "mac/init.hpp"
|
||||
# include "mac/safe.hpp"
|
||||
# include <MacErrors.h>
|
||||
# include "mac/init.hpp"
|
||||
# include "mac/safe.hpp"
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
@@ -40,30 +40,31 @@ condition_impl::condition_impl()
|
||||
{
|
||||
m_gate = reinterpret_cast<void*>(CreateSemaphore(0, 1, 1, 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));
|
||||
|
||||
if (!m_gate || !m_queue || !m_mutex)
|
||||
{
|
||||
int res = 0;
|
||||
if (m_gate)
|
||||
{
|
||||
res = CloseHandle(reinterpret_cast<HANDLE>(m_gate));
|
||||
assert(res);
|
||||
}
|
||||
if (m_queue)
|
||||
{
|
||||
res = CloseHandle(reinterpret_cast<HANDLE>(m_queue));
|
||||
assert(res);
|
||||
}
|
||||
if (m_mutex)
|
||||
{
|
||||
res = CloseHandle(reinterpret_cast<HANDLE>(m_mutex));
|
||||
assert(res);
|
||||
}
|
||||
int res = 0;
|
||||
if (m_gate)
|
||||
{
|
||||
res = CloseHandle(reinterpret_cast<HANDLE>(m_gate));
|
||||
assert(res);
|
||||
}
|
||||
if (m_queue)
|
||||
{
|
||||
res = CloseHandle(reinterpret_cast<HANDLE>(m_queue));
|
||||
assert(res);
|
||||
}
|
||||
if (m_mutex)
|
||||
{
|
||||
res = CloseHandle(reinterpret_cast<HANDLE>(m_mutex));
|
||||
assert(res);
|
||||
}
|
||||
|
||||
throw thread_resource_error();
|
||||
}
|
||||
throw thread_resource_error();
|
||||
}
|
||||
}
|
||||
|
||||
condition_impl::~condition_impl()
|
||||
@@ -86,47 +87,47 @@ void condition_impl::notify_one()
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
|
||||
if (m_waiting != 0) // the m_gate is already closed
|
||||
{
|
||||
if (m_blocked == 0)
|
||||
{
|
||||
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||
assert(res);
|
||||
return;
|
||||
}
|
||||
if (m_blocked == 0)
|
||||
{
|
||||
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||
assert(res);
|
||||
return;
|
||||
}
|
||||
|
||||
++m_waiting;
|
||||
--m_blocked;
|
||||
signals = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
if (m_blocked > m_gone)
|
||||
{
|
||||
if (m_gone != 0)
|
||||
{
|
||||
m_blocked -= m_gone;
|
||||
m_gone = 0;
|
||||
}
|
||||
signals = m_waiting = 1;
|
||||
++m_waiting;
|
||||
--m_blocked;
|
||||
signals = 1;
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||
assert(res);
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
if (m_blocked > m_gone)
|
||||
{
|
||||
if (m_gone != 0)
|
||||
{
|
||||
m_blocked -= m_gone;
|
||||
m_gone = 0;
|
||||
}
|
||||
signals = m_waiting = 1;
|
||||
--m_blocked;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||
assert(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||
assert(res);
|
||||
|
||||
if (signals)
|
||||
{
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_queue), signals, 0);
|
||||
assert(res);
|
||||
}
|
||||
{
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_queue), signals, 0);
|
||||
assert(res);
|
||||
}
|
||||
}
|
||||
|
||||
void condition_impl::notify_all()
|
||||
@@ -138,46 +139,47 @@ void condition_impl::notify_all()
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
|
||||
if (m_waiting != 0) // the m_gate is already closed
|
||||
{
|
||||
if (m_blocked == 0)
|
||||
{
|
||||
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||
assert(res);
|
||||
return;
|
||||
}
|
||||
if (m_blocked == 0)
|
||||
{
|
||||
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||
assert(res);
|
||||
return;
|
||||
}
|
||||
|
||||
m_waiting += (signals = m_blocked);
|
||||
m_blocked = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
if (m_blocked > m_gone)
|
||||
{
|
||||
if (m_gone != 0)
|
||||
{
|
||||
m_blocked -= m_gone;
|
||||
m_gone = 0;
|
||||
}
|
||||
signals = m_waiting = m_blocked;
|
||||
m_waiting += (signals = m_blocked);
|
||||
m_blocked = 0;
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||
assert(res);
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
if (m_blocked > m_gone)
|
||||
{
|
||||
if (m_gone != 0)
|
||||
{
|
||||
m_blocked -= m_gone;
|
||||
m_gone = 0;
|
||||
}
|
||||
signals = m_waiting = m_blocked;
|
||||
m_blocked = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||
assert(res);
|
||||
}
|
||||
}
|
||||
|
||||
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||
assert(res);
|
||||
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||
assert(res);
|
||||
|
||||
if (signals)
|
||||
if (signals)
|
||||
{
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_queue), signals, 0);
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_queue), signals,
|
||||
0);
|
||||
assert(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void condition_impl::enter_wait()
|
||||
@@ -204,47 +206,47 @@ void condition_impl::do_wait()
|
||||
was_waiting = m_waiting;
|
||||
was_gone = m_gone;
|
||||
if (was_waiting != 0)
|
||||
{
|
||||
if (--m_waiting == 0)
|
||||
{
|
||||
if (m_blocked != 0)
|
||||
{
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1,
|
||||
0); // open m_gate
|
||||
assert(res);
|
||||
was_waiting = 0;
|
||||
}
|
||||
else if (m_gone != 0)
|
||||
m_gone = 0;
|
||||
if (--m_waiting == 0)
|
||||
{
|
||||
if (m_blocked != 0)
|
||||
{
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1,
|
||||
0); // open m_gate
|
||||
assert(res);
|
||||
was_waiting = 0;
|
||||
}
|
||||
else if (m_gone != 0)
|
||||
m_gone = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (++m_gone == (std::numeric_limits<unsigned>::max() / 2))
|
||||
{
|
||||
// timeout occured, normalize the m_gone count
|
||||
// this may occur if many calls to wait with a timeout are made and
|
||||
// no call to notify_* is made
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
m_blocked -= m_gone;
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||
assert(res);
|
||||
m_gone = 0;
|
||||
}
|
||||
{
|
||||
// timeout occured, normalize the m_gone count
|
||||
// this may occur if many calls to wait with a timeout are made and
|
||||
// no call to notify_* is made
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
m_blocked -= m_gone;
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||
assert(res);
|
||||
m_gone = 0;
|
||||
}
|
||||
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||
assert(res);
|
||||
|
||||
if (was_waiting == 1)
|
||||
{
|
||||
for (/**/ ; was_gone; --was_gone)
|
||||
{
|
||||
// better now than spurious later
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue),
|
||||
INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
for (/**/ ; was_gone; --was_gone)
|
||||
{
|
||||
// better now than spurious later
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue),
|
||||
INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
}
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||
assert(res);
|
||||
}
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||
assert(res);
|
||||
}
|
||||
}
|
||||
|
||||
bool condition_impl::do_timed_wait(const xtime& xt)
|
||||
@@ -253,25 +255,25 @@ bool condition_impl::do_timed_wait(const xtime& xt)
|
||||
unsigned int res = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
int milliseconds;
|
||||
to_duration(xt, milliseconds);
|
||||
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue),
|
||||
milliseconds);
|
||||
assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
|
||||
ret = (res == WAIT_OBJECT_0);
|
||||
|
||||
if (res == WAIT_TIMEOUT)
|
||||
{
|
||||
xtime cur;
|
||||
xtime_get(&cur, TIME_UTC);
|
||||
if (xtime_cmp(xt, cur) > 0)
|
||||
continue;
|
||||
}
|
||||
int milliseconds;
|
||||
to_duration(xt, milliseconds);
|
||||
|
||||
break;
|
||||
}
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue),
|
||||
milliseconds);
|
||||
assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
|
||||
ret = (res == WAIT_OBJECT_0);
|
||||
|
||||
if (res == WAIT_TIMEOUT)
|
||||
{
|
||||
xtime cur;
|
||||
xtime_get(&cur, TIME_UTC);
|
||||
if (xtime_cmp(xt, cur) > 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
unsigned was_waiting=0;
|
||||
unsigned was_gone=0;
|
||||
@@ -281,54 +283,54 @@ bool condition_impl::do_timed_wait(const xtime& xt)
|
||||
was_waiting = m_waiting;
|
||||
was_gone = m_gone;
|
||||
if (was_waiting != 0)
|
||||
{
|
||||
if (!ret) // timeout
|
||||
{
|
||||
if (m_blocked != 0)
|
||||
--m_blocked;
|
||||
else
|
||||
++m_gone; // count spurious wakeups
|
||||
if (!ret) // timeout
|
||||
{
|
||||
if (m_blocked != 0)
|
||||
--m_blocked;
|
||||
else
|
||||
++m_gone; // count spurious wakeups
|
||||
}
|
||||
if (--m_waiting == 0)
|
||||
{
|
||||
if (m_blocked != 0)
|
||||
{
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1,
|
||||
0); // open m_gate
|
||||
assert(res);
|
||||
was_waiting = 0;
|
||||
}
|
||||
else if (m_gone != 0)
|
||||
m_gone = 0;
|
||||
}
|
||||
}
|
||||
if (--m_waiting == 0)
|
||||
{
|
||||
if (m_blocked != 0)
|
||||
{
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1,
|
||||
0); // open m_gate
|
||||
assert(res);
|
||||
was_waiting = 0;
|
||||
}
|
||||
else if (m_gone != 0)
|
||||
m_gone = 0;
|
||||
}
|
||||
}
|
||||
else if (++m_gone == (std::numeric_limits<unsigned>::max() / 2))
|
||||
{
|
||||
// timeout occured, normalize the m_gone count
|
||||
// this may occur if many calls to wait with a timeout are made and
|
||||
// no call to notify_* is made
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
m_blocked -= m_gone;
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||
assert(res);
|
||||
m_gone = 0;
|
||||
}
|
||||
{
|
||||
// timeout occured, normalize the m_gone count
|
||||
// this may occur if many calls to wait with a timeout are made and
|
||||
// no call to notify_* is made
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
m_blocked -= m_gone;
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||
assert(res);
|
||||
m_gone = 0;
|
||||
}
|
||||
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||
assert(res);
|
||||
|
||||
if (was_waiting == 1)
|
||||
{
|
||||
for (/**/ ; was_gone; --was_gone)
|
||||
{
|
||||
// better now than spurious later
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue),
|
||||
INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
for (/**/ ; was_gone; --was_gone)
|
||||
{
|
||||
// better now than spurious later
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue),
|
||||
INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
}
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||
assert(res);
|
||||
}
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||
assert(res);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -397,20 +399,20 @@ condition_impl::condition_impl()
|
||||
lStatus = MPCreateSemaphore(ULONG_MAX, 0, &m_queue);
|
||||
|
||||
if(lStatus != noErr || !m_gate || !m_queue)
|
||||
{
|
||||
if (m_gate)
|
||||
{
|
||||
lStatus = MPDeleteSemaphore(m_gate);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
if (m_queue)
|
||||
{
|
||||
lStatus = MPDeleteSemaphore(m_queue);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
if (m_gate)
|
||||
{
|
||||
lStatus = MPDeleteSemaphore(m_gate);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
if (m_queue)
|
||||
{
|
||||
lStatus = MPDeleteSemaphore(m_queue);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
throw thread_resource_error();
|
||||
}
|
||||
throw thread_resource_error();
|
||||
}
|
||||
}
|
||||
|
||||
condition_impl::~condition_impl()
|
||||
@@ -427,51 +429,52 @@ void condition_impl::notify_one()
|
||||
unsigned signals = 0;
|
||||
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||
m_mutex_mutex);
|
||||
assert(lStatus == noErr);
|
||||
|
||||
if (m_waiting != 0) // the m_gate is already closed
|
||||
{
|
||||
if (m_blocked == 0)
|
||||
{
|
||||
lStatus = MPExitCriticalRegion(m_mutex);
|
||||
assert(lStatus == noErr);
|
||||
return;
|
||||
}
|
||||
if (m_blocked == 0)
|
||||
{
|
||||
lStatus = MPExitCriticalRegion(m_mutex);
|
||||
assert(lStatus == noErr);
|
||||
return;
|
||||
}
|
||||
|
||||
++m_waiting;
|
||||
--m_blocked;
|
||||
}
|
||||
else
|
||||
{
|
||||
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
|
||||
assert(lStatus == noErr);
|
||||
if (m_blocked > m_gone)
|
||||
{
|
||||
if (m_gone != 0)
|
||||
{
|
||||
m_blocked -= m_gone;
|
||||
m_gone = 0;
|
||||
}
|
||||
signals = m_waiting = 1;
|
||||
++m_waiting;
|
||||
--m_blocked;
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
lStatus = MPSignalSemaphore(m_gate);
|
||||
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
if (m_blocked > m_gone)
|
||||
{
|
||||
if (m_gone != 0)
|
||||
{
|
||||
m_blocked -= m_gone;
|
||||
m_gone = 0;
|
||||
}
|
||||
signals = m_waiting = 1;
|
||||
--m_blocked;
|
||||
}
|
||||
else
|
||||
{
|
||||
lStatus = MPSignalSemaphore(m_gate);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
lStatus = MPExitCriticalRegion(m_mutex);
|
||||
assert(lStatus == noErr);
|
||||
|
||||
while (signals)
|
||||
{
|
||||
lStatus = MPSignalSemaphore(m_queue);
|
||||
lStatus = MPExitCriticalRegion(m_mutex);
|
||||
assert(lStatus == noErr);
|
||||
--signals;
|
||||
|
||||
while (signals)
|
||||
{
|
||||
lStatus = MPSignalSemaphore(m_queue);
|
||||
assert(lStatus == noErr);
|
||||
--signals;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void condition_impl::notify_all()
|
||||
@@ -479,51 +482,52 @@ void condition_impl::notify_all()
|
||||
unsigned signals = 0;
|
||||
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||
m_mutex_mutex);
|
||||
assert(lStatus == noErr);
|
||||
|
||||
if (m_waiting != 0) // the m_gate is already closed
|
||||
{
|
||||
if (m_blocked == 0)
|
||||
{
|
||||
lStatus = MPExitCriticalRegion(m_mutex);
|
||||
assert(lStatus == noErr);
|
||||
return;
|
||||
}
|
||||
if (m_blocked == 0)
|
||||
{
|
||||
lStatus = MPExitCriticalRegion(m_mutex);
|
||||
assert(lStatus == noErr);
|
||||
return;
|
||||
}
|
||||
|
||||
m_waiting += (signals = m_blocked);
|
||||
m_blocked = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
|
||||
assert(lStatus == noErr);
|
||||
if (m_blocked > m_gone)
|
||||
{
|
||||
if (m_gone != 0)
|
||||
{
|
||||
m_blocked -= m_gone;
|
||||
m_gone = 0;
|
||||
}
|
||||
signals = m_waiting = m_blocked;
|
||||
m_waiting += (signals = m_blocked);
|
||||
m_blocked = 0;
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
lStatus = MPSignalSemaphore(m_gate);
|
||||
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
if (m_blocked > m_gone)
|
||||
{
|
||||
if (m_gone != 0)
|
||||
{
|
||||
m_blocked -= m_gone;
|
||||
m_gone = 0;
|
||||
}
|
||||
signals = m_waiting = m_blocked;
|
||||
m_blocked = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
lStatus = MPSignalSemaphore(m_gate);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
lStatus = MPExitCriticalRegion(m_mutex);
|
||||
assert(lStatus == noErr);
|
||||
|
||||
while (signals)
|
||||
{
|
||||
lStatus = MPSignalSemaphore(m_queue);
|
||||
lStatus = MPExitCriticalRegion(m_mutex);
|
||||
assert(lStatus == noErr);
|
||||
--signals;
|
||||
|
||||
while (signals)
|
||||
{
|
||||
lStatus = MPSignalSemaphore(m_queue);
|
||||
assert(lStatus == noErr);
|
||||
--signals;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void condition_impl::enter_wait()
|
||||
@@ -545,50 +549,51 @@ void condition_impl::do_wait()
|
||||
unsigned was_waiting=0;
|
||||
unsigned was_gone=0;
|
||||
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||
m_mutex_mutex);
|
||||
assert(lStatus == noErr);
|
||||
was_waiting = m_waiting;
|
||||
was_gone = m_gone;
|
||||
if (was_waiting != 0)
|
||||
{
|
||||
if (--m_waiting == 0)
|
||||
{
|
||||
if (m_blocked != 0)
|
||||
{
|
||||
lStatus = MPSignalSemaphore(m_gate); // open m_gate
|
||||
assert(lStatus == noErr);
|
||||
was_waiting = 0;
|
||||
}
|
||||
else if (m_gone != 0)
|
||||
m_gone = 0;
|
||||
if (--m_waiting == 0)
|
||||
{
|
||||
if (m_blocked != 0)
|
||||
{
|
||||
lStatus = MPSignalSemaphore(m_gate); // open m_gate
|
||||
assert(lStatus == noErr);
|
||||
was_waiting = 0;
|
||||
}
|
||||
else if (m_gone != 0)
|
||||
m_gone = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (++m_gone == (std::numeric_limits<unsigned>::max() / 2))
|
||||
{
|
||||
// timeout occured, normalize the m_gone count
|
||||
// this may occur if many calls to wait with a timeout are made and
|
||||
// no call to notify_* is made
|
||||
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
|
||||
assert(lStatus == noErr);
|
||||
m_blocked -= m_gone;
|
||||
lStatus = MPSignalSemaphore(m_gate);
|
||||
assert(lStatus == noErr);
|
||||
m_gone = 0;
|
||||
}
|
||||
{
|
||||
// timeout occured, normalize the m_gone count
|
||||
// this may occur if many calls to wait with a timeout are made and
|
||||
// no call to notify_* is made
|
||||
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
|
||||
assert(lStatus == noErr);
|
||||
m_blocked -= m_gone;
|
||||
lStatus = MPSignalSemaphore(m_gate);
|
||||
assert(lStatus == noErr);
|
||||
m_gone = 0;
|
||||
}
|
||||
lStatus = MPExitCriticalRegion(m_mutex);
|
||||
assert(lStatus == noErr);
|
||||
|
||||
if (was_waiting == 1)
|
||||
{
|
||||
for (/**/ ; was_gone; --was_gone)
|
||||
{
|
||||
// better now than spurious later
|
||||
lStatus = safe_wait_on_semaphore(m_queue, kDurationForever);
|
||||
for (/**/ ; was_gone; --was_gone)
|
||||
{
|
||||
// better now than spurious later
|
||||
lStatus = safe_wait_on_semaphore(m_queue, kDurationForever);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
lStatus = MPSignalSemaphore(m_gate);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
lStatus = MPSignalSemaphore(m_gate);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
}
|
||||
|
||||
bool condition_impl::do_timed_wait(const xtime& xt)
|
||||
@@ -605,57 +610,58 @@ bool condition_impl::do_timed_wait(const xtime& xt)
|
||||
unsigned was_waiting=0;
|
||||
unsigned was_gone=0;
|
||||
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||
m_mutex_mutex);
|
||||
assert(lStatus == noErr);
|
||||
was_waiting = m_waiting;
|
||||
was_gone = m_gone;
|
||||
if (was_waiting != 0)
|
||||
{
|
||||
if (!ret) // timeout
|
||||
{
|
||||
if (m_blocked != 0)
|
||||
--m_blocked;
|
||||
else
|
||||
++m_gone; // count spurious wakeups
|
||||
if (!ret) // timeout
|
||||
{
|
||||
if (m_blocked != 0)
|
||||
--m_blocked;
|
||||
else
|
||||
++m_gone; // count spurious wakeups
|
||||
}
|
||||
if (--m_waiting == 0)
|
||||
{
|
||||
if (m_blocked != 0)
|
||||
{
|
||||
lStatus = MPSignalSemaphore(m_gate); // open m_gate
|
||||
assert(lStatus == noErr);
|
||||
was_waiting = 0;
|
||||
}
|
||||
else if (m_gone != 0)
|
||||
m_gone = 0;
|
||||
}
|
||||
}
|
||||
if (--m_waiting == 0)
|
||||
{
|
||||
if (m_blocked != 0)
|
||||
{
|
||||
lStatus = MPSignalSemaphore(m_gate); // open m_gate
|
||||
assert(lStatus == noErr);
|
||||
was_waiting = 0;
|
||||
}
|
||||
else if (m_gone != 0)
|
||||
m_gone = 0;
|
||||
}
|
||||
}
|
||||
else if (++m_gone == (std::numeric_limits<unsigned>::max() / 2))
|
||||
{
|
||||
// timeout occured, normalize the m_gone count
|
||||
// this may occur if many calls to wait with a timeout are made and
|
||||
// no call to notify_* is made
|
||||
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
|
||||
assert(lStatus == noErr);
|
||||
m_blocked -= m_gone;
|
||||
lStatus = MPSignalSemaphore(m_gate);
|
||||
assert(lStatus == noErr);
|
||||
m_gone = 0;
|
||||
}
|
||||
{
|
||||
// timeout occured, normalize the m_gone count
|
||||
// this may occur if many calls to wait with a timeout are made and
|
||||
// no call to notify_* is made
|
||||
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
|
||||
assert(lStatus == noErr);
|
||||
m_blocked -= m_gone;
|
||||
lStatus = MPSignalSemaphore(m_gate);
|
||||
assert(lStatus == noErr);
|
||||
m_gone = 0;
|
||||
}
|
||||
lStatus = MPExitCriticalRegion(m_mutex);
|
||||
assert(lStatus == noErr);
|
||||
|
||||
if (was_waiting == 1)
|
||||
{
|
||||
for (/**/ ; was_gone; --was_gone)
|
||||
{
|
||||
// better now than spurious later
|
||||
lStatus = safe_wait_on_semaphore(m_queue, kDurationForever);
|
||||
for (/**/ ; was_gone; --was_gone)
|
||||
{
|
||||
// better now than spurious later
|
||||
lStatus = safe_wait_on_semaphore(m_queue, kDurationForever);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
lStatus = MPSignalSemaphore(m_gate);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
lStatus = MPSignalSemaphore(m_gate);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2001
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
@@ -14,11 +14,13 @@
|
||||
|
||||
namespace boost {
|
||||
|
||||
lock_error::lock_error() : std::logic_error("thread lock error")
|
||||
lock_error::lock_error()
|
||||
: std::logic_error("thread lock error")
|
||||
{
|
||||
}
|
||||
|
||||
thread_resource_error::thread_resource_error() : std::runtime_error("thread resource error")
|
||||
thread_resource_error::thread_resource_error()
|
||||
: std::runtime_error("thread resource error")
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2001
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
@@ -16,7 +16,6 @@
|
||||
#include <boost/limits.hpp>
|
||||
#include <stdexcept>
|
||||
#include <cassert>
|
||||
#include <new>
|
||||
#include "timeconv.inl"
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
@@ -25,18 +24,23 @@
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
# include <errno.h>
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
# include <MacErrors.h>
|
||||
|
||||
# include "mac/init.hpp"
|
||||
# include "mac/safe.hpp"
|
||||
# include <MacErrors.h>
|
||||
# include "mac/init.hpp"
|
||||
# include "mac/safe.hpp"
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
mutex::mutex()
|
||||
mutex::mutex() : m_mutex(0)
|
||||
{
|
||||
m_mutex = reinterpret_cast<void*>(new(std::nothrow) CRITICAL_SECTION);
|
||||
try
|
||||
{
|
||||
m_mutex = reinterpret_cast<void*>(new CRITICAL_SECTION);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
if (!m_mutex)
|
||||
throw thread_resource_error();
|
||||
InitializeCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(m_mutex));
|
||||
@@ -151,7 +155,8 @@ bool timed_mutex::do_timedlock(const xtime& xt)
|
||||
int milliseconds;
|
||||
to_duration(xt, milliseconds);
|
||||
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), milliseconds);
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex),
|
||||
milliseconds);
|
||||
assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
|
||||
|
||||
if (res == WAIT_TIMEOUT)
|
||||
@@ -427,7 +432,8 @@ mutex::~mutex()
|
||||
void mutex::do_lock()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||
m_mutex_mutex);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
@@ -459,7 +465,8 @@ try_mutex::~try_mutex()
|
||||
void try_mutex::do_lock()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||
m_mutex_mutex);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
@@ -499,7 +506,8 @@ timed_mutex::~timed_mutex()
|
||||
void timed_mutex::do_lock()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||
m_mutex_mutex);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
|
||||
142
src/once.cpp
142
src/once.cpp
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2001
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
@@ -17,14 +17,16 @@
|
||||
# include <windows.h>
|
||||
# if defined(BOOST_NO_STRINGSTREAM)
|
||||
# include <strstream>
|
||||
class unfreezer
|
||||
{
|
||||
public:
|
||||
unfreezer(std::ostrstream& s) : m_stream(s) {}
|
||||
~unfreezer() { m_stream.freeze(false); }
|
||||
private:
|
||||
std::ostrstream& m_stream;
|
||||
};
|
||||
|
||||
class unfreezer
|
||||
{
|
||||
public:
|
||||
unfreezer(std::ostrstream& s) : m_stream(s) {}
|
||||
~unfreezer() { m_stream.freeze(false); }
|
||||
private:
|
||||
std::ostrstream& m_stream;
|
||||
};
|
||||
|
||||
# else
|
||||
# include <sstream>
|
||||
# endif
|
||||
@@ -33,7 +35,7 @@
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_NO_STDC_NAMESPACE
|
||||
namespace std { using ::sprintf; }
|
||||
namespace std { using ::sprintf; }
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
@@ -46,64 +48,70 @@ typedef void (*once_callback)();
|
||||
|
||||
extern "C" {
|
||||
|
||||
static void key_init()
|
||||
{
|
||||
pthread_key_create(&key, 0);
|
||||
}
|
||||
static void key_init()
|
||||
{
|
||||
pthread_key_create(&key, 0);
|
||||
}
|
||||
|
||||
static void do_once()
|
||||
{
|
||||
once_callback* cb = reinterpret_cast<once_callback*>(pthread_getspecific(key));
|
||||
(**cb)();
|
||||
}
|
||||
static void do_once()
|
||||
{
|
||||
once_callback* cb = reinterpret_cast<once_callback*>(
|
||||
pthread_getspecific(key));
|
||||
(**cb)();
|
||||
}
|
||||
|
||||
}
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
namespace {
|
||||
void *remote_call_proxy(void *pData)
|
||||
void *remote_call_proxy(void *pData)
|
||||
{
|
||||
std::pair<void (*)(), boost::once_flag *> &rData(
|
||||
*reinterpret_cast<std::pair<void (*)(), boost::once_flag *> *>(pData));
|
||||
|
||||
if(*rData.second == false)
|
||||
{
|
||||
std::pair<void (*)(), boost::once_flag *> &rData(*reinterpret_cast<std::pair<void (*)(), boost::once_flag *> *>(pData));
|
||||
|
||||
if(*rData.second == false)
|
||||
{
|
||||
rData.first();
|
||||
*rData.second = true;
|
||||
}
|
||||
|
||||
return(NULL);
|
||||
rData.first();
|
||||
*rData.second = true;
|
||||
}
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(BOOST_HAS_WINTHREADS)
|
||||
namespace {
|
||||
// The signature for InterlockedCompareExchange has changed with the
|
||||
// addition of Win64 support. I can't determine any (consistent and
|
||||
// portable) way of using conditional compilation to detect this, so
|
||||
// we use these type wrappers. Unfortunately, the various vendors
|
||||
// use different calling conventions and other signature anamolies,
|
||||
// and thus have unique types as well. This is known to work on VC6,
|
||||
// VC7, Borland 5.5.2 and gcc 3.2. Are there other signatures for
|
||||
// other platforms?
|
||||
inline LONG ice_wrapper(LONG (__stdcall *ice)(LONG*, LONG, LONG), volatile LONG* dest, LONG exch, LONG cmp)
|
||||
{
|
||||
return (*ice)(const_cast<LONG*>(dest), exch, cmp);
|
||||
}
|
||||
// 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(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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
// 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
|
||||
|
||||
@@ -116,12 +124,14 @@ void call_once(void (*func)(), once_flag& flag)
|
||||
{
|
||||
#if defined(BOOST_NO_STRINGSTREAM)
|
||||
std::ostrstream strm;
|
||||
strm << "2AC1A572DB6944B0A65C38C4140AF2F4" << std::hex << GetCurrentProcessId() << &flag << std::ends;
|
||||
strm << "2AC1A572DB6944B0A65C38C4140AF2F4" << std::hex
|
||||
<< GetCurrentProcessId() << &flag << std::ends;
|
||||
unfreezer unfreeze(strm);
|
||||
HANDLE mutex = CreateMutex(NULL, FALSE, strm.str());
|
||||
HANDLE mutex = CreateMutexA(NULL, FALSE, strm.str());
|
||||
#else
|
||||
std::ostringstream strm;
|
||||
strm << "2AC1A572DB6944B0A65C38C4140AF2F4" << std::hex << GetCurrentProcessId() << &flag;
|
||||
strm << "2AC1A572DB6944B0A65C38C4140AF2F4" << std::hex
|
||||
<< GetCurrentProcessId() << &flag;
|
||||
HANDLE mutex = CreateMutexA(NULL, FALSE, strm.str().c_str());
|
||||
#endif
|
||||
assert(mutex != NULL);
|
||||
@@ -132,7 +142,18 @@ void call_once(void (*func)(), once_flag& flag)
|
||||
|
||||
if (compare_exchange(&flag, 1, 1) == 0)
|
||||
{
|
||||
func();
|
||||
try
|
||||
{
|
||||
func();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
res = ReleaseMutex(mutex);
|
||||
assert(res);
|
||||
res = CloseHandle(mutex);
|
||||
assert(res);
|
||||
throw;
|
||||
}
|
||||
InterlockedExchange(&flag, 1);
|
||||
}
|
||||
|
||||
@@ -148,7 +169,8 @@ void call_once(void (*func)(), once_flag& flag)
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
if(flag == false)
|
||||
{
|
||||
// all we do here is make a remote call to blue, as blue is not reentrant.
|
||||
// all we do here is make a remote call to blue, as blue is not
|
||||
// reentrant.
|
||||
std::pair<void (*)(), once_flag *> sData(func, &flag);
|
||||
MPRemoteCall(remote_call_proxy, &sData, kMPOwningProcessRemoteContext);
|
||||
assert(flag == true);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2001
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
@@ -23,17 +23,23 @@
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
# include <errno.h>
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
# include <MacErrors.h>
|
||||
# include "safe.hpp"
|
||||
# include <MacErrors.h>
|
||||
# include "safe.hpp"
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
recursive_mutex::recursive_mutex()
|
||||
: m_count(0)
|
||||
: m_mutex(0), m_count(0)
|
||||
{
|
||||
m_mutex = reinterpret_cast<void*>(new(std::nothrow) CRITICAL_SECTION);
|
||||
try
|
||||
{
|
||||
m_mutex = reinterpret_cast<void*>(new CRITICAL_SECTION);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
if (!m_mutex)
|
||||
throw thread_resource_error();
|
||||
InitializeCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(m_mutex));
|
||||
@@ -201,7 +207,8 @@ bool recursive_timed_mutex::do_timedlock(const xtime& xt)
|
||||
to_duration(xt, milliseconds);
|
||||
|
||||
unsigned int res = 0;
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), milliseconds);
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex),
|
||||
milliseconds);
|
||||
assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
|
||||
|
||||
if (res == WAIT_TIMEOUT)
|
||||
@@ -798,7 +805,8 @@ recursive_mutex::~recursive_mutex()
|
||||
void recursive_mutex::do_lock()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||
m_mutex_mutex);
|
||||
assert(lStatus == noErr);
|
||||
|
||||
if (++m_count > 1)
|
||||
@@ -821,7 +829,8 @@ void recursive_mutex::do_unlock()
|
||||
void recursive_mutex::do_lock(cv_state& state)
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||
m_mutex_mutex);
|
||||
assert(lStatus == noErr);
|
||||
|
||||
m_count = state;
|
||||
@@ -849,7 +858,8 @@ recursive_try_mutex::~recursive_try_mutex()
|
||||
void recursive_try_mutex::do_lock()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||
m_mutex_mutex);
|
||||
assert(lStatus == noErr);
|
||||
|
||||
if (++m_count > 1)
|
||||
@@ -890,7 +900,8 @@ void recursive_try_mutex::do_unlock()
|
||||
void recursive_try_mutex::do_lock(cv_state& state)
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||
m_mutex_mutex);
|
||||
assert(lStatus == noErr);
|
||||
|
||||
m_count = state;
|
||||
@@ -918,7 +929,8 @@ recursive_timed_mutex::~recursive_timed_mutex()
|
||||
void recursive_timed_mutex::do_lock()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||
m_mutex_mutex);
|
||||
assert(lStatus == noErr);
|
||||
|
||||
if (++m_count > 1)
|
||||
@@ -981,7 +993,8 @@ void recursive_timed_mutex::do_unlock()
|
||||
void recursive_timed_mutex::do_lock(cv_state& state)
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||
m_mutex_mutex);
|
||||
assert(lStatus == noErr);
|
||||
|
||||
m_count = state;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2001
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
@@ -18,11 +18,11 @@
|
||||
# include <windows.h>
|
||||
# include <process.h>
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
# include <DriverServices.h>
|
||||
# include <DriverServices.h>
|
||||
|
||||
# include "init.hpp"
|
||||
# include "safe.hpp"
|
||||
# include <boost/thread/tss.hpp>
|
||||
# include "init.hpp"
|
||||
# include "safe.hpp"
|
||||
# include <boost/thread/tss.hpp>
|
||||
#endif
|
||||
|
||||
#include "timeconv.inl"
|
||||
@@ -32,7 +32,10 @@ namespace {
|
||||
class thread_param
|
||||
{
|
||||
public:
|
||||
thread_param(const boost::function0<void>& threadfunc) : m_threadfunc(threadfunc), m_started(false) { }
|
||||
thread_param(const boost::function0<void>& threadfunc)
|
||||
: m_threadfunc(threadfunc), m_started(false)
|
||||
{
|
||||
}
|
||||
void wait()
|
||||
{
|
||||
boost::mutex::scoped_lock scoped_lock(m_mutex);
|
||||
@@ -56,28 +59,28 @@ public:
|
||||
|
||||
extern "C" {
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
unsigned __stdcall thread_proxy(void* param)
|
||||
unsigned __stdcall thread_proxy(void* param)
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
static void* thread_proxy(void* param)
|
||||
static void* thread_proxy(void* param)
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
static OSStatus thread_proxy(void* param)
|
||||
static OSStatus thread_proxy(void* param)
|
||||
#endif
|
||||
{
|
||||
try
|
||||
{
|
||||
thread_param* p = static_cast<thread_param*>(param);
|
||||
boost::function0<void> threadfunc = p->m_threadfunc;
|
||||
p->started();
|
||||
threadfunc();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
try
|
||||
{
|
||||
thread_param* p = static_cast<thread_param*>(param);
|
||||
boost::function0<void> threadfunc = p->m_threadfunc;
|
||||
p->started();
|
||||
threadfunc();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
#if defined(BOOST_HAS_MPTASKS)
|
||||
::boost::detail::thread_cleanup();
|
||||
::boost::detail::thread_cleanup();
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -104,7 +107,8 @@ thread::thread(const function0<void>& threadfunc)
|
||||
{
|
||||
thread_param param(threadfunc);
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
m_thread = reinterpret_cast<void*>(_beginthreadex(0, 0, &thread_proxy, ¶m, 0, &m_id));
|
||||
m_thread = reinterpret_cast<void*>(_beginthreadex(0, 0, &thread_proxy,
|
||||
¶m, 0, &m_id));
|
||||
if (!m_thread)
|
||||
throw thread_resource_error();
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
@@ -121,11 +125,11 @@ thread::thread(const function0<void>& threadfunc)
|
||||
m_pTaskID = kInvalidID;
|
||||
|
||||
lStatus = MPCreateQueue(&m_pJoinQueueID);
|
||||
if(lStatus != noErr) throw thread_resource_error();
|
||||
if (lStatus != noErr) throw thread_resource_error();
|
||||
|
||||
lStatus = MPCreateTask(&thread_proxy, ¶m, 0UL, m_pJoinQueueID, NULL, NULL,
|
||||
0UL, &m_pTaskID);
|
||||
if(lStatus != noErr)
|
||||
lStatus = MPCreateTask(&thread_proxy, ¶m, 0UL, m_pJoinQueueID, NULL,
|
||||
NULL, 0UL, &m_pTaskID);
|
||||
if (lStatus != noErr)
|
||||
{
|
||||
lStatus = MPDeleteQueue(m_pJoinQueueID);
|
||||
assert(lStatus == noErr);
|
||||
@@ -181,7 +185,8 @@ void thread::join()
|
||||
res = pthread_join(m_thread, 0);
|
||||
assert(res == 0);
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
OSStatus lStatus = threads::mac::detail::safe_wait_on_queue(m_pJoinQueueID, NULL, NULL, NULL, kDurationForever);
|
||||
OSStatus lStatus = threads::mac::detail::safe_wait_on_queue(
|
||||
m_pJoinQueueID, NULL, NULL, NULL, kDurationForever);
|
||||
assert(lStatus == noErr);
|
||||
#endif
|
||||
// This isn't a race condition since any race that could occur would
|
||||
@@ -260,17 +265,20 @@ thread_group::thread_group()
|
||||
|
||||
thread_group::~thread_group()
|
||||
{
|
||||
// We shouldn't have to scoped_lock here, since referencing this object from another thread
|
||||
// while we're deleting it in the current thread is going to lead to undefined behavior
|
||||
// any way.
|
||||
for (std::list<thread*>::iterator it = m_threads.begin(); it != m_threads.end(); ++it)
|
||||
// We shouldn't have to scoped_lock here, since referencing this object
|
||||
// from another thread while we're deleting it in the current thread is
|
||||
// going to lead to undefined behavior any way.
|
||||
for (std::list<thread*>::iterator it = m_threads.begin();
|
||||
it != m_threads.end(); ++it)
|
||||
{
|
||||
delete (*it);
|
||||
}
|
||||
}
|
||||
|
||||
thread* thread_group::create_thread(const function0<void>& threadfunc)
|
||||
{
|
||||
// No scoped_lock required here since the only "shared data" that's modified here occurs
|
||||
// inside add_thread which does scoped_lock.
|
||||
// No scoped_lock required here since the only "shared data" that's
|
||||
// modified here occurs inside add_thread which does scoped_lock.
|
||||
std::auto_ptr<thread> thrd(new thread(threadfunc));
|
||||
add_thread(thrd.get());
|
||||
return thrd.release();
|
||||
@@ -280,9 +288,11 @@ void thread_group::add_thread(thread* thrd)
|
||||
{
|
||||
mutex::scoped_lock scoped_lock(m_mutex);
|
||||
|
||||
// For now we'll simply ignore requests to add a thread object multiple times.
|
||||
// Should we consider this an error and either throw or return an error value?
|
||||
std::list<thread*>::iterator it = std::find(m_threads.begin(), m_threads.end(), thrd);
|
||||
// For now we'll simply ignore requests to add a thread object multiple
|
||||
// times. Should we consider this an error and either throw or return an
|
||||
// error value?
|
||||
std::list<thread*>::iterator it = std::find(m_threads.begin(),
|
||||
m_threads.end(), thrd);
|
||||
assert(it == m_threads.end());
|
||||
if (it == m_threads.end())
|
||||
m_threads.push_back(thrd);
|
||||
@@ -292,9 +302,11 @@ void thread_group::remove_thread(thread* thrd)
|
||||
{
|
||||
mutex::scoped_lock scoped_lock(m_mutex);
|
||||
|
||||
// For now we'll simply ignore requests to remove a thread object that's not in the group.
|
||||
// Should we consider this an error and either throw or return an error value?
|
||||
std::list<thread*>::iterator it = std::find(m_threads.begin(), m_threads.end(), thrd);
|
||||
// For now we'll simply ignore requests to remove a thread object that's
|
||||
// not in the group. Should we consider this an error and either throw or
|
||||
// return an error value?
|
||||
std::list<thread*>::iterator it = std::find(m_threads.begin(),
|
||||
m_threads.end(), thrd);
|
||||
assert(it != m_threads.end());
|
||||
if (it != m_threads.end())
|
||||
m_threads.erase(it);
|
||||
@@ -303,8 +315,11 @@ void thread_group::remove_thread(thread* thrd)
|
||||
void thread_group::join_all()
|
||||
{
|
||||
mutex::scoped_lock scoped_lock(m_mutex);
|
||||
for (std::list<thread*>::iterator it = m_threads.begin(); it != m_threads.end(); ++it)
|
||||
for (std::list<thread*>::iterator it = m_threads.begin();
|
||||
it != m_threads.end(); ++it)
|
||||
{
|
||||
(*it)->join();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
// threadmon.cpp : Defines the entry point for the DLL application.
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
@@ -26,9 +34,9 @@ typedef std::set<exit_handlers*> registered_handlers;
|
||||
|
||||
namespace
|
||||
{
|
||||
CRITICAL_SECTION cs;
|
||||
DWORD key;
|
||||
registered_handlers registry;
|
||||
CRITICAL_SECTION cs;
|
||||
DWORD key;
|
||||
registered_handlers registry;
|
||||
}
|
||||
|
||||
#if defined(__BORLANDC__)
|
||||
@@ -36,70 +44,70 @@ namespace
|
||||
#endif
|
||||
|
||||
extern "C"
|
||||
BOOL WINAPI DllMain(HANDLE module, DWORD reason, LPVOID)
|
||||
BOOL WINAPI DllMain(HANDLE /*module*/, DWORD reason, LPVOID)
|
||||
{
|
||||
switch (reason)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
InitializeCriticalSection(&cs);
|
||||
key = TlsAlloc();
|
||||
break;
|
||||
case DLL_THREAD_ATTACH:
|
||||
break;
|
||||
case DLL_THREAD_DETACH:
|
||||
case DLL_PROCESS_ATTACH:
|
||||
InitializeCriticalSection(&cs);
|
||||
key = TlsAlloc();
|
||||
break;
|
||||
case DLL_THREAD_ATTACH:
|
||||
break;
|
||||
case DLL_THREAD_DETACH:
|
||||
{
|
||||
// Call the thread's exit handlers.
|
||||
exit_handlers* handlers =
|
||||
static_cast<exit_handlers*>(TlsGetValue(key));
|
||||
if (handlers)
|
||||
{
|
||||
for (exit_handlers::iterator it = handlers->begin();
|
||||
it != handlers->end(); ++it)
|
||||
{
|
||||
// Call the thread's exit handlers.
|
||||
exit_handlers* handlers =
|
||||
static_cast<exit_handlers*>(TlsGetValue(key));
|
||||
if (handlers)
|
||||
{
|
||||
for (exit_handlers::iterator it = handlers->begin();
|
||||
it != handlers->end(); ++it)
|
||||
{
|
||||
(*it)();
|
||||
}
|
||||
|
||||
// Remove the exit handler list from the registered lists
|
||||
// and then destroy it.
|
||||
EnterCriticalSection(&cs);
|
||||
registry.erase(handlers);
|
||||
LeaveCriticalSection(&cs);
|
||||
delete handlers;
|
||||
}
|
||||
(*it)();
|
||||
}
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
|
||||
// Remove the exit handler list from the registered lists
|
||||
// and then destroy it.
|
||||
EnterCriticalSection(&cs);
|
||||
registry.erase(handlers);
|
||||
LeaveCriticalSection(&cs);
|
||||
delete handlers;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
{
|
||||
// Assume the main thread is ending (call its handlers) and
|
||||
// all other threads have already ended. If this DLL is
|
||||
// loaded and unloaded dynamically at run time
|
||||
// this is a bad assumption, but this is the best we can do.
|
||||
exit_handlers* handlers =
|
||||
static_cast<exit_handlers*>(TlsGetValue(key));
|
||||
if (handlers)
|
||||
{
|
||||
for (exit_handlers::iterator it = handlers->begin();
|
||||
it != handlers->end(); ++it)
|
||||
{
|
||||
// Assume the main thread is ending (call its handlers) and
|
||||
// all other threads have already ended. If this DLL is
|
||||
// loaded and unloaded dynamically at run time
|
||||
// this is a bad assumption, but this is the best we can do.
|
||||
exit_handlers* handlers =
|
||||
static_cast<exit_handlers*>(TlsGetValue(key));
|
||||
if (handlers)
|
||||
{
|
||||
for (exit_handlers::iterator it = handlers->begin();
|
||||
it != handlers->end(); ++it)
|
||||
{
|
||||
(*it)();
|
||||
}
|
||||
}
|
||||
|
||||
// Destroy any remaining exit handlers. Above we assumed
|
||||
// there'd only be the main thread left, but to insure we
|
||||
// don't get memory leaks we won't make that assumption
|
||||
// here.
|
||||
EnterCriticalSection(&cs);
|
||||
for (registered_handlers::iterator it = registry.begin();
|
||||
it != registry.end(); ++it)
|
||||
{
|
||||
delete (*it);
|
||||
}
|
||||
LeaveCriticalSection(&cs);
|
||||
DeleteCriticalSection(&cs);
|
||||
TlsFree(key);
|
||||
(*it)();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Destroy any remaining exit handlers. Above we assumed
|
||||
// there'd only be the main thread left, but to insure we
|
||||
// don't get memory leaks we won't make that assumption
|
||||
// here.
|
||||
EnterCriticalSection(&cs);
|
||||
for (registered_handlers::iterator it = registry.begin();
|
||||
it != registry.end(); ++it)
|
||||
{
|
||||
delete (*it);
|
||||
}
|
||||
LeaveCriticalSection(&cs);
|
||||
DeleteCriticalSection(&cs);
|
||||
TlsFree(key);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
179
src/timeconv.inl
179
src/timeconv.inl
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2001
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
@@ -10,118 +10,119 @@
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
namespace {
|
||||
const int MILLISECONDS_PER_SECOND = 1000;
|
||||
const int NANOSECONDS_PER_SECOND = 1000000000;
|
||||
const int NANOSECONDS_PER_MILLISECOND = 1000000;
|
||||
const int MILLISECONDS_PER_SECOND = 1000;
|
||||
const int NANOSECONDS_PER_SECOND = 1000000000;
|
||||
const int NANOSECONDS_PER_MILLISECOND = 1000000;
|
||||
|
||||
const int MICROSECONDS_PER_SECOND = 1000000;
|
||||
const int NANOSECONDS_PER_MICROSECOND = 1000;
|
||||
const int MICROSECONDS_PER_SECOND = 1000000;
|
||||
const int NANOSECONDS_PER_MICROSECOND = 1000;
|
||||
|
||||
inline void to_time(int milliseconds, boost::xtime& xt)
|
||||
inline void to_time(int milliseconds, boost::xtime& xt)
|
||||
{
|
||||
int res = 0;
|
||||
res = boost::xtime_get(&xt, boost::TIME_UTC);
|
||||
assert(res == boost::TIME_UTC);
|
||||
|
||||
xt.sec += (milliseconds / MILLISECONDS_PER_SECOND);
|
||||
xt.nsec += ((milliseconds % MILLISECONDS_PER_SECOND) *
|
||||
NANOSECONDS_PER_MILLISECOND);
|
||||
|
||||
if (xt.nsec > static_cast<const int>(NANOSECONDS_PER_SECOND))
|
||||
{
|
||||
int res = 0;
|
||||
res = boost::xtime_get(&xt, boost::TIME_UTC);
|
||||
assert(res == boost::TIME_UTC);
|
||||
|
||||
xt.sec += (milliseconds / MILLISECONDS_PER_SECOND);
|
||||
xt.nsec += ((milliseconds % MILLISECONDS_PER_SECOND) * NANOSECONDS_PER_MILLISECOND);
|
||||
|
||||
if (xt.nsec > static_cast<const int>(NANOSECONDS_PER_SECOND))
|
||||
{
|
||||
++xt.sec;
|
||||
xt.nsec -= NANOSECONDS_PER_SECOND;
|
||||
}
|
||||
++xt.sec;
|
||||
xt.nsec -= NANOSECONDS_PER_SECOND;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
inline void to_timespec(const boost::xtime& xt, timespec& ts)
|
||||
inline void to_timespec(const boost::xtime& xt, timespec& ts)
|
||||
{
|
||||
ts.tv_sec = static_cast<int>(xt.sec);
|
||||
ts.tv_nsec = static_cast<int>(xt.nsec);
|
||||
if(ts.tv_nsec > static_cast<const int>(NANOSECONDS_PER_SECOND))
|
||||
{
|
||||
ts.tv_sec = static_cast<int>(xt.sec);
|
||||
ts.tv_nsec = static_cast<int>(xt.nsec);
|
||||
ts.tv_sec += ts.tv_nsec / NANOSECONDS_PER_SECOND;
|
||||
ts.tv_nsec %= NANOSECONDS_PER_SECOND;
|
||||
}
|
||||
}
|
||||
|
||||
inline void to_time(int milliseconds, timespec& ts)
|
||||
{
|
||||
boost::xtime xt;
|
||||
to_time(milliseconds, xt);
|
||||
to_timespec(xt, ts);
|
||||
}
|
||||
|
||||
inline void to_timespec_duration(const boost::xtime& xt, timespec& ts)
|
||||
{
|
||||
boost::xtime cur;
|
||||
int res = 0;
|
||||
res = boost::xtime_get(&cur, boost::TIME_UTC);
|
||||
assert(res == boost::TIME_UTC);
|
||||
|
||||
if (boost::xtime_cmp(xt, cur) <= 0)
|
||||
{
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ts.tv_sec = xt.sec - cur.sec;
|
||||
ts.tv_nsec = xt.nsec - cur.nsec;
|
||||
|
||||
if( ts.tv_nsec < 0 )
|
||||
{
|
||||
ts.tv_sec -= 1;
|
||||
ts.tv_nsec += NANOSECONDS_PER_SECOND;
|
||||
}
|
||||
if(ts.tv_nsec > static_cast<const int>(NANOSECONDS_PER_SECOND))
|
||||
{
|
||||
ts.tv_sec += ts.tv_nsec / NANOSECONDS_PER_SECOND;
|
||||
ts.tv_nsec %= NANOSECONDS_PER_SECOND;
|
||||
}
|
||||
}
|
||||
|
||||
inline void to_time(int milliseconds, timespec& ts)
|
||||
{
|
||||
boost::xtime xt;
|
||||
to_time(milliseconds, xt);
|
||||
to_timespec(xt, ts);
|
||||
}
|
||||
|
||||
inline void to_timespec_duration(const boost::xtime& xt, timespec& ts)
|
||||
{
|
||||
boost::xtime cur;
|
||||
int res = 0;
|
||||
res = boost::xtime_get(&cur, boost::TIME_UTC);
|
||||
assert(res == boost::TIME_UTC);
|
||||
|
||||
if (boost::xtime_cmp(xt, cur) <= 0)
|
||||
{
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ts.tv_sec = xt.sec - cur.sec;
|
||||
ts.tv_nsec = xt.nsec - cur.nsec;
|
||||
|
||||
if( ts.tv_nsec < 0 )
|
||||
{
|
||||
ts.tv_sec -= 1;
|
||||
ts.tv_nsec += NANOSECONDS_PER_SECOND;
|
||||
}
|
||||
if(ts.tv_nsec > static_cast<const int>(NANOSECONDS_PER_SECOND))
|
||||
{
|
||||
ts.tv_sec += ts.tv_nsec / NANOSECONDS_PER_SECOND;
|
||||
ts.tv_nsec %= NANOSECONDS_PER_SECOND;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
inline void to_duration(boost::xtime xt, int& milliseconds)
|
||||
{
|
||||
boost::xtime cur;
|
||||
int res = 0;
|
||||
res = boost::xtime_get(&cur, boost::TIME_UTC);
|
||||
assert(res == boost::TIME_UTC);
|
||||
inline void to_duration(boost::xtime xt, int& milliseconds)
|
||||
{
|
||||
boost::xtime cur;
|
||||
int res = 0;
|
||||
res = boost::xtime_get(&cur, boost::TIME_UTC);
|
||||
assert(res == boost::TIME_UTC);
|
||||
|
||||
if (boost::xtime_cmp(xt, cur) <= 0)
|
||||
milliseconds = 0;
|
||||
else
|
||||
if (boost::xtime_cmp(xt, cur) <= 0)
|
||||
milliseconds = 0;
|
||||
else
|
||||
{
|
||||
if (cur.nsec > xt.nsec)
|
||||
{
|
||||
if (cur.nsec > xt.nsec)
|
||||
{
|
||||
xt.nsec += NANOSECONDS_PER_SECOND;
|
||||
--xt.sec;
|
||||
}
|
||||
milliseconds = ((xt.sec - cur.sec) * MILLISECONDS_PER_SECOND) +
|
||||
(((xt.nsec - cur.nsec) + (NANOSECONDS_PER_MILLISECOND/2)) /
|
||||
xt.nsec += NANOSECONDS_PER_SECOND;
|
||||
--xt.sec;
|
||||
}
|
||||
milliseconds = (int)((xt.sec - cur.sec) * MILLISECONDS_PER_SECOND) +
|
||||
(((xt.nsec - cur.nsec) + (NANOSECONDS_PER_MILLISECOND/2)) /
|
||||
NANOSECONDS_PER_MILLISECOND);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void to_microduration(const boost::xtime& xt, int& microseconds)
|
||||
inline void to_microduration(const boost::xtime& xt, int& microseconds)
|
||||
{
|
||||
boost::xtime cur;
|
||||
int res = 0;
|
||||
res = boost::xtime_get(&cur, boost::TIME_UTC);
|
||||
assert(res == boost::TIME_UTC);
|
||||
|
||||
if (boost::xtime_get(&cur, boost::TIME_UTC) <= 0)
|
||||
microseconds = 0;
|
||||
else
|
||||
{
|
||||
boost::xtime cur;
|
||||
int res = 0;
|
||||
res = boost::xtime_get(&cur, boost::TIME_UTC);
|
||||
assert(res == boost::TIME_UTC);
|
||||
|
||||
if (boost::xtime_get(&cur, boost::TIME_UTC) <= 0)
|
||||
microseconds = 0;
|
||||
else
|
||||
{
|
||||
microseconds = ((xt.sec - cur.sec) * MICROSECONDS_PER_SECOND) +
|
||||
(((xt.nsec - cur.nsec) + (NANOSECONDS_PER_MICROSECOND/2)) /
|
||||
microseconds = (int)((xt.sec - cur.sec) * MICROSECONDS_PER_SECOND) +
|
||||
(((xt.nsec - cur.nsec) + (NANOSECONDS_PER_MICROSECOND/2)) /
|
||||
NANOSECONDS_PER_MICROSECOND);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Change Log:
|
||||
// 1 Jun 01 Initial creation.
|
||||
|
||||
151
src/tss.cpp
151
src/tss.cpp
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2001
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
@@ -23,94 +23,100 @@
|
||||
#include <boost/thread/detail/threadmon.hpp>
|
||||
#include <map>
|
||||
namespace {
|
||||
typedef std::pair<void(*)(void*), void*> cleanup_info;
|
||||
typedef std::map<int, cleanup_info> cleanup_handlers;
|
||||
typedef std::pair<void(*)(void*), void*> cleanup_info;
|
||||
typedef std::map<int, cleanup_info> cleanup_handlers;
|
||||
|
||||
DWORD key;
|
||||
boost::once_flag once = BOOST_ONCE_INIT;
|
||||
DWORD key;
|
||||
boost::once_flag once = BOOST_ONCE_INIT;
|
||||
|
||||
void init_cleanup_key()
|
||||
void init_cleanup_key()
|
||||
{
|
||||
key = TlsAlloc();
|
||||
assert(key != 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
void __cdecl cleanup()
|
||||
{
|
||||
cleanup_handlers* handlers = static_cast<cleanup_handlers*>(
|
||||
TlsGetValue(key));
|
||||
for (cleanup_handlers::iterator it = handlers->begin();
|
||||
it != handlers->end(); ++it)
|
||||
{
|
||||
key = TlsAlloc();
|
||||
assert(key != 0xFFFFFFFF);
|
||||
cleanup_info info = it->second;
|
||||
if (info.second)
|
||||
info.first(info.second);
|
||||
}
|
||||
delete handlers;
|
||||
}
|
||||
|
||||
void __cdecl cleanup()
|
||||
cleanup_handlers* get_handlers()
|
||||
{
|
||||
boost::call_once(&init_cleanup_key, once);
|
||||
|
||||
cleanup_handlers* handlers = static_cast<cleanup_handlers*>(
|
||||
TlsGetValue(key));
|
||||
if (!handlers)
|
||||
{
|
||||
cleanup_handlers* handlers = static_cast<cleanup_handlers*>(TlsGetValue(key));
|
||||
for (cleanup_handlers::iterator it = handlers->begin(); it != handlers->end(); ++it)
|
||||
try
|
||||
{
|
||||
cleanup_info info = it->second;
|
||||
if (info.second)
|
||||
info.first(info.second);
|
||||
handlers = new cleanup_handlers;
|
||||
}
|
||||
delete handlers;
|
||||
}
|
||||
|
||||
cleanup_handlers* get_handlers()
|
||||
{
|
||||
boost::call_once(&init_cleanup_key, once);
|
||||
|
||||
cleanup_handlers* handlers = static_cast<cleanup_handlers*>(TlsGetValue(key));
|
||||
if (!handlers)
|
||||
catch (...)
|
||||
{
|
||||
try
|
||||
{
|
||||
handlers = new cleanup_handlers;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int res = 0;
|
||||
res = TlsSetValue(key, handlers);
|
||||
assert(res);
|
||||
res = on_thread_exit(&cleanup);
|
||||
assert(res == 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return handlers;
|
||||
int res = 0;
|
||||
res = TlsSetValue(key, handlers);
|
||||
assert(res);
|
||||
res = on_thread_exit(&cleanup);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
return handlers;
|
||||
}
|
||||
}
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
#include <map>
|
||||
namespace {
|
||||
typedef std::pair<void(*)(void*), void*> cleanup_info;
|
||||
typedef std::map<int, cleanup_info> cleanup_handlers;
|
||||
typedef std::pair<void(*)(void*), void*> cleanup_info;
|
||||
typedef std::map<int, cleanup_info> cleanup_handlers;
|
||||
|
||||
TaskStorageIndex key;
|
||||
boost::once_flag once = BOOST_ONCE_INIT;
|
||||
TaskStorageIndex key;
|
||||
boost::once_flag once = BOOST_ONCE_INIT;
|
||||
|
||||
void init_cleanup_key()
|
||||
void init_cleanup_key()
|
||||
{
|
||||
OSStatus lStatus = MPAllocateTaskStorageIndex(&key);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
cleanup_handlers* get_handlers()
|
||||
{
|
||||
boost::call_once(&init_cleanup_key, once);
|
||||
|
||||
cleanup_handlers* handlers = reinterpret_cast<cleanup_handlers*>(
|
||||
MPGetTaskStorageValue(key));
|
||||
if (!handlers)
|
||||
{
|
||||
OSStatus lStatus = MPAllocateTaskStorageIndex(&key);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
cleanup_handlers* get_handlers()
|
||||
{
|
||||
boost::call_once(&init_cleanup_key, once);
|
||||
|
||||
cleanup_handlers* handlers = reinterpret_cast<cleanup_handlers*>(MPGetTaskStorageValue(key));
|
||||
if (!handlers)
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
handlers = new cleanup_handlers;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = MPSetTaskStorageValue(key, reinterpret_cast<TaskStorageValue>(handlers));
|
||||
assert(lStatus == noErr);
|
||||
// TODO - create a generalized mechanism for registering thread exit functions
|
||||
// and use it here.
|
||||
handlers = new cleanup_handlers;
|
||||
}
|
||||
|
||||
return handlers;
|
||||
catch (...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = MPSetTaskStorageValue(key,
|
||||
reinterpret_cast<TaskStorageValue>(handlers));
|
||||
assert(lStatus == noErr);
|
||||
// TODO - create a generalized mechanism for registering thread exit
|
||||
// functions and use it here.
|
||||
}
|
||||
|
||||
return handlers;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace boost {
|
||||
@@ -120,10 +126,12 @@ namespace detail {
|
||||
|
||||
void thread_cleanup()
|
||||
{
|
||||
cleanup_handlers* handlers = reinterpret_cast<cleanup_handlers*>(MPGetTaskStorageValue(key));
|
||||
cleanup_handlers* handlers = reinterpret_cast<cleanup_handlers*>(
|
||||
MPGetTaskStorageValue(key));
|
||||
if(handlers != NULL)
|
||||
{
|
||||
for (cleanup_handlers::iterator it = handlers->begin(); it != handlers->end(); ++it)
|
||||
for (cleanup_handlers::iterator it = handlers->begin();
|
||||
it != handlers->end(); ++it)
|
||||
{
|
||||
cleanup_info info = it->second;
|
||||
if (info.second)
|
||||
@@ -235,7 +243,8 @@ bool tss::set(void* value)
|
||||
cleanup_info info(m_cleanup, value);
|
||||
(*handlers)[m_key] = info;
|
||||
}
|
||||
OSStatus lStatus = MPSetTaskStorageValue(m_key, reinterpret_cast<TaskStorageValue>(value));
|
||||
OSStatus lStatus = MPSetTaskStorageValue(m_key,
|
||||
reinterpret_cast<TaskStorageValue>(value));
|
||||
return(lStatus == noErr);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2001
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
@@ -33,29 +33,30 @@ struct startup_time_info
|
||||
{
|
||||
startup_time_info()
|
||||
{
|
||||
// 1970 Jan 1 at 00:00:00
|
||||
// 1970 Jan 1 at 00:00:00
|
||||
static const DateTimeRec k_sUNIXBase = {1970, 1, 1, 0, 0, 0, 0};
|
||||
static unsigned long s_ulUNIXBaseSeconds = 0UL;
|
||||
|
||||
if(s_ulUNIXBaseSeconds == 0UL)
|
||||
{
|
||||
// calculate the number of seconds between the Mac OS base and the UNIX base
|
||||
// the first time we enter this constructor.
|
||||
// calculate the number of seconds between the Mac OS base and the
|
||||
// UNIX base the first time we enter this constructor.
|
||||
DateToSeconds(&k_sUNIXBase, &s_ulUNIXBaseSeconds);
|
||||
}
|
||||
|
||||
unsigned long ulSeconds;
|
||||
|
||||
// get the time in UpTime units twice, with the time in seconds in the middle.
|
||||
// get the time in UpTime units twice, with the time in seconds in the
|
||||
// middle.
|
||||
uint64_t ullFirstUpTime = force_cast<uint64_t>(UpTime());
|
||||
GetDateTime(&ulSeconds);
|
||||
uint64_t ullSecondUpTime = force_cast<uint64_t>(UpTime());
|
||||
|
||||
// calculate the midpoint of the two UpTimes, and save that.
|
||||
// calculate the midpoint of the two UpTimes, and save that.
|
||||
uint64_t ullAverageUpTime = (ullFirstUpTime + ullSecondUpTime) / 2ULL;
|
||||
m_sStartupAbsoluteTime = force_cast<AbsoluteTime>(ullAverageUpTime);
|
||||
|
||||
// save the number of seconds, recentered at the UNIX base.
|
||||
// save the number of seconds, recentered at the UNIX base.
|
||||
m_ulStartupSeconds = ulSeconds - s_ulUNIXBaseSeconds;
|
||||
}
|
||||
|
||||
@@ -77,10 +78,13 @@ int xtime_get(struct xtime* xtp, int clock_type)
|
||||
#if defined(BOOST_HAS_FTIME)
|
||||
FILETIME ft;
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
const boost::uint64_t TIMESPEC_TO_FILETIME_OFFSET = ((boost::uint64_t)27111902UL << 32) + (boost::uint64_t)3577643008UL;
|
||||
xtp->sec = (int)((*(__int64*)&ft - TIMESPEC_TO_FILETIME_OFFSET) / 10000000);
|
||||
const boost::uint64_t TIMESPEC_TO_FILETIME_OFFSET =
|
||||
((boost::uint64_t)27111902UL << 32) +
|
||||
(boost::uint64_t)3577643008UL;
|
||||
xtp->sec = (int)((*(__int64*)&ft - TIMESPEC_TO_FILETIME_OFFSET) /
|
||||
10000000);
|
||||
xtp->nsec = (int)((*(__int64*)&ft - TIMESPEC_TO_FILETIME_OFFSET -
|
||||
((__int64)xtp->sec * (__int64)10000000)) * 100);
|
||||
((__int64)xtp->sec * (__int64)10000000)) * 100);
|
||||
return clock_type;
|
||||
#elif defined(BOOST_HAS_GETTIMEOFDAY)
|
||||
struct timeval tv;
|
||||
@@ -96,12 +100,16 @@ int xtime_get(struct xtime* xtp, int clock_type)
|
||||
return clock_type;
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
using detail::thread::force_cast;
|
||||
// the Mac OS does not have an MP-safe way of getting the date/time, so we use a
|
||||
// delta from the startup time. We _could_ defer this and use something that is
|
||||
// interrupt-safe, but this would be _SLOW_, and we need speed here.
|
||||
// the Mac OS does not have an MP-safe way of getting the date/time,
|
||||
// so we use a delta from the startup time. We _could_ defer this
|
||||
// and use something that is interrupt-safe, but this would be _SLOW_,
|
||||
// and we need speed here.
|
||||
const uint64_t k_ullNanosecondsPerSecond(1000ULL * 1000ULL * 1000ULL);
|
||||
AbsoluteTime sUpTime(UpTime());
|
||||
uint64_t ullNanoseconds(force_cast<uint64_t>(AbsoluteDeltaToNanoseconds(sUpTime, detail::g_sStartupTimeInfo.m_sStartupAbsoluteTime)));
|
||||
uint64_t ullNanoseconds(
|
||||
force_cast<uint64_t>(
|
||||
AbsoluteDeltaToNanoseconds(sUpTime,
|
||||
detail::g_sStartupTimeInfo.m_sStartupAbsoluteTime)));
|
||||
uint64_t ullSeconds = (ullNanoseconds / k_ullNanosecondsPerSecond);
|
||||
ullNanoseconds -= (ullSeconds * k_ullNanosecondsPerSecond);
|
||||
xtp->sec = detail::g_sStartupTimeInfo.m_ulStartupSeconds + ullSeconds;
|
||||
|
||||
58
test/Jamfile
58
test/Jamfile
@@ -1,12 +1,10 @@
|
||||
# (C) Copyright William E. Kempf 2001. Permission to copy, use, modify, sell and
|
||||
# distribute this software is granted provided this copyright notice appears
|
||||
# in all copies. This software is provided "as is" without express or implied
|
||||
# warranty, and with no claim as to its suitability for any purpose.
|
||||
# (C) Copyright William E. Kempf 2001. Permission to copy, use, modify, sell
|
||||
# and distribute this software is granted provided this copyright notice
|
||||
# appears in all copies. This software is provided "as is" without express or
|
||||
# implied warranty, and with no claim as to its suitability for any purpose.
|
||||
#
|
||||
# Boost.Threads test Jamfile
|
||||
#
|
||||
# Declares the following targets:
|
||||
# 1. test_thread, a unit test executable.
|
||||
# Additional configuration variables used:
|
||||
# 1. PTW32 may be used on Win32 platforms to specify that the pthreads-win32
|
||||
# library should be used instead of "native" threads. This feature is
|
||||
@@ -23,33 +21,29 @@ subproject libs/thread/test ;
|
||||
# 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 threads.jam = $(BOOST_ROOT)/libs/thread/build ;
|
||||
include threads.jam ;
|
||||
import ../build/threads ;
|
||||
|
||||
# bring in rules for testing
|
||||
SEARCH on testing.jam = $(BOOST_BUILD_PATH) ;
|
||||
include testing.jam ;
|
||||
import testing ;
|
||||
|
||||
sources = test.cpp test_thread.cpp test_mutex.cpp test_condition.cpp test_tss.cpp test_once.cpp ;
|
||||
{
|
||||
template test
|
||||
## sources ##
|
||||
: <template>thread_base
|
||||
<dll>../build/boost_thread
|
||||
<lib>../../test/build/boost_unit_test_framework
|
||||
## requirements ##
|
||||
:
|
||||
## default build ##
|
||||
:
|
||||
;
|
||||
|
||||
template test
|
||||
## sources ##
|
||||
: <template>thread_base
|
||||
<dll>../build/boost_thread
|
||||
<lib>../../test/build/boost_unit_test_framework
|
||||
$(threadmon)
|
||||
## requirements ##
|
||||
:
|
||||
## default build ##
|
||||
: debug release <runtime-link>static/dynamic
|
||||
;
|
||||
|
||||
#######################
|
||||
# Declare the Boost.Threads unit test program test_thread.
|
||||
|
||||
run test_thread.cpp <template>test ;
|
||||
run test_mutex.cpp <template>test ;
|
||||
run test_condition.cpp <template>test ;
|
||||
run test_tss.cpp <template>test ;
|
||||
run test_once.cpp <template>test ;
|
||||
run test_xtime.cpp <template>test ;
|
||||
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 ]
|
||||
;
|
||||
}
|
||||
|
||||
35
test/Jamfile.v2
Normal file
35
test/Jamfile.v2
Normal file
@@ -0,0 +1,35 @@
|
||||
# (C) Copyright William E. Kempf 2001. Permission to copy, use, modify, sell
|
||||
# and distribute this software is granted provided this copyright notice
|
||||
# appears in all copies. This software is provided "as is" without express or
|
||||
# implied warranty, and with no claim as to its suitability for any purpose.
|
||||
#
|
||||
# Boost.Threads test Jamfile
|
||||
#
|
||||
# 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"
|
||||
|
||||
# bring in rules for testing
|
||||
import testing ;
|
||||
|
||||
project
|
||||
: requirements <library>../build//boost_thread
|
||||
<library>../../test/build//boost_unit_test_framework
|
||||
<threading>multi
|
||||
;
|
||||
{
|
||||
test-suite "threads"
|
||||
: [ run test_thread.cpp ]
|
||||
[ run test_mutex.cpp ]
|
||||
[ run test_condition.cpp ]
|
||||
[ run test_tss.cpp ]
|
||||
[ run test_once.cpp ]
|
||||
[ run test_xtime.cpp ]
|
||||
;
|
||||
}
|
||||
@@ -1,103 +1,97 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <boost/thread/condition.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
namespace
|
||||
#include "util.inl"
|
||||
|
||||
struct condition_test_data
|
||||
{
|
||||
struct condition_test_data
|
||||
{
|
||||
condition_test_data() : notified(0), awoken(0) { }
|
||||
condition_test_data() : notified(0), awoken(0) { }
|
||||
|
||||
boost::mutex mutex;
|
||||
boost::condition condition;
|
||||
int notified;
|
||||
int awoken;
|
||||
};
|
||||
boost::mutex mutex;
|
||||
boost::condition condition;
|
||||
int notified;
|
||||
int awoken;
|
||||
};
|
||||
|
||||
void condition_test_thread(void* param)
|
||||
{
|
||||
condition_test_data* data = static_cast<condition_test_data*>(param);
|
||||
boost::mutex::scoped_lock lock(data->mutex);
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
while (!(data->notified > 0))
|
||||
data->condition.wait(lock);
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
data->awoken++;
|
||||
}
|
||||
|
||||
class thread_adapter
|
||||
{
|
||||
public:
|
||||
thread_adapter(void (*func)(void*), void* param) : _func(func), _param(param) { }
|
||||
void operator()() const { _func(_param); }
|
||||
private:
|
||||
void (*_func)(void*);
|
||||
void* _param;
|
||||
};
|
||||
|
||||
struct cond_predicate
|
||||
{
|
||||
cond_predicate(int& var, int val) : _var(var), _val(val) { }
|
||||
|
||||
bool operator()() { return _var == _val; }
|
||||
|
||||
int& _var;
|
||||
int _val;
|
||||
};
|
||||
|
||||
void condition_test_waits(void* param)
|
||||
{
|
||||
condition_test_data* data = static_cast<condition_test_data*>(param);
|
||||
|
||||
boost::mutex::scoped_lock lock(data->mutex);
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
|
||||
// Test wait.
|
||||
while (data->notified != 1)
|
||||
data->condition.wait(lock);
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
BOOST_CHECK_EQUAL(data->notified, 1);
|
||||
data->awoken++;
|
||||
data->condition.notify_one();
|
||||
|
||||
// Test predicate wait.
|
||||
data->condition.wait(lock, cond_predicate(data->notified, 2));
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
BOOST_CHECK_EQUAL(data->notified, 2);
|
||||
data->awoken++;
|
||||
data->condition.notify_one();
|
||||
|
||||
// Test timed_wait.
|
||||
boost::xtime xt;
|
||||
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
|
||||
xt.sec += 10;
|
||||
while (data->notified != 3)
|
||||
data->condition.timed_wait(lock, xt);
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
BOOST_CHECK_EQUAL(data->notified, 3);
|
||||
data->awoken++;
|
||||
data->condition.notify_one();
|
||||
|
||||
// Test predicate timed_wait.
|
||||
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
|
||||
xt.sec += 10;
|
||||
cond_predicate pred(data->notified, 4);
|
||||
BOOST_CHECK(data->condition.timed_wait(lock, xt, pred));
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
BOOST_CHECK(pred());
|
||||
BOOST_CHECK_EQUAL(data->notified, 4);
|
||||
data->awoken++;
|
||||
data->condition.notify_one();
|
||||
}
|
||||
void condition_test_thread(condition_test_data* data)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(data->mutex);
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
while (!(data->notified > 0))
|
||||
data->condition.wait(lock);
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
data->awoken++;
|
||||
}
|
||||
|
||||
void test_condition_notify_one()
|
||||
struct cond_predicate
|
||||
{
|
||||
cond_predicate(int& var, int val) : _var(var), _val(val) { }
|
||||
|
||||
bool operator()() { return _var == _val; }
|
||||
|
||||
int& _var;
|
||||
int _val;
|
||||
};
|
||||
|
||||
void condition_test_waits(condition_test_data* data)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(data->mutex);
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
|
||||
// Test wait.
|
||||
while (data->notified != 1)
|
||||
data->condition.wait(lock);
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
BOOST_CHECK_EQUAL(data->notified, 1);
|
||||
data->awoken++;
|
||||
data->condition.notify_one();
|
||||
|
||||
// Test predicate wait.
|
||||
data->condition.wait(lock, cond_predicate(data->notified, 2));
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
BOOST_CHECK_EQUAL(data->notified, 2);
|
||||
data->awoken++;
|
||||
data->condition.notify_one();
|
||||
|
||||
// Test timed_wait.
|
||||
boost::xtime xt = delay(10);
|
||||
while (data->notified != 3)
|
||||
data->condition.timed_wait(lock, xt);
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
BOOST_CHECK_EQUAL(data->notified, 3);
|
||||
data->awoken++;
|
||||
data->condition.notify_one();
|
||||
|
||||
// Test predicate timed_wait.
|
||||
xt = delay(10);
|
||||
cond_predicate pred(data->notified, 4);
|
||||
BOOST_CHECK(data->condition.timed_wait(lock, xt, pred));
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
BOOST_CHECK(pred());
|
||||
BOOST_CHECK_EQUAL(data->notified, 4);
|
||||
data->awoken++;
|
||||
data->condition.notify_one();
|
||||
}
|
||||
|
||||
void do_test_condition_notify_one()
|
||||
{
|
||||
condition_test_data data;
|
||||
|
||||
boost::thread thread(thread_adapter(&condition_test_thread, &data));
|
||||
boost::thread thread(bind(&condition_test_thread, &data));
|
||||
|
||||
{
|
||||
boost::mutex::scoped_lock lock(data.mutex);
|
||||
@@ -110,14 +104,19 @@ void test_condition_notify_one()
|
||||
BOOST_CHECK_EQUAL(data.awoken, 1);
|
||||
}
|
||||
|
||||
void test_condition_notify_all()
|
||||
void test_condition_notify_one()
|
||||
{
|
||||
timed_test(&do_test_condition_notify_one, 2, execution_monitor::use_mutex);
|
||||
}
|
||||
|
||||
void do_test_condition_notify_all()
|
||||
{
|
||||
const int NUMTHREADS = 5;
|
||||
boost::thread_group threads;
|
||||
condition_test_data data;
|
||||
|
||||
for (int i = 0; i < NUMTHREADS; ++i)
|
||||
threads.create_thread(thread_adapter(&condition_test_thread, &data));
|
||||
threads.create_thread(bind(&condition_test_thread, &data));
|
||||
|
||||
{
|
||||
boost::mutex::scoped_lock lock(data.mutex);
|
||||
@@ -130,21 +129,25 @@ void test_condition_notify_all()
|
||||
BOOST_CHECK_EQUAL(data.awoken, NUMTHREADS);
|
||||
}
|
||||
|
||||
void test_condition_waits()
|
||||
void test_condition_notify_all()
|
||||
{
|
||||
// We should have already tested notify_one here, so
|
||||
// a timed test with the default execution_monitor::use_condition
|
||||
// should be OK, and gives the fastest performance
|
||||
timed_test(&do_test_condition_notify_all, 3);
|
||||
}
|
||||
|
||||
void do_test_condition_waits()
|
||||
{
|
||||
condition_test_data data;
|
||||
|
||||
boost::thread thread(thread_adapter(&condition_test_waits, &data));
|
||||
|
||||
boost::xtime xt;
|
||||
boost::thread thread(bind(&condition_test_waits, &data));
|
||||
|
||||
{
|
||||
boost::mutex::scoped_lock lock(data.mutex);
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
|
||||
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
|
||||
xt.sec += 1;
|
||||
boost::thread::sleep(xt);
|
||||
boost::thread::sleep(delay(1));
|
||||
data.notified++;
|
||||
data.condition.notify_one();
|
||||
while (data.awoken != 1)
|
||||
@@ -152,9 +155,7 @@ void test_condition_waits()
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
BOOST_CHECK_EQUAL(data.awoken, 1);
|
||||
|
||||
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
|
||||
xt.sec += 1;
|
||||
boost::thread::sleep(xt);
|
||||
boost::thread::sleep(delay(1));
|
||||
data.notified++;
|
||||
data.condition.notify_one();
|
||||
while (data.awoken != 2)
|
||||
@@ -162,9 +163,7 @@ void test_condition_waits()
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
BOOST_CHECK_EQUAL(data.awoken, 2);
|
||||
|
||||
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
|
||||
xt.sec += 1;
|
||||
boost::thread::sleep(xt);
|
||||
boost::thread::sleep(delay(1));
|
||||
data.notified++;
|
||||
data.condition.notify_one();
|
||||
while (data.awoken != 3)
|
||||
@@ -172,9 +171,7 @@ void test_condition_waits()
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
BOOST_CHECK_EQUAL(data.awoken, 3);
|
||||
|
||||
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
|
||||
xt.sec += 1;
|
||||
boost::thread::sleep(xt);
|
||||
boost::thread::sleep(delay(1));
|
||||
data.notified++;
|
||||
data.condition.notify_one();
|
||||
while (data.awoken != 4)
|
||||
@@ -183,16 +180,22 @@ void test_condition_waits()
|
||||
BOOST_CHECK_EQUAL(data.awoken, 4);
|
||||
}
|
||||
|
||||
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
|
||||
xt.sec += 1;
|
||||
boost::thread::sleep(xt);
|
||||
thread.join();
|
||||
BOOST_CHECK_EQUAL(data.awoken, 4);
|
||||
}
|
||||
|
||||
void test_condition_waits()
|
||||
{
|
||||
// We should have already tested notify_one here, so
|
||||
// a timed test with the default execution_monitor::use_condition
|
||||
// should be OK, and gives the fastest performance
|
||||
timed_test(&do_test_condition_waits, 12);
|
||||
}
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test = BOOST_TEST_SUITE("Boost.Threads: condition test suite");
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: condition test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(&test_condition_notify_one));
|
||||
test->add(BOOST_TEST_CASE(&test_condition_notify_all));
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
@@ -6,22 +17,8 @@
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/test/unit_test_suite_ex.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
inline bool xtime_in_range(boost::xtime& xt, int less_seconds, int greater_seconds)
|
||||
{
|
||||
boost::xtime cur;
|
||||
BOOST_CHECK_EQUAL(boost::xtime_get(&cur, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
|
||||
|
||||
boost::xtime less = cur;
|
||||
less.sec += less_seconds;
|
||||
|
||||
boost::xtime greater = cur;
|
||||
greater.sec += greater_seconds;
|
||||
|
||||
return (boost::xtime_cmp(xt, less) >= 0) && (boost::xtime_cmp(xt, greater) <= 0);
|
||||
}
|
||||
}
|
||||
#define DEFAULT_EXECUTION_MONITOR_TYPE execution_monitor::use_sleep_only
|
||||
#include "util.inl"
|
||||
|
||||
template <typename M>
|
||||
struct test_lock
|
||||
@@ -43,9 +40,7 @@ struct test_lock
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
|
||||
// Construct and initialize an xtime for a fast time out.
|
||||
boost::xtime xt;
|
||||
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
|
||||
xt.nsec += 100000000;
|
||||
boost::xtime xt = delay(0, 100);
|
||||
|
||||
// Test the lock and the mutex with condition variables.
|
||||
// No one is going to notify this condition variable. We expect to
|
||||
@@ -85,9 +80,7 @@ struct test_trylock
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
|
||||
// Construct and initialize an xtime for a fast time out.
|
||||
boost::xtime xt;
|
||||
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
|
||||
xt.nsec += 100000000;
|
||||
boost::xtime xt = delay(0, 100);
|
||||
|
||||
// Test the lock and the mutex with condition variables.
|
||||
// No one is going to notify this condition variable. We expect to
|
||||
@@ -121,9 +114,7 @@ struct test_timedlock
|
||||
// Test the lock's constructors.
|
||||
{
|
||||
// Construct and initialize an xtime for a fast time out.
|
||||
boost::xtime xt;
|
||||
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
|
||||
xt.nsec += 100000000;
|
||||
boost::xtime xt = delay(0, 100);
|
||||
|
||||
timed_lock_type lock(mutex, xt);
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
@@ -136,16 +127,14 @@ struct test_timedlock
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
|
||||
// Construct and initialize an xtime for a fast time out.
|
||||
boost::xtime xt;
|
||||
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
|
||||
xt.nsec += 100000000;
|
||||
boost::xtime xt = delay(0, 100);
|
||||
|
||||
// Test the lock and the mutex with condition variables.
|
||||
// No one is going to notify this condition variable. We expect to
|
||||
// time out.
|
||||
BOOST_CHECK(!condition.timed_wait(lock, xt));
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
BOOST_CHECK(xtime_in_range(xt, -1, 0));
|
||||
BOOST_CHECK(in_range(xt));
|
||||
|
||||
// Test the lock, unlock and timedlock methods.
|
||||
lock.unlock();
|
||||
@@ -154,8 +143,7 @@ struct test_timedlock
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
lock.unlock();
|
||||
BOOST_CHECK(!lock);
|
||||
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
|
||||
xt.nsec += 100000000;
|
||||
xt = delay(0, 100);
|
||||
BOOST_CHECK(lock.timed_lock(xt));
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
}
|
||||
@@ -175,38 +163,63 @@ struct test_recursive_lock
|
||||
}
|
||||
};
|
||||
|
||||
void test_mutex()
|
||||
void do_test_mutex()
|
||||
{
|
||||
test_lock<boost::mutex>()();
|
||||
}
|
||||
|
||||
void test_try_mutex()
|
||||
void test_mutex()
|
||||
{
|
||||
timed_test(&do_test_mutex, 3);
|
||||
}
|
||||
|
||||
void do_test_try_mutex()
|
||||
{
|
||||
test_lock<boost::try_mutex>()();
|
||||
test_trylock<boost::try_mutex>()();
|
||||
}
|
||||
|
||||
void test_timed_mutex()
|
||||
void test_try_mutex()
|
||||
{
|
||||
timed_test(&do_test_try_mutex, 3);
|
||||
}
|
||||
|
||||
void do_test_timed_mutex()
|
||||
{
|
||||
test_lock<boost::timed_mutex>()();
|
||||
test_trylock<boost::timed_mutex>()();
|
||||
test_timedlock<boost::timed_mutex>()();
|
||||
}
|
||||
|
||||
void test_recursive_mutex()
|
||||
void test_timed_mutex()
|
||||
{
|
||||
timed_test(&do_test_timed_mutex, 3);
|
||||
}
|
||||
|
||||
void do_test_recursive_mutex()
|
||||
{
|
||||
test_lock<boost::recursive_mutex>()();
|
||||
test_recursive_lock<boost::recursive_mutex>()();
|
||||
}
|
||||
|
||||
void test_recursive_try_mutex()
|
||||
void test_recursive_mutex()
|
||||
{
|
||||
timed_test(&do_test_recursive_mutex, 3);
|
||||
}
|
||||
|
||||
void do_test_recursive_try_mutex()
|
||||
{
|
||||
test_lock<boost::recursive_try_mutex>()();
|
||||
test_trylock<boost::recursive_try_mutex>()();
|
||||
test_recursive_lock<boost::recursive_try_mutex>()();
|
||||
}
|
||||
|
||||
void test_recursive_timed_mutex()
|
||||
void test_recursive_try_mutex()
|
||||
{
|
||||
timed_test(&do_test_recursive_try_mutex, 3);
|
||||
}
|
||||
|
||||
void do_test_recursive_timed_mutex()
|
||||
{
|
||||
test_lock<boost::recursive_timed_mutex>()();
|
||||
test_trylock<boost::recursive_timed_mutex>()();
|
||||
@@ -214,9 +227,15 @@ void test_recursive_timed_mutex()
|
||||
test_recursive_lock<boost::recursive_timed_mutex>()();
|
||||
}
|
||||
|
||||
void test_recursive_timed_mutex()
|
||||
{
|
||||
timed_test(&do_test_recursive_timed_mutex, 3);
|
||||
}
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test = BOOST_TEST_SUITE("Boost.Threads: mutex test suite");
|
||||
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));
|
||||
|
||||
@@ -1,25 +1,35 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <boost/thread/once.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
namespace
|
||||
#include "util.inl"
|
||||
|
||||
int once_value = 0;
|
||||
boost::once_flag once = BOOST_ONCE_INIT;
|
||||
|
||||
void init_once_value()
|
||||
{
|
||||
int once_value = 0;
|
||||
boost::once_flag once = BOOST_ONCE_INIT;
|
||||
|
||||
void init_once_value()
|
||||
{
|
||||
once_value++;
|
||||
}
|
||||
|
||||
void test_once_thread()
|
||||
{
|
||||
boost::call_once(init_once_value, once);
|
||||
}
|
||||
once_value++;
|
||||
}
|
||||
|
||||
void test_once()
|
||||
void test_once_thread()
|
||||
{
|
||||
boost::call_once(init_once_value, once);
|
||||
}
|
||||
|
||||
void do_test_once()
|
||||
{
|
||||
const int NUMTHREADS=5;
|
||||
boost::thread_group threads;
|
||||
@@ -29,9 +39,15 @@ void test_once()
|
||||
BOOST_CHECK_EQUAL(once_value, 1);
|
||||
}
|
||||
|
||||
void test_once()
|
||||
{
|
||||
timed_test(&do_test_once, 2);
|
||||
}
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test = BOOST_TEST_SUITE("Boost.Threads: once test suite");
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: once test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(test_once));
|
||||
|
||||
|
||||
@@ -1,68 +1,47 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
namespace
|
||||
#define DEFAULT_EXECUTION_MONITOR_TYPE execution_monitor::use_sleep_only
|
||||
#include "util.inl"
|
||||
|
||||
int test_value;
|
||||
|
||||
void simple_thread()
|
||||
{
|
||||
inline bool xtime_in_range(boost::xtime& xt, int less_seconds, int greater_seconds)
|
||||
{
|
||||
boost::xtime cur;
|
||||
BOOST_CHECK_EQUAL(boost::xtime_get(&cur, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
|
||||
test_value = 999;
|
||||
}
|
||||
|
||||
boost::xtime less = cur;
|
||||
less.sec += less_seconds;
|
||||
|
||||
boost::xtime greater = cur;
|
||||
greater.sec += greater_seconds;
|
||||
|
||||
return (boost::xtime_cmp(xt, less) >= 0) && (boost::xtime_cmp(xt, greater) <= 0);
|
||||
}
|
||||
|
||||
int test_value;
|
||||
|
||||
void simple_thread()
|
||||
{
|
||||
test_value = 999;
|
||||
}
|
||||
|
||||
struct thread_adapter
|
||||
{
|
||||
thread_adapter(void (*func)(boost::thread& parent), boost::thread& parent)
|
||||
: func(func), parent(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void operator()()
|
||||
{
|
||||
(*func)(parent);
|
||||
}
|
||||
|
||||
void (*func)(boost::thread& parent);
|
||||
boost::thread& parent;
|
||||
};
|
||||
|
||||
void comparison_thread(boost::thread& parent)
|
||||
{
|
||||
boost::thread thrd;
|
||||
BOOST_TEST(thrd != parent);
|
||||
BOOST_TEST(thrd == boost::thread());
|
||||
}
|
||||
void comparison_thread(boost::thread* parent)
|
||||
{
|
||||
boost::thread thrd;
|
||||
BOOST_TEST(thrd != *parent);
|
||||
BOOST_TEST(thrd == boost::thread());
|
||||
}
|
||||
|
||||
void test_sleep()
|
||||
{
|
||||
boost::xtime xt;
|
||||
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
|
||||
xt.sec += 3;
|
||||
|
||||
boost::xtime xt = delay(3);
|
||||
boost::thread::sleep(xt);
|
||||
|
||||
// Insure it's in a range instead of checking actual equality due to time lapse
|
||||
BOOST_CHECK(xtime_in_range(xt, -1, 0));
|
||||
// Ensure it's in a range instead of checking actual equality due to time
|
||||
// lapse
|
||||
BOOST_CHECK(in_range(xt));
|
||||
}
|
||||
|
||||
void test_creation()
|
||||
void do_test_creation()
|
||||
{
|
||||
test_value = 0;
|
||||
boost::thread thrd(&simple_thread);
|
||||
@@ -70,16 +49,27 @@ void test_creation()
|
||||
BOOST_CHECK_EQUAL(test_value, 999);
|
||||
}
|
||||
|
||||
void test_comparison()
|
||||
void test_creation()
|
||||
{
|
||||
timed_test(&do_test_creation, 1);
|
||||
}
|
||||
|
||||
void do_test_comparison()
|
||||
{
|
||||
boost::thread self;
|
||||
boost::thread thrd(thread_adapter(comparison_thread, self));
|
||||
boost::thread thrd(bind(&comparison_thread, &self));
|
||||
thrd.join();
|
||||
}
|
||||
|
||||
void test_comparison()
|
||||
{
|
||||
timed_test(&do_test_comparison, 1);
|
||||
}
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test = BOOST_TEST_SUITE("Boost.Threads: thread test suite");
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: thread test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(test_sleep));
|
||||
test->add(BOOST_TEST_CASE(test_creation));
|
||||
|
||||
@@ -1,45 +1,62 @@
|
||||
// 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/mutex.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
namespace
|
||||
#include "util.inl"
|
||||
|
||||
boost::mutex check_mutex;
|
||||
boost::mutex tss_mutex;
|
||||
int tss_instances = 0;
|
||||
|
||||
struct tss_value_t
|
||||
{
|
||||
boost::mutex tss_mutex;
|
||||
int tss_instances = 0;
|
||||
|
||||
struct tss_value_t
|
||||
tss_value_t()
|
||||
{
|
||||
tss_value_t()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(tss_mutex);
|
||||
++tss_instances;
|
||||
value = 0;
|
||||
}
|
||||
~tss_value_t()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(tss_mutex);
|
||||
--tss_instances;
|
||||
}
|
||||
int value;
|
||||
};
|
||||
|
||||
boost::thread_specific_ptr<tss_value_t> tss_value;
|
||||
|
||||
void test_tss_thread()
|
||||
boost::mutex::scoped_lock lock(tss_mutex);
|
||||
++tss_instances;
|
||||
value = 0;
|
||||
}
|
||||
~tss_value_t()
|
||||
{
|
||||
tss_value.reset(new tss_value_t());
|
||||
for (int i=0; i<1000; ++i)
|
||||
boost::mutex::scoped_lock lock(tss_mutex);
|
||||
--tss_instances;
|
||||
}
|
||||
int value;
|
||||
};
|
||||
|
||||
boost::thread_specific_ptr<tss_value_t> tss_value;
|
||||
|
||||
void test_tss_thread()
|
||||
{
|
||||
tss_value.reset(new tss_value_t());
|
||||
for (int i=0; i<1000; ++i)
|
||||
{
|
||||
int& n = tss_value->value;
|
||||
// Don't call BOOST_CHECK_EQUAL directly, as it doesn't appear to
|
||||
// be thread safe. Must evaluate further.
|
||||
if (n != i)
|
||||
{
|
||||
int& n = tss_value->value;
|
||||
boost::mutex::scoped_lock lock(check_mutex);
|
||||
BOOST_CHECK_EQUAL(n, i);
|
||||
++n;
|
||||
}
|
||||
++n;
|
||||
}
|
||||
}
|
||||
|
||||
void test_tss()
|
||||
void do_test_tss()
|
||||
{
|
||||
const int NUMTHREADS=5;
|
||||
boost::thread_group threads;
|
||||
@@ -49,9 +66,15 @@ void test_tss()
|
||||
BOOST_CHECK_EQUAL(tss_instances, 0);
|
||||
}
|
||||
|
||||
void test_tss()
|
||||
{
|
||||
timed_test(&do_test_tss, 2);
|
||||
}
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test = BOOST_TEST_SUITE("Boost.Threads: tss test suite");
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: tss test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(test_tss));
|
||||
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <boost/thread/xtime.hpp>
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
@@ -5,7 +16,9 @@
|
||||
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));
|
||||
BOOST_CHECK_EQUAL(
|
||||
boost::xtime_get(&cur, boost::TIME_UTC),
|
||||
static_cast<int>(boost::TIME_UTC));
|
||||
|
||||
xt1 = xt2 = cur;
|
||||
xt1.nsec -= 1;
|
||||
@@ -27,12 +40,16 @@ void test_xtime_cmp()
|
||||
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));
|
||||
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_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;
|
||||
@@ -41,7 +58,8 @@ void test_xtime_get()
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test = BOOST_TEST_SUITE("Boost.Threads: xtime test suite");
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: xtime test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(&test_xtime_cmp));
|
||||
test->add(BOOST_TEST_CASE(&test_xtime_get));
|
||||
|
||||
162
test/util.inl
Normal file
162
test/util.inl
Normal file
@@ -0,0 +1,162 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#if !defined(UTIL_INL_WEK01242003)
|
||||
#define UTIL_INL_WEK01242003
|
||||
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/condition.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
#ifndef DEFAULT_EXECUTION_MONITOR_TYPE
|
||||
# define DEFAULT_EXECUTION_MONITOR_TYPE execution_monitor::use_condition
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
inline boost::xtime delay(int secs, int msecs=0, int nsecs=0)
|
||||
{
|
||||
const int MILLISECONDS_PER_SECOND = 1000;
|
||||
const int NANOSECONDS_PER_SECOND = 1000000000;
|
||||
const int NANOSECONDS_PER_MILLISECOND = 1000000;
|
||||
|
||||
boost::xtime xt;
|
||||
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC),
|
||||
static_cast<int>(boost::TIME_UTC));
|
||||
|
||||
nsecs += xt.nsec;
|
||||
msecs += nsecs / NANOSECONDS_PER_MILLISECOND;
|
||||
secs += msecs / MILLISECONDS_PER_SECOND;
|
||||
nsecs += (msecs % MILLISECONDS_PER_SECOND) * NANOSECONDS_PER_MILLISECOND;
|
||||
xt.nsec = nsecs % NANOSECONDS_PER_SECOND;
|
||||
xt.sec += secs + (nsecs / NANOSECONDS_PER_SECOND);
|
||||
|
||||
return xt;
|
||||
}
|
||||
|
||||
inline bool in_range(const boost::xtime& xt, int secs=1)
|
||||
{
|
||||
boost::xtime min = delay(-secs);
|
||||
boost::xtime max = delay(0);
|
||||
return (boost::xtime_cmp(xt, min) >= 0) &&
|
||||
(boost::xtime_cmp(xt, max) <= 0);
|
||||
}
|
||||
|
||||
class execution_monitor
|
||||
{
|
||||
public:
|
||||
enum wait_type { use_sleep_only, use_mutex, use_condition };
|
||||
|
||||
execution_monitor(wait_type type, int secs)
|
||||
: done(false), type(type), secs(secs) { }
|
||||
void start()
|
||||
{
|
||||
if (type != use_sleep_only) {
|
||||
boost::mutex::scoped_lock lock(mutex); done = false;
|
||||
} else {
|
||||
done = false;
|
||||
}
|
||||
}
|
||||
void finish()
|
||||
{
|
||||
if (type != use_sleep_only) {
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
done = true;
|
||||
if (type == use_condition)
|
||||
cond.notify_one();
|
||||
} else {
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
bool wait()
|
||||
{
|
||||
boost::xtime xt = delay(secs);
|
||||
if (type != use_condition)
|
||||
boost::thread::sleep(xt);
|
||||
if (type != use_sleep_only) {
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
while (type == use_condition && !done) {
|
||||
if (!cond.timed_wait(lock, xt))
|
||||
break;
|
||||
}
|
||||
return done;
|
||||
}
|
||||
return done;
|
||||
}
|
||||
|
||||
private:
|
||||
boost::mutex mutex;
|
||||
boost::condition cond;
|
||||
bool done;
|
||||
wait_type type;
|
||||
int secs;
|
||||
};
|
||||
|
||||
template <typename F>
|
||||
class indirect_adapter
|
||||
{
|
||||
public:
|
||||
indirect_adapter(F func, execution_monitor& monitor)
|
||||
: func(func), monitor(monitor) { }
|
||||
void operator()() const
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::thread thrd(func);
|
||||
thrd.join();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
monitor.finish();
|
||||
throw;
|
||||
}
|
||||
monitor.finish();
|
||||
}
|
||||
|
||||
private:
|
||||
F func;
|
||||
execution_monitor& monitor;
|
||||
};
|
||||
|
||||
template <typename F>
|
||||
void timed_test(F func, int secs,
|
||||
execution_monitor::wait_type type=DEFAULT_EXECUTION_MONITOR_TYPE)
|
||||
{
|
||||
execution_monitor monitor(type, secs);
|
||||
indirect_adapter<F> ifunc(func, monitor);
|
||||
monitor.start();
|
||||
boost::thread thrd(ifunc);
|
||||
BOOST_REQUIRE_MESSAGE(monitor.wait(),
|
||||
"Timed test didn't complete in time, possible deadlock.");
|
||||
}
|
||||
|
||||
template <typename F, typename T>
|
||||
class binder
|
||||
{
|
||||
public:
|
||||
binder(const F& func, const T& param)
|
||||
: func(func), param(param) { }
|
||||
void operator()() const { func(param); }
|
||||
|
||||
private:
|
||||
F func;
|
||||
T param;
|
||||
};
|
||||
|
||||
template <typename F, typename T>
|
||||
binder<F, T> bind(const F& func, const T& param)
|
||||
{
|
||||
return binder<F, T>(func, param);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
#endif
|
||||
@@ -1,8 +1,19 @@
|
||||
# (C) Copyright William E. Kempf 2001. Permission to copy, use, modify, sell and
|
||||
# distribute this software is granted provided this copyright notice appears
|
||||
# in all copies. This software is provided "as is" without express or implied
|
||||
# warranty, and with no claim as to its suitability for any purpose.
|
||||
# (C) Copyright William E. Kempf 2001. Permission to copy, use, modify, sell
|
||||
# and distribute this software is granted provided this copyright notice
|
||||
# appears in all copies. This software is provided "as is" without express or
|
||||
# implied warranty, and with no claim as to its suitability for any purpose.
|
||||
#
|
||||
# Boost.Threads 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.
|
||||
|
||||
@@ -11,25 +22,27 @@ 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 ;
|
||||
import ../build/threads ;
|
||||
|
||||
template tutorial
|
||||
## sources ##
|
||||
: <template>thread_base <lib>../build/boost_thread <lib>../../test/build/unit_test_framework $(threadmon)
|
||||
## requirements ##
|
||||
:
|
||||
## default build ##
|
||||
: release <runtime-link>static
|
||||
;
|
||||
{
|
||||
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 ;
|
||||
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 ;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <boost/thread/condition.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
@@ -39,9 +50,9 @@ bounded_buffer buf(2);
|
||||
void sender() {
|
||||
int n = 0;
|
||||
while (n < 100) {
|
||||
buf.send(n);
|
||||
std::cout << "sent: " << n << std::endl;
|
||||
++n;
|
||||
buf.send(n);
|
||||
std::cout << "sent: " << n << std::endl;
|
||||
++n;
|
||||
}
|
||||
buf.send(-1);
|
||||
}
|
||||
@@ -49,8 +60,8 @@ void sender() {
|
||||
void receiver() {
|
||||
int n;
|
||||
do {
|
||||
n = buf.receive();
|
||||
std::cout << "received: " << n << std::endl;
|
||||
n = buf.receive();
|
||||
std::cout << "received: " << n << std::endl;
|
||||
} while (n != -1); // -1 indicates end of buffer
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <iostream>
|
||||
@@ -7,7 +18,7 @@ int counter=0;
|
||||
|
||||
void change_count()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
int i = ++counter;
|
||||
std::cout << "count == " << i << std::endl;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <iostream>
|
||||
|
||||
@@ -23,4 +34,4 @@ int main()
|
||||
boost::thread thrd(f);
|
||||
thrd.join();
|
||||
std::cout << "10! = " << result << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/ref.hpp>
|
||||
#include <iostream>
|
||||
@@ -23,4 +34,4 @@ int main()
|
||||
boost::thread thrd(boost::ref(f));
|
||||
thrd.join();
|
||||
std::cout << "10! = " << f.result() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <iostream>
|
||||
|
||||
@@ -21,10 +32,10 @@ private:
|
||||
int main()
|
||||
{
|
||||
int results[NUM_CALCS];
|
||||
boost::thread_group thrds;
|
||||
for (int i=0; i < NUM_CALCS; ++i)
|
||||
thrds.create_thread(factorial(i*10, results[i]));
|
||||
thrds.join_all();
|
||||
for (int i=0; i < NUM_CALCS; ++i)
|
||||
std::cout << i*10 << "! = " << results[i] << std::endl;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <iostream>
|
||||
|
||||
@@ -10,4 +21,4 @@ int main()
|
||||
{
|
||||
boost::thread thrd(&helloworld);
|
||||
thrd.join();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <iostream>
|
||||
|
||||
@@ -11,4 +22,4 @@ int main()
|
||||
{
|
||||
boost::thread thrd(helloworld());
|
||||
thrd.join();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <iostream>
|
||||
|
||||
@@ -12,4 +23,4 @@ int main()
|
||||
{
|
||||
boost::thread thrd(helloworld("Bob"));
|
||||
thrd.join();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <iostream>
|
||||
@@ -11,4 +22,4 @@ int main()
|
||||
{
|
||||
boost::thread thrd(boost::bind(&helloworld, "Bob"));
|
||||
thrd.join();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/once.hpp>
|
||||
#include <cassert>
|
||||
@@ -12,14 +23,14 @@ void init()
|
||||
|
||||
void thread_proc()
|
||||
{
|
||||
boost::call_once(&init, once);
|
||||
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);
|
||||
boost::thread_group threads;
|
||||
for (int i=0; i<5; ++i)
|
||||
threads.create_thread(&thread_proc);
|
||||
threads.join_all();
|
||||
assert(value == 1);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/tss.hpp>
|
||||
#include <cassert>
|
||||
@@ -6,25 +17,25 @@ boost::thread_specific_ptr<int> value;
|
||||
|
||||
void increment()
|
||||
{
|
||||
int* p = value.get();
|
||||
++*p;
|
||||
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);
|
||||
}
|
||||
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();
|
||||
boost::thread_group threads;
|
||||
for (int i=0; i<5; ++i)
|
||||
threads.create_thread(&thread_proc);
|
||||
threads.join_all();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user