mirror of
https://github.com/boostorg/thread.git
synced 2026-02-03 09:42:16 +00:00
Compare commits
4 Commits
boost-1.30
...
boost-1.29
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
60326d5b37 | ||
|
|
9169abc03f | ||
|
|
13233e3146 | ||
|
|
813620fa7c |
@@ -1,11 +1,17 @@
|
||||
# (C) Copyright William E. Kempf 2001. Permission to copy, use, modify,
|
||||
# sell and distribute this software is granted provided this copyright
|
||||
# notice appears in all copies. This software is provided "as is" without
|
||||
# express or implied warranty, and with no claim as to its suitability for
|
||||
# any purpose.
|
||||
# (C) Copyright William E. Kempf 2001. Permission to copy, use, modify, sell and
|
||||
# distribute this software is granted provided this copyright notice appears
|
||||
# in all copies. This software is provided "as is" without express or implied
|
||||
# warranty, and with no claim as to its suitability for any purpose.
|
||||
#
|
||||
# Boost.Threads build Jamfile
|
||||
#
|
||||
# Declares the following targets:
|
||||
# 1. libboost_thread, a static link library.
|
||||
# 1a. On Win32 (when PTW32 is not defined), a dynamic link library
|
||||
# boost_threadmon, which must be used in conjunction with
|
||||
# libboost_thread. Note that this DLL *must* be used through static
|
||||
# linking to the import library. Dynamic loading will cause undefined
|
||||
# behavior.
|
||||
# Additional configuration variables used:
|
||||
# 1. PTW32 may be used on Win32 platforms to specify that the pthreads-win32
|
||||
# library should be used instead of "native" threads. This feature is
|
||||
@@ -25,29 +31,37 @@ subproject libs/thread/build ;
|
||||
SEARCH on <module@>threads.jam = $(SUBDIR) ;
|
||||
include <module@>threads.jam ;
|
||||
|
||||
template thread_libs
|
||||
## sources ##
|
||||
: <template>thread_base
|
||||
## requirements ##
|
||||
:
|
||||
## default build ##
|
||||
: debug release <runtime-link>static/dynamic
|
||||
;
|
||||
|
||||
#######################
|
||||
# Conditionally declare the Boost.Threads dynamic link library boost_threadmon.
|
||||
|
||||
if $(NT) && ! $(PTW32)
|
||||
{
|
||||
template thread_libs
|
||||
## sources ##
|
||||
: <template>thread_base
|
||||
## requirements ##
|
||||
:
|
||||
## default build ##
|
||||
: debug release
|
||||
;
|
||||
|
||||
# Base names of the source files for libboost_thread.
|
||||
CPP_SOURCES = condition mutex recursive_mutex thread tss xtime once
|
||||
exceptions threadmon ;
|
||||
|
||||
dll boost_thread
|
||||
: <template>thread_libs ../src/$(CPP_SOURCES).cpp
|
||||
: <define>BOOST_THREAD_BUILD_DLL=1
|
||||
;
|
||||
|
||||
stage bin-stage
|
||||
: <dll>boost_thread
|
||||
: #<tag><runtime-link-static>"s"
|
||||
<tag><debug>"d"
|
||||
: debug release
|
||||
;
|
||||
dll boost_threadmon : <template>thread_libs ../src/threadmon.cpp ;
|
||||
}
|
||||
|
||||
#######################
|
||||
# Declare the Boost.Threads static link library libboost_thread.
|
||||
|
||||
# Base names of the source files for libboost_thread.
|
||||
CPP_SOURCES = condition mutex recursive_mutex thread tss xtime once exceptions ;
|
||||
|
||||
lib boost_thread : <template>thread_libs ../src/$(CPP_SOURCES).cpp ;
|
||||
|
||||
#######################
|
||||
# Stage the generated targets.
|
||||
|
||||
#stage bin-stage
|
||||
# : <lib>boost_thread $(threadmon)
|
||||
# : <tag><runtime-link-static>"s"
|
||||
# <tag><debug>"d"
|
||||
# : debug release <runtime-link>static/dynamic
|
||||
#;
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
|
||||
# Declare the uses system library
|
||||
lib pthread : : <name>pthread ;
|
||||
|
||||
project boost/thread
|
||||
: source-location ../src
|
||||
: usage-requirements <library>pthread
|
||||
;
|
||||
|
||||
CPP_SOURCES = condition mutex recursive_mutex thread tss xtime once exceptions ;
|
||||
|
||||
lib boost_thread : $(CPP_SOURCES).cpp ;
|
||||
@@ -1,29 +1,32 @@
|
||||
# Do some OS-specific setup
|
||||
|
||||
threadmon = ;
|
||||
pthreads-win32 = ;
|
||||
|
||||
if $(NT)
|
||||
{
|
||||
pthreads-win32 = ;
|
||||
|
||||
if $(NT)
|
||||
if $(PTW32)
|
||||
{
|
||||
if $(PTW32)
|
||||
{
|
||||
local install-path = $(PTW32[1]) ;
|
||||
local lib = $(PTW32[2]) ;
|
||||
pthreads-win32 =
|
||||
<define>BOOST_HAS_PTHREADS
|
||||
<define>PtW32NoCatchWarn
|
||||
<include>$(install-path)/pre-built/include
|
||||
<library-file>$(install-path)/pre-built/lib/$(lib)
|
||||
;
|
||||
}
|
||||
local install-path = $(PTW32[1]) ;
|
||||
local lib = $(PTW32[2]) ;
|
||||
pthreads-win32 =
|
||||
<define>BOOST_HAS_PTHREADS
|
||||
<define>PtW32NoCatchWarn
|
||||
<include>$(install-path)/pre-built/include
|
||||
<library-file>$(install-path)/pre-built/lib/$(lib)
|
||||
;
|
||||
}
|
||||
else
|
||||
{
|
||||
threadmon = <dll>../build/boost_threadmon ;
|
||||
}
|
||||
}
|
||||
|
||||
template thread_base
|
||||
## sources ##
|
||||
:
|
||||
## requirements ##
|
||||
: <sysinclude>$(BOOST_ROOT) <threading>multi $(pthreads-win32)
|
||||
<borland><*><cxxflags>-w-8004
|
||||
## default build ##
|
||||
:
|
||||
;
|
||||
}
|
||||
template thread_base
|
||||
## sources ##
|
||||
:
|
||||
## requirements ##
|
||||
: <sysinclude>$(BOOST_ROOT) <threading>multi $(pthreads-win32)
|
||||
## 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), Kevin S. Van Horn (for several updates/corrections
|
||||
to the documentation), and Martin Johnson (shared library implementation).</p>
|
||||
build to work on other platforms), and Kevin S. Van Horn (for several updates/corrections
|
||||
to the documentation).</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
|
||||
|
||||
@@ -61,9 +61,10 @@
|
||||
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:
|
||||
@@ -85,19 +86,22 @@
|
||||
</pre>
|
||||
<h4><a name="class-condition-ctors"></a>Class <code>condition</code> constructors
|
||||
and destructor</h4>
|
||||
<pre>condition();
|
||||
<pre>
|
||||
condition();
|
||||
</pre>
|
||||
<dl class="function-semantics">
|
||||
<dt><b>Effects:</b> Constructs a <code>condition</code> object.</dt>
|
||||
</dl>
|
||||
<pre>~condition();
|
||||
<pre>
|
||||
~condition();
|
||||
</pre>
|
||||
<dl class="function-semantics">
|
||||
<dt><b>Effects:</b> Destroys <code>*this</code>.</dt>
|
||||
</dl>
|
||||
<h4><a name="class-condition-modifiers"></a>Class <code>condition</code> modifier
|
||||
functions</h4>
|
||||
<pre>void notify_one();
|
||||
<pre>
|
||||
void notify_one();
|
||||
</pre>
|
||||
<dl class="function-semantics">
|
||||
<dt><b>Effects:</b> If there is a thread waiting on <code>*this</code>, change
|
||||
@@ -107,14 +111,16 @@
|
||||
thread must still acquire the mutex again (which occurs within the call to
|
||||
one of the <code>condition</code> object's wait functions).</dt>
|
||||
</dl>
|
||||
<pre>void notify_all();
|
||||
<pre>
|
||||
void notify_all();
|
||||
</pre>
|
||||
<dl class="function-semantics">
|
||||
<dt><b>Effects:</b> Change the state of all threads waiting on <code> *this</code>
|
||||
to ready. If there are no waiting threads, <code> notify_all()</code> has
|
||||
no effect.</dt>
|
||||
</dl>
|
||||
<pre>template <typename ScopedLock>
|
||||
<pre>
|
||||
template <typename ScopedLock>
|
||||
void wait(ScopedLock& lock);
|
||||
</pre>
|
||||
<dl class="function-semantics">
|
||||
@@ -132,7 +138,8 @@
|
||||
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">
|
||||
@@ -142,7 +149,8 @@
|
||||
<dt><b>Throws:</b> <code><a href="exceptions.html#class-lock_error">lock_error</a></code>
|
||||
if <code>!lock.locked()</code></dt>
|
||||
</dl>
|
||||
<pre>template <typename ScopedLock>
|
||||
<pre>
|
||||
template <typename ScopedLock>
|
||||
bool timed_wait(ScopedLock& lock, const <a href="xtime.html">xtime</a>& XT);
|
||||
</pre>
|
||||
<dl class="function-semantics">
|
||||
@@ -163,14 +171,16 @@
|
||||
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;
|
||||
@@ -186,7 +196,8 @@ return true;
|
||||
<h2><a name="examples"></a>Example(s)</h2>
|
||||
<p><a href="../example/condition.cpp">libs/thread/example/condition.cpp</a></p>
|
||||
<p>Typical output (dependent on scheduling policies) is:</p>
|
||||
<pre>sent: 0
|
||||
<pre>
|
||||
sent: 0
|
||||
sent: 1
|
||||
received: 0
|
||||
received: 1
|
||||
@@ -198,7 +209,9 @@ sent: 4
|
||||
received: 4
|
||||
</pre>
|
||||
<p>Revised
|
||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->09 January, 2003<!--webbot bot="Timestamp" endspan i-checksum="38582" -->
|
||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
||||
05 November, 2001
|
||||
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
|
||||
</p>
|
||||
<p><i>© Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
|
||||
All Rights Reserved.</i></p>
|
||||
@@ -209,4 +222,4 @@ received: 4
|
||||
makes no representations about the suitability of this software for any purpose.
|
||||
It is provided "as is" without express or implied warranty.</p>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -241,17 +241,18 @@
|
||||
there is no matching exception handler in a program [15.3/9]. That is, terminate()
|
||||
is called, and it is implementation defined whether or not the stack is unwound.</p>
|
||||
<h2><a name="acknowledgements"></a>Acknowledgments</h2>
|
||||
<p>This document was originally written by Beman Dawes, and then much improved by the incorporation of comments from
|
||||
William Kempf, who now maintains the contents.</p>
|
||||
<p>This document has been much improved by the incorporation of comments from
|
||||
William Kempf.</p>
|
||||
<p>The visibility rules are based on <a href=
|
||||
"bibliography.html#Butenhof-97">[Butenhof 97]</a>.</p>
|
||||
<hr>
|
||||
<p>Revised
|
||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->06 October, 2002<!--webbot bot="Timestamp" endspan i-checksum="38429" -->
|
||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
||||
05 November, 2001
|
||||
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
|
||||
</p>
|
||||
<p><i>© Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
|
||||
All Rights Reserved.<br>
|
||||
</i>© Copyright Beman Dawes, 2001</p>
|
||||
All Rights Reserved.</i></p>
|
||||
<p>Permission to use, copy, modify, distribute and sell this software and its
|
||||
documentation for any purpose is hereby granted without fee, provided that the
|
||||
above copyright notice appear in all copies and that both that copyright notice
|
||||
@@ -259,4 +260,4 @@
|
||||
makes no representations about the suitability of this software for any purpose.
|
||||
It is provided "as is" without express or implied warranty.</p>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
13
doc/faq.html
13
doc/faq.html
@@ -86,7 +86,8 @@
|
||||
"definitions.html#Thread-safe">thread-safe</a>. The following is a simple
|
||||
example of a class with copyable semantics and internal synchronization through
|
||||
a mutex member.</p>
|
||||
<pre>class counter
|
||||
<pre>
|
||||
class counter
|
||||
{
|
||||
public:
|
||||
// Doesn't need synchronization since there can be no references to *this
|
||||
@@ -144,8 +145,8 @@ private:
|
||||
a mutex member as mutable clearly documents the intended semantics.</p>
|
||||
<h2><a name="question7"></a>7. Why supply <a href="condition.html">condition variables</a>
|
||||
rather than <a href="rationale.html#Events">event variables</a>?</h2>
|
||||
<p>Condition variables result in user code much less prone to
|
||||
<a href="definitions.html#definition-race-condition">race conditions</a> than event variables.
|
||||
<p>Condition variables result in user code much less prone to <a href=
|
||||
"definitions.html#Race condition">race conditions</a> than event variables.
|
||||
See <a href="rationale.html#Events">Rationale</a> for analysis. Also see <a href="bibliography.html#Hoare-74">[Hoare
|
||||
74]</a> and <a href="bibliography.html#Schmidt-00">[Schmidt 00]</a>.</p>
|
||||
<h2><a name="question8"></a>8. Why isn't thread cancellation or termination
|
||||
@@ -166,7 +167,9 @@ private:
|
||||
greater safety by the combination of a mutex and a condition variable.</p>
|
||||
<hr>
|
||||
<p>Revised
|
||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->09 January, 2003<!--webbot bot="Timestamp" endspan i-checksum="38582" -->
|
||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
||||
05 November, 2001
|
||||
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
|
||||
</p>
|
||||
<p><i>© Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
|
||||
All Rights Reserved.</i></p>
|
||||
@@ -177,4 +180,4 @@ private:
|
||||
makes no representations about the suitability of this software for any purpose.
|
||||
It is provided "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,7 +223,9 @@
|
||||
</table>
|
||||
<hr>
|
||||
<p>Revised
|
||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->09 January, 2003<!--webbot bot="Timestamp" endspan i-checksum="38582" -->
|
||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
||||
05 November, 2001
|
||||
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
|
||||
</p>
|
||||
<p><i>© Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
|
||||
All Rights Reserved.</i></p>
|
||||
@@ -234,4 +236,4 @@
|
||||
makes no representations about the suitability of this software for any purpose.
|
||||
It is provided "as is" without express or implied warranty.</p>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -110,8 +110,7 @@
|
||||
<p><b>Warning:</b> Multithreaded programs such as those using <b> Boost.Threads</b>
|
||||
must link to <a href="definitions.html#Thread-safe"> thread-safe</a> versions
|
||||
of all runtime libraries used by the program, including the runtime library
|
||||
for the C++ Standard Library. Otherwise
|
||||
<a href="definitions.html#definition-race-condition">race
|
||||
for the C++ Standard Library. Otherwise <a href="definitions.html#Race condition">race
|
||||
conditions</a> will occur when multiple threads simultaneously execute runtime
|
||||
library functions for <i>new</i>, <i>delete</i>, or other language features
|
||||
which imply shared state.</p>
|
||||
@@ -158,7 +157,9 @@
|
||||
as implementations are free to meet the NonCopyable requirement in other ways.</p>
|
||||
<hr>
|
||||
<p>Revised
|
||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->09 January, 2003<!--webbot bot="Timestamp" endspan i-checksum="38582" -->
|
||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
||||
05 November, 2001
|
||||
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
|
||||
</p>
|
||||
<p><i>© Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
|
||||
All Rights Reserved.</i></p>
|
||||
@@ -169,4 +170,4 @@
|
||||
makes no representations about the suitability of this software for any purpose.
|
||||
It is provided "as is" without express or implied warranty.</p>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -144,27 +144,31 @@
|
||||
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);
|
||||
@@ -173,14 +177,16 @@
|
||||
}
|
||||
</pre>
|
||||
<h3>5. Creation of a thread whose ownership is passed to another object/method.</h3>
|
||||
<pre>Void foo()
|
||||
<pre>
|
||||
Void foo()
|
||||
{
|
||||
thread = create_thread(&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);
|
||||
@@ -205,7 +211,8 @@
|
||||
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);
|
||||
}
|
||||
@@ -216,7 +223,8 @@ void foo()
|
||||
}
|
||||
</pre>
|
||||
<h3>2.</h3>
|
||||
<pre>void foo()
|
||||
<pre>
|
||||
void foo()
|
||||
{
|
||||
thread thrd(&bar);
|
||||
thrd.join();
|
||||
@@ -229,7 +237,8 @@ void foo()
|
||||
}
|
||||
</pre>
|
||||
<h3>3.</h3>
|
||||
<pre>void foo()
|
||||
<pre>
|
||||
void foo()
|
||||
{
|
||||
for (int i=0; i<NUM_THREADS; ++i)
|
||||
thread thrd(&bar);
|
||||
@@ -242,7 +251,8 @@ 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)
|
||||
@@ -261,7 +271,8 @@ void foo()
|
||||
}
|
||||
</pre>
|
||||
<h3>5.</h3>
|
||||
<pre>void foo()
|
||||
<pre>
|
||||
void foo()
|
||||
{
|
||||
thread thrd* = new thread(&bar);
|
||||
manager.owns(thread);
|
||||
@@ -274,7 +285,8 @@ void foo()
|
||||
}
|
||||
</pre>
|
||||
<h3>6.</h3>
|
||||
<pre>void foo()
|
||||
<pre>
|
||||
void foo()
|
||||
{
|
||||
boost::shared_ptr<thread> thrd(new thread(&bar));
|
||||
manager1.add(thrd);
|
||||
@@ -296,7 +308,8 @@ void foo()
|
||||
the presence of operator new in user code, but this can be eliminated by proper
|
||||
design of higher level concepts, such as the boost::thread_group class that
|
||||
simplifies example (4) down to:</p>
|
||||
<pre>void foo()
|
||||
<pre>
|
||||
void foo()
|
||||
{
|
||||
thread_group threads;
|
||||
for (int i=0; i<NUM_THREADS; ++i)
|
||||
@@ -353,7 +366,8 @@ void foo()
|
||||
variables are a continuing source of errors, even after previous bad experiences
|
||||
caused them to be very careful in their use of event variables. Overt problems
|
||||
can be avoided, for example, by teaming the event variable with a mutex, but
|
||||
that may just convert a <a href="definitions.html#definition-race-condition">race condition</a> into another problem,
|
||||
that may just convert a <a href=
|
||||
"definitions.html#Race condition">race condition</a> into another problem,
|
||||
such as excessive resource use. One of the most distressing aspects of the experience
|
||||
reports is the claim that many defects are latent. That is, the programs appear
|
||||
to work correctly, but contain hidden timing dependencies which will cause them
|
||||
@@ -369,7 +383,9 @@ void foo()
|
||||
<p>[Rationale provided by Beman Dawes]</p>
|
||||
<hr>
|
||||
<p>Revised
|
||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->09 January, 2003<!--webbot bot="Timestamp" endspan i-checksum="38582" -->
|
||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
||||
05 November, 2001
|
||||
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
|
||||
</p>
|
||||
<p><i>© Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
|
||||
All Rights Reserved.</i></p>
|
||||
@@ -380,4 +396,4 @@ void foo()
|
||||
makes no representations about the suitability of this software for any purpose.
|
||||
It is provided "as is" without express or implied warranty.</p>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -85,8 +85,10 @@
|
||||
having first been called, the thread of execution continues until its initial
|
||||
function completes.</p>
|
||||
<h4><a name="class-thread-synopsis"></a>Class <code>thread</code> synopsis</h4>
|
||||
<pre>namespace boost {
|
||||
class thread : <a href="../../utility/utility.htm#Class_noncopyable">boost::noncopyable</a> // Exposition only.
|
||||
<pre>
|
||||
namespace boost {
|
||||
class thread : <a href=
|
||||
"../../utility/utility.htm#Class noncopyable">boost::noncopyable</a> // Exposition only.
|
||||
// Class thread meets the <a href=
|
||||
"overview.html#non-copyable">NonCopyable</a> requirement.
|
||||
{
|
||||
@@ -107,7 +109,8 @@ public:
|
||||
</pre>
|
||||
<h4><a name="class-thread-ctors"></a>Class <code>thread</code> constructors and
|
||||
destructor</h4>
|
||||
<pre>thread();
|
||||
<pre>
|
||||
thread();
|
||||
</pre>
|
||||
<dl class="function-semantics">
|
||||
<dt><b>Effects:</b> Constructs a <code>thread</code> object representing the
|
||||
@@ -115,7 +118,8 @@ public:
|
||||
<dt><b>Postconditions:</b> <code>*this</code> is non-joinable.</dt>
|
||||
<dt><b>Danger:</b> <code>*this</code> is valid only within the current thread.</dt>
|
||||
</dl>
|
||||
<pre>thread(const <a href="../../function/index.html">boost::function0</a><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>
|
||||
@@ -128,7 +132,8 @@ public:
|
||||
<dt><b>Throws:</b> <code>boost::thread_resource_error</code> if a new thread
|
||||
of execution cannot be started.</dt>
|
||||
</dl>
|
||||
<pre>~Thread();
|
||||
<pre>
|
||||
~Thread();
|
||||
</pre>
|
||||
<dl class="function-semantics">
|
||||
<dt><b>Effects:</b> Destroys <code>*this</code>. The actual thread of execution
|
||||
@@ -141,21 +146,24 @@ public:
|
||||
</dl>
|
||||
<h4><a name="class-thread-comparisons"></a>Class <code>thread</code> comparison
|
||||
functions</h4>
|
||||
<pre>bool operator==(const thread& 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>
|
||||
@@ -168,13 +176,15 @@ public:
|
||||
<a href="definitions.html#Deadlock"> deadlock</a>.</dt>
|
||||
</dl>
|
||||
<h4><a name="class-thread-statics"></a>Class <code>thread</code> static functions</h4>
|
||||
<pre>static void sleep(const <a href="xtime.html">xtime</a>& 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"
|
||||
@@ -190,9 +200,10 @@ public:
|
||||
"definitions.html#thread-safe">thread-safe</a>, except destruction.</p>
|
||||
<h4><a name="class-thread_group-synopsis"></a>Class <code>thread_group</code>
|
||||
synopsis</h4>
|
||||
<pre>namespace boost {
|
||||
<pre>
|
||||
namespace boost {
|
||||
class thread_group : <a href=
|
||||
"../../utility/utility.htm#Class_noncopyable">boost::noncopyable</a>
|
||||
"../../utility/utility.htm#Class noncopyable">boost::noncopyable</a>
|
||||
{
|
||||
public:
|
||||
thread_group();
|
||||
@@ -207,12 +218,14 @@ public:
|
||||
</pre>
|
||||
<h4><a name="class-thread_group-ctors"></a>Class <code>thread_group</code> constructors
|
||||
and destructor</h4>
|
||||
<pre>thread_group();
|
||||
<pre>
|
||||
thread_group();
|
||||
</pre>
|
||||
<dl class="function-semantics">
|
||||
<dt><b>Effects:</b> Constructs an empty <code>thread_group</code> container.</dt>
|
||||
</dl>
|
||||
<pre>~thread_group();
|
||||
<pre>
|
||||
~thread_group();
|
||||
</pre>
|
||||
<dl class="function-semantics">
|
||||
<dt><b>Effects:</b> Destroys each contained thread object. Destroys <code>*this</code>.</dt>
|
||||
@@ -221,7 +234,8 @@ public:
|
||||
</dl>
|
||||
<h4><a name="class-thread_group-modifiers"></a>Class <code>thread_group</code>
|
||||
modifier functions</h4>
|
||||
<pre>thread* create_thread(const boost::function0<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>
|
||||
@@ -229,14 +243,16 @@ public:
|
||||
<tt>thread</tt> objects.</dt>
|
||||
<dt><b>Returns:</b> Pointer to the newly created thread.</dt>
|
||||
</dl>
|
||||
<pre>void add_thread(thread* thrd);
|
||||
<pre>
|
||||
void add_thread(thread* thrd);
|
||||
</pre>
|
||||
<dl class="function-semantics">
|
||||
<dt><b>Effects:</b> Adds <tt>thrd</tt> to the <tt>thread_group</tt> object'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>
|
||||
@@ -244,14 +260,16 @@ public:
|
||||
<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>
|
||||
@@ -268,13 +286,15 @@ public:
|
||||
<h3><a name="example-thread"></a>Simple usage of <code>boost::thread</code></h3>
|
||||
<p><a href="../example/thread.cpp">libs/thread/example/thread.cpp</a></p>
|
||||
<p>The output is:</p>
|
||||
<pre>setting alarm for 5 seconds...
|
||||
<pre>
|
||||
setting alarm for 5 seconds...
|
||||
alarm sounded...
|
||||
</pre>
|
||||
<h3><a name="example-thread_group"></a>Simple usage of <code>boost::thread_group</code></h3>
|
||||
<p><a href="../example/thread_group.cpp">libs/thread/example/thread_group.cpp</a></p>
|
||||
<p>The output is:</p>
|
||||
<pre>count = 1
|
||||
<pre>
|
||||
count = 1
|
||||
count = 2
|
||||
count = 3
|
||||
count = 4
|
||||
@@ -287,7 +307,9 @@ count = 10
|
||||
</pre>
|
||||
<hr>
|
||||
<p>Revised
|
||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->09 January, 2003<!--webbot bot="Timestamp" endspan i-checksum="38582" -->
|
||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
||||
05 November, 2001
|
||||
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
|
||||
</p>
|
||||
<p><i>© Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
|
||||
All Rights Reserved.</i></p>
|
||||
@@ -298,4 +320,4 @@ count = 10
|
||||
makes no representations about the suitability of this software for any purpose.
|
||||
It is provided "as is" without express or implied warranty.</p>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -1,19 +1,7 @@
|
||||
# (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"
|
||||
# (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.
|
||||
|
||||
# Declare the location of this subproject relative to the root.
|
||||
subproject libs/thread/example ;
|
||||
@@ -24,26 +12,23 @@ subproject libs/thread/example ;
|
||||
SEARCH on <module@>threads.jam = $(BOOST_ROOT)/libs/thread/build ;
|
||||
include <module@>threads.jam ;
|
||||
|
||||
{
|
||||
template example
|
||||
## sources ##
|
||||
: <template>thread_base
|
||||
<dll>../build/boost_thread
|
||||
## requirements ##
|
||||
:
|
||||
## default build ##
|
||||
:
|
||||
;
|
||||
template example
|
||||
## sources ##
|
||||
: <template>thread_base <lib>../build/boost_thread <lib>../../test/build/unit_test_framework $(threadmon)
|
||||
## requirements ##
|
||||
:
|
||||
## default build ##
|
||||
: release <runtime-link>static
|
||||
;
|
||||
|
||||
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,5 +0,0 @@
|
||||
|
||||
exe starvephil
|
||||
: starvephil.cpp ../build/boost_thread ../../test/build/unit_test_framework
|
||||
;
|
||||
|
||||
@@ -1,14 +1,3 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <boost/utility.hpp>
|
||||
@@ -54,9 +43,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);
|
||||
}
|
||||
@@ -64,8 +53,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,14 +1,3 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <boost/thread/condition.hpp>
|
||||
@@ -17,11 +6,9 @@
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
namespace {
|
||||
|
||||
const int ITERS = 100;
|
||||
boost::mutex io_mutex;
|
||||
|
||||
} // namespace
|
||||
const int ITERS = 100;
|
||||
boost::mutex io_mutex;
|
||||
}
|
||||
|
||||
template <typename M>
|
||||
class buffer_t
|
||||
|
||||
@@ -1,14 +1,3 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <iostream>
|
||||
|
||||
@@ -1,14 +1,3 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/once.hpp>
|
||||
#include <cassert>
|
||||
@@ -23,14 +12,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,14 +1,3 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <iostream>
|
||||
|
||||
@@ -1,14 +1,3 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/condition.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
@@ -16,10 +5,9 @@
|
||||
#include <iostream>
|
||||
#include <time.h>
|
||||
|
||||
namespace {
|
||||
|
||||
boost::mutex iomx;
|
||||
|
||||
namespace
|
||||
{
|
||||
boost::mutex iomx;
|
||||
}
|
||||
|
||||
class canteen
|
||||
@@ -51,9 +39,8 @@ 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);
|
||||
@@ -97,7 +84,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);
|
||||
}
|
||||
@@ -109,8 +96,7 @@ 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 (;;)
|
||||
{
|
||||
@@ -124,13 +110,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -143,10 +129,7 @@ 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);
|
||||
@@ -160,10 +143,7 @@ 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,14 +1,3 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/condition.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
@@ -60,8 +49,7 @@ 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);
|
||||
}
|
||||
|
||||
@@ -72,10 +60,7 @@ 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);
|
||||
@@ -89,10 +74,7 @@ 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,40 +1,29 @@
|
||||
// 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,14 +1,3 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <iostream>
|
||||
|
||||
@@ -17,14 +6,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,14 +1,3 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/tss.hpp>
|
||||
#include <cassert>
|
||||
@@ -17,25 +6,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,21 +1,10 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <boost/thread/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
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#if !defined(BOOST_THREAD_WEK01082003_HPP)
|
||||
#define BOOST_THREAD_WEK01082003_HPP
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/condition.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/once.hpp>
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
#include <boost/thread/tss.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
|
||||
#endif
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// Copyright (C) 2001
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
@@ -20,7 +20,6 @@
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/thread/detail/lock.hpp>
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
# include <pthread.h>
|
||||
@@ -32,60 +31,14 @@ namespace boost {
|
||||
|
||||
struct xtime;
|
||||
|
||||
namespace detail {
|
||||
|
||||
class BOOST_THREAD_DECL condition_impl : private noncopyable
|
||||
{
|
||||
friend class condition;
|
||||
|
||||
public:
|
||||
condition_impl();
|
||||
~condition_impl();
|
||||
|
||||
void notify_one();
|
||||
void notify_all();
|
||||
|
||||
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||
void enter_wait();
|
||||
void do_wait();
|
||||
bool do_timed_wait(const xtime& xt);
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
void do_wait(pthread_mutex_t* pmutex);
|
||||
bool do_timed_wait(const xtime& xt, pthread_mutex_t* pmutex);
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
void* m_gate;
|
||||
void* m_queue;
|
||||
void* m_mutex;
|
||||
unsigned m_gone; // # threads that timed out and never made it to m_queue
|
||||
unsigned long m_blocked; // # threads blocked on the condition
|
||||
unsigned m_waiting; // # threads no longer waiting for the condition but
|
||||
// still waiting to be removed from m_queue
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
pthread_cond_t m_condition;
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
MPSemaphoreID m_gate;
|
||||
MPSemaphoreID m_queue;
|
||||
threads::mac::detail::scoped_critical_region m_mutex;
|
||||
threads::mac::detail::scoped_critical_region m_mutex_mutex;
|
||||
unsigned m_gone; // # threads that timed out and never made it to m_queue
|
||||
unsigned long m_blocked; // # threads blocked on the condition
|
||||
unsigned m_waiting; // # threads no longer waiting for the condition but
|
||||
// still waiting to be removed from m_queue
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
class condition : private noncopyable
|
||||
{
|
||||
public:
|
||||
condition() { }
|
||||
~condition() { }
|
||||
condition();
|
||||
~condition();
|
||||
|
||||
void notify_one() { m_impl.notify_one(); }
|
||||
void notify_all() { m_impl.notify_all(); }
|
||||
void notify_one();
|
||||
void notify_all();
|
||||
|
||||
template <typename L>
|
||||
void wait(L& lock)
|
||||
@@ -131,63 +84,79 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
detail::condition_impl m_impl;
|
||||
|
||||
template <typename M>
|
||||
void do_wait(M& mutex)
|
||||
{
|
||||
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||
m_impl.enter_wait();
|
||||
enter_wait();
|
||||
#endif
|
||||
|
||||
typedef detail::thread::lock_ops<M>
|
||||
#if defined(__HP_aCC) && __HP_aCC <= 33900 && !defined(BOOST_STRICT_CONFIG)
|
||||
# define lock_ops lock_ops_ // HP confuses lock_ops witht the template
|
||||
#endif
|
||||
lock_ops;
|
||||
|
||||
typedef detail::thread::lock_ops<M> lock_ops;
|
||||
typename lock_ops::lock_state state;
|
||||
lock_ops::unlock(mutex, state);
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
m_impl.do_wait(state.pmutex);
|
||||
do_wait(state.pmutex);
|
||||
#elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||
m_impl.do_wait();
|
||||
do_wait();
|
||||
#endif
|
||||
|
||||
lock_ops::lock(mutex, state);
|
||||
#undef lock_ops
|
||||
}
|
||||
|
||||
template <typename M>
|
||||
bool do_timed_wait(M& mutex, const xtime& xt)
|
||||
{
|
||||
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||
m_impl.enter_wait();
|
||||
enter_wait();
|
||||
#endif
|
||||
|
||||
typedef detail::thread::lock_ops<M>
|
||||
#if defined(__HP_aCC) && __HP_aCC <= 33900 && !defined(BOOST_STRICT_CONFIG)
|
||||
# define lock_ops lock_ops_ // HP confuses lock_ops witht the template
|
||||
#endif
|
||||
lock_ops;
|
||||
|
||||
typedef detail::thread::lock_ops<M> lock_ops;
|
||||
typename lock_ops::lock_state state;
|
||||
lock_ops::unlock(mutex, state);
|
||||
|
||||
bool ret = false;
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
ret = m_impl.do_timed_wait(xt, state.pmutex);
|
||||
ret = do_timed_wait(xt, state.pmutex);
|
||||
#elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||
ret = m_impl.do_timed_wait(xt);
|
||||
ret = do_timed_wait(xt);
|
||||
#endif
|
||||
|
||||
lock_ops::lock(mutex, state);
|
||||
#undef lock_ops
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||
void enter_wait();
|
||||
void do_wait();
|
||||
bool do_timed_wait(const xtime& xt);
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
void do_wait(pthread_mutex_t* pmutex);
|
||||
bool do_timed_wait(const xtime& xt, pthread_mutex_t* pmutex);
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
void* m_gate;
|
||||
void* m_queue;
|
||||
void* m_mutex;
|
||||
unsigned m_gone; // # threads that timed out and never made it to the m_queue
|
||||
unsigned long m_blocked; // # threads m_blocked m_waiting for the condition
|
||||
unsigned m_waiting; // # threads m_waiting no longer m_waiting for the condition but still
|
||||
// m_waiting to be removed from the m_queue
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
pthread_cond_t m_condition;
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
MPSemaphoreID m_gate;
|
||||
MPSemaphoreID m_queue;
|
||||
threads::mac::detail::scoped_critical_region m_mutex;
|
||||
threads::mac::detail::scoped_critical_region m_mutex_mutex;
|
||||
unsigned m_gone; // # threads that timed out and never made it to the m_queue
|
||||
unsigned long m_blocked; // # threads m_blocked m_waiting for the condition
|
||||
unsigned m_waiting; // # threads m_waiting no longer m_waiting for the condition but still
|
||||
// m_waiting to be removed from the m_queue
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace boost
|
||||
@@ -195,8 +164,7 @@ private:
|
||||
// Change Log:
|
||||
// 8 Feb 01 WEKEMPF Initial version.
|
||||
// 22 May 01 WEKEMPF Modified to use xtime for time outs.
|
||||
// 23 May 01 WEKEMPF Removed "duration" timed_waits, as they are too
|
||||
// difficult to use with spurious wakeups.
|
||||
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
|
||||
// 23 May 01 WEKEMPF Removed "duration" timed_waits, as they are too difficult
|
||||
// to use with spurious wakeups.
|
||||
|
||||
#endif // BOOST_CONDITION_WEK070601_HPP
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#ifndef BOOST_THREAD_CONFIG_WEK01032003_HPP
|
||||
#define BOOST_THREAD_CONFIG_WEK01032003_HPP
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
# if defined(BOOST_THREAD_BUILD_DLL)
|
||||
# define BOOST_THREAD_DECL __declspec(dllexport)
|
||||
# else
|
||||
# define BOOST_THREAD_DECL __declspec(dllimport)
|
||||
# endif
|
||||
#else
|
||||
# define BOOST_THREAD_DECL
|
||||
#endif // BOOST_THREAD_SHARED_LIB
|
||||
|
||||
#endif // BOOST_THREAD_CONFIG_WEK1032003_HPP
|
||||
@@ -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
|
||||
{
|
||||
private:
|
||||
lock_ops() { }
|
||||
template <typename Mutex>
|
||||
class lock_ops : private noncopyable
|
||||
{
|
||||
private:
|
||||
lock_ops() { }
|
||||
|
||||
public:
|
||||
typedef typename Mutex::cv_state lock_state;
|
||||
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);
|
||||
}
|
||||
};
|
||||
static void lock(Mutex& m)
|
||||
{
|
||||
m.do_lock();
|
||||
}
|
||||
static bool trylock(Mutex& m)
|
||||
{
|
||||
return m.do_trylock();
|
||||
}
|
||||
static bool timedlock(Mutex& m, const xtime& xt)
|
||||
{
|
||||
return m.do_timedlock(xt);
|
||||
}
|
||||
static void unlock(Mutex& m)
|
||||
{
|
||||
m.do_unlock();
|
||||
}
|
||||
static void lock(Mutex& m, lock_state& state)
|
||||
{
|
||||
m.do_lock(state);
|
||||
}
|
||||
static void unlock(Mutex& m, lock_state& state)
|
||||
{
|
||||
m.do_unlock(state);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Mutex>
|
||||
class scoped_lock : private noncopyable
|
||||
{
|
||||
public:
|
||||
typedef Mutex mutex_type;
|
||||
|
||||
explicit scoped_lock(Mutex& mx, bool initially_locked=true)
|
||||
: m_mutex(mx), m_locked(false)
|
||||
template <typename Mutex>
|
||||
class scoped_lock : private noncopyable
|
||||
{
|
||||
if (initially_locked) lock();
|
||||
}
|
||||
~scoped_lock()
|
||||
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
|
||||
{
|
||||
if (m_locked) unlock();
|
||||
}
|
||||
public:
|
||||
typedef TryMutex mutex_type;
|
||||
|
||||
void lock()
|
||||
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
|
||||
{
|
||||
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;
|
||||
}
|
||||
public:
|
||||
typedef TimedMutex mutex_type;
|
||||
|
||||
bool locked() const { return m_locked; }
|
||||
operator const void*() const { return m_locked ? this : 0; }
|
||||
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();
|
||||
}
|
||||
|
||||
private:
|
||||
friend class boost::condition;
|
||||
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;
|
||||
}
|
||||
|
||||
Mutex& m_mutex;
|
||||
bool m_locked;
|
||||
};
|
||||
bool locked() const { return m_locked; }
|
||||
operator const void*() const { return m_locked ? this : 0; }
|
||||
|
||||
template <typename TryMutex>
|
||||
class scoped_try_lock : private noncopyable
|
||||
{
|
||||
public:
|
||||
typedef TryMutex mutex_type;
|
||||
private:
|
||||
friend class boost::condition;
|
||||
|
||||
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();
|
||||
}
|
||||
TimedMutex& m_mutex;
|
||||
bool m_locked;
|
||||
};
|
||||
|
||||
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 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,25 +0,0 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifndef BOOST_HAS_THREADS
|
||||
# error Thread support is unavailable!
|
||||
#endif
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_WINTHREADS
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
extern "C" BOOST_THREAD_DECL int on_thread_exit(void (__cdecl * func)(void));
|
||||
|
||||
#endif // BOOST_HAS_WINTHREADS
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// Copyright (C) 2001
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
@@ -12,9 +12,6 @@
|
||||
#ifndef BOOST_THREAD_EXCEPTIONS_PDM070801_H
|
||||
#define BOOST_THREAD_EXCEPTIONS_PDM070801_H
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
// pdm: Sorry, but this class is used all over the place & I end up
|
||||
// with recursive headers if I don't separate it
|
||||
// wek: Not sure why recursive headers would cause compilation problems
|
||||
@@ -25,13 +22,13 @@
|
||||
|
||||
namespace boost {
|
||||
|
||||
class BOOST_THREAD_DECL lock_error : public std::logic_error
|
||||
class lock_error : public std::logic_error
|
||||
{
|
||||
public:
|
||||
lock_error();
|
||||
};
|
||||
|
||||
class BOOST_THREAD_DECL thread_resource_error : public std::runtime_error
|
||||
class thread_resource_error : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
thread_resource_error();
|
||||
@@ -39,7 +36,4 @@ public:
|
||||
|
||||
} // namespace boost
|
||||
|
||||
// Change log:
|
||||
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
|
||||
|
||||
#endif // BOOST_THREAD_CONFIG_PDM070801_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// Copyright (C) 2001
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/thread/detail/lock.hpp>
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
# include <pthread.h>
|
||||
@@ -33,7 +32,7 @@ namespace boost {
|
||||
|
||||
struct xtime;
|
||||
|
||||
class BOOST_THREAD_DECL mutex : private noncopyable
|
||||
class mutex : private noncopyable
|
||||
{
|
||||
public:
|
||||
friend class detail::thread::lock_ops<mutex>;
|
||||
@@ -71,7 +70,7 @@ private:
|
||||
#endif
|
||||
};
|
||||
|
||||
class BOOST_THREAD_DECL try_mutex : private noncopyable
|
||||
class try_mutex : private noncopyable
|
||||
{
|
||||
public:
|
||||
friend class detail::thread::lock_ops<try_mutex>;
|
||||
@@ -111,7 +110,7 @@ private:
|
||||
#endif
|
||||
};
|
||||
|
||||
class BOOST_THREAD_DECL timed_mutex : private noncopyable
|
||||
class timed_mutex : private noncopyable
|
||||
{
|
||||
public:
|
||||
friend class detail::thread::lock_ops<timed_mutex>;
|
||||
@@ -161,6 +160,5 @@ private:
|
||||
// 8 Feb 01 WEKEMPF Initial version.
|
||||
// 22 May 01 WEKEMPF Modified to use xtime for time outs. Factored out
|
||||
// to three classes, mutex, try_mutex and timed_mutex.
|
||||
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
|
||||
|
||||
#endif // BOOST_MUTEX_WEK070601_HPP
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// Copyright (C) 2001
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
@@ -17,8 +17,6 @@
|
||||
# error Thread support is unavailable!
|
||||
#endif
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
# include <pthread.h>
|
||||
#endif
|
||||
@@ -37,7 +35,7 @@ typedef long once_flag;
|
||||
|
||||
#endif
|
||||
|
||||
void BOOST_THREAD_DECL call_once(void (*func)(), once_flag& flag);
|
||||
void call_once(void (*func)(), once_flag& flag);
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// Copyright (C) 2001
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/thread/detail/lock.hpp>
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
# include <pthread.h>
|
||||
@@ -31,7 +30,7 @@ namespace boost {
|
||||
|
||||
struct xtime;
|
||||
|
||||
class BOOST_THREAD_DECL recursive_mutex : private noncopyable
|
||||
class recursive_mutex : private noncopyable
|
||||
{
|
||||
public:
|
||||
friend class detail::thread::lock_ops<recursive_mutex>;
|
||||
@@ -74,14 +73,13 @@ private:
|
||||
#endif
|
||||
};
|
||||
|
||||
class BOOST_THREAD_DECL recursive_try_mutex : private noncopyable
|
||||
class recursive_try_mutex : private noncopyable
|
||||
{
|
||||
public:
|
||||
friend class detail::thread::lock_ops<recursive_try_mutex>;
|
||||
|
||||
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();
|
||||
@@ -120,16 +118,14 @@ private:
|
||||
#endif
|
||||
};
|
||||
|
||||
class BOOST_THREAD_DECL recursive_timed_mutex : private noncopyable
|
||||
class recursive_timed_mutex : private noncopyable
|
||||
{
|
||||
public:
|
||||
friend class detail::thread::lock_ops<recursive_timed_mutex>;
|
||||
|
||||
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();
|
||||
@@ -174,7 +170,5 @@ private:
|
||||
// 1 Jun 01 WEKEMPF Modified to use xtime for time outs. Factored out
|
||||
// to three classes, mutex, try_mutex and timed_mutex.
|
||||
// 11 Jun 01 WEKEMPF Modified to use PTHREAD_MUTEX_RECURSIVE if available.
|
||||
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
|
||||
|
||||
|
||||
#endif // BOOST_RECURSIVE_MUTEX_WEK070601_HPP
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// Copyright (C) 2001
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
@@ -20,7 +20,6 @@
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
|
||||
@@ -35,7 +34,7 @@ namespace boost {
|
||||
|
||||
struct xtime;
|
||||
|
||||
class BOOST_THREAD_DECL thread : private noncopyable
|
||||
class thread : private noncopyable
|
||||
{
|
||||
public:
|
||||
thread();
|
||||
@@ -64,7 +63,7 @@ private:
|
||||
bool m_joinable;
|
||||
};
|
||||
|
||||
class BOOST_THREAD_DECL thread_group : private noncopyable
|
||||
class thread_group : private noncopyable
|
||||
{
|
||||
public:
|
||||
thread_group();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// Copyright (C) 2001
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
@@ -18,7 +18,6 @@
|
||||
#endif
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
# include <pthread.h>
|
||||
@@ -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 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,13 +64,7 @@ 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-2003
|
||||
// Copyright (C) 2001
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
@@ -12,9 +12,8 @@
|
||||
#ifndef BOOST_XTIME_WEK070601_HPP
|
||||
#define BOOST_XTIME_WEK070601_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/config.hpp>
|
||||
|
||||
namespace boost {
|
||||
|
||||
@@ -40,7 +39,7 @@ struct xtime
|
||||
int_fast32_t nsec;
|
||||
};
|
||||
|
||||
int BOOST_THREAD_DECL xtime_get(struct xtime* xtp, int clock_type);
|
||||
int xtime_get(struct xtime* xtp, int clock_type);
|
||||
inline int xtime_cmp(const xtime& xt1, const xtime& xt2)
|
||||
{
|
||||
int res = (int)(xt1.sec - xt2.sec);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// Copyright (C) 2001
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
@@ -25,49 +25,45 @@
|
||||
#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 {
|
||||
|
||||
namespace detail {
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
condition_impl::condition_impl()
|
||||
condition::condition()
|
||||
: m_gone(0), m_blocked(0), m_waiting(0)
|
||||
{
|
||||
m_gate = reinterpret_cast<void*>(CreateSemaphore(0, 1, 1, 0));
|
||||
m_queue = reinterpret_cast<void*>(CreateSemaphore(0, 0,
|
||||
std::numeric_limits<long>::max(),
|
||||
0));
|
||||
m_queue = reinterpret_cast<void*>(CreateSemaphore(0, 0, std::numeric_limits<long>::max(), 0));
|
||||
m_mutex = reinterpret_cast<void*>(CreateMutex(0, 0, 0));
|
||||
|
||||
if (!m_gate || !m_queue || !m_mutex)
|
||||
{
|
||||
int res = 0;
|
||||
if (m_gate)
|
||||
{
|
||||
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();
|
||||
res = CloseHandle(reinterpret_cast<HANDLE>(m_gate));
|
||||
assert(res);
|
||||
}
|
||||
if (m_queue)
|
||||
{
|
||||
res = CloseHandle(reinterpret_cast<HANDLE>(m_queue));
|
||||
assert(res);
|
||||
}
|
||||
if (m_mutex)
|
||||
{
|
||||
res = CloseHandle(reinterpret_cast<HANDLE>(m_mutex));
|
||||
assert(res);
|
||||
}
|
||||
|
||||
throw thread_resource_error();
|
||||
}
|
||||
}
|
||||
|
||||
condition_impl::~condition_impl()
|
||||
condition::~condition()
|
||||
{
|
||||
int res = 0;
|
||||
res = CloseHandle(reinterpret_cast<HANDLE>(m_gate));
|
||||
@@ -78,7 +74,7 @@ condition_impl::~condition_impl()
|
||||
assert(res);
|
||||
}
|
||||
|
||||
void condition_impl::notify_one()
|
||||
void condition::notify_one()
|
||||
{
|
||||
unsigned signals = 0;
|
||||
|
||||
@@ -87,102 +83,101 @@ void condition_impl::notify_one()
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
|
||||
if (m_waiting != 0) // the m_gate is already closed
|
||||
{
|
||||
if (m_blocked == 0)
|
||||
{
|
||||
if (m_blocked == 0)
|
||||
{
|
||||
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||
assert(res);
|
||||
return;
|
||||
}
|
||||
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||
assert(res);
|
||||
return;
|
||||
}
|
||||
|
||||
++m_waiting;
|
||||
--m_blocked;
|
||||
signals = 1;
|
||||
}
|
||||
++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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
if (m_gone != 0)
|
||||
{
|
||||
m_blocked -= m_gone;
|
||||
m_gone = 0;
|
||||
}
|
||||
signals = m_waiting = 1;
|
||||
--m_blocked;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||
assert(res);
|
||||
}
|
||||
}
|
||||
|
||||
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||
assert(res);
|
||||
|
||||
if (signals)
|
||||
{
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_queue), signals, 0);
|
||||
assert(res);
|
||||
}
|
||||
}
|
||||
|
||||
void condition::notify_all()
|
||||
{
|
||||
unsigned signals = 0;
|
||||
|
||||
int res = 0;
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
|
||||
if (m_waiting != 0) // the m_gate is already closed
|
||||
{
|
||||
if (m_blocked == 0)
|
||||
{
|
||||
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||
assert(res);
|
||||
return;
|
||||
}
|
||||
|
||||
m_waiting += (signals = m_blocked);
|
||||
m_blocked = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
if (m_blocked > m_gone)
|
||||
{
|
||||
if (m_gone != 0)
|
||||
{
|
||||
m_blocked -= m_gone;
|
||||
m_gone = 0;
|
||||
}
|
||||
signals = m_waiting = m_blocked;
|
||||
m_blocked = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||
assert(res);
|
||||
}
|
||||
|
||||
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||
assert(res);
|
||||
|
||||
if (signals)
|
||||
{
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_queue), signals, 0);
|
||||
assert(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void condition_impl::notify_all()
|
||||
{
|
||||
unsigned signals = 0;
|
||||
|
||||
int res = 0;
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
|
||||
if (m_waiting != 0) // the m_gate is already closed
|
||||
{
|
||||
if (m_blocked == 0)
|
||||
{
|
||||
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||
assert(res);
|
||||
return;
|
||||
}
|
||||
|
||||
m_waiting += (signals = m_blocked);
|
||||
m_blocked = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
if (m_blocked > m_gone)
|
||||
{
|
||||
if (m_gone != 0)
|
||||
{
|
||||
m_blocked -= m_gone;
|
||||
m_gone = 0;
|
||||
}
|
||||
signals = m_waiting = m_blocked;
|
||||
m_blocked = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||
assert(res);
|
||||
}
|
||||
}
|
||||
|
||||
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||
assert(res);
|
||||
|
||||
if (signals)
|
||||
{
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_queue), signals,
|
||||
0);
|
||||
assert(res);
|
||||
}
|
||||
}
|
||||
|
||||
void condition_impl::enter_wait()
|
||||
void condition::enter_wait()
|
||||
{
|
||||
int res = 0;
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
|
||||
@@ -192,7 +187,7 @@ void condition_impl::enter_wait()
|
||||
assert(res);
|
||||
}
|
||||
|
||||
void condition_impl::do_wait()
|
||||
void condition::do_wait()
|
||||
{
|
||||
int res = 0;
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue), INFINITE);
|
||||
@@ -206,75 +201,72 @@ void condition_impl::do_wait()
|
||||
was_waiting = m_waiting;
|
||||
was_gone = m_gone;
|
||||
if (was_waiting != 0)
|
||||
{
|
||||
if (--m_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_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)
|
||||
{
|
||||
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);
|
||||
// better now than spurious later
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue), INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
}
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||
assert(res);
|
||||
}
|
||||
}
|
||||
|
||||
bool condition_impl::do_timed_wait(const xtime& xt)
|
||||
bool condition::do_timed_wait(const xtime& xt)
|
||||
{
|
||||
bool ret = false;
|
||||
unsigned int res = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
int milliseconds;
|
||||
to_duration(xt, milliseconds);
|
||||
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue), milliseconds);
|
||||
assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
|
||||
ret = (res == WAIT_OBJECT_0);
|
||||
|
||||
if (res == WAIT_TIMEOUT)
|
||||
{
|
||||
int milliseconds;
|
||||
to_duration(xt, milliseconds);
|
||||
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue),
|
||||
milliseconds);
|
||||
assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
|
||||
ret = (res == WAIT_OBJECT_0);
|
||||
|
||||
if (res == WAIT_TIMEOUT)
|
||||
{
|
||||
xtime cur;
|
||||
xtime_get(&cur, TIME_UTC);
|
||||
if (xtime_cmp(xt, cur) > 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
xtime cur;
|
||||
xtime_get(&cur, TIME_UTC);
|
||||
if (xtime_cmp(xt, cur) > 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
unsigned was_waiting=0;
|
||||
unsigned was_gone=0;
|
||||
|
||||
@@ -283,59 +275,57 @@ 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 (!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_blocked != 0)
|
||||
--m_blocked;
|
||||
else
|
||||
++m_gone; // count spurious wakeups
|
||||
}
|
||||
if (--m_waiting == 0)
|
||||
{
|
||||
if (m_blocked != 0)
|
||||
{
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0); // open m_gate
|
||||
assert(res);
|
||||
was_waiting = 0;
|
||||
}
|
||||
else if (m_gone != 0)
|
||||
m_gone = 0;
|
||||
}
|
||||
}
|
||||
else if (++m_gone == (std::numeric_limits<unsigned>::max() / 2))
|
||||
{
|
||||
// timeout occured, normalize the m_gone count
|
||||
// this may occur if many calls to wait with a timeout are made and
|
||||
// no call to notify_* is made
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
m_blocked -= m_gone;
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||
assert(res);
|
||||
m_gone = 0;
|
||||
}
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
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);
|
||||
// better now than spurious later
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue), INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
}
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||
assert(res);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
condition_impl::condition_impl()
|
||||
condition::condition()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_cond_init(&m_condition, 0);
|
||||
@@ -343,35 +333,35 @@ condition_impl::condition_impl()
|
||||
throw thread_resource_error();
|
||||
}
|
||||
|
||||
condition_impl::~condition_impl()
|
||||
condition::~condition()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_cond_destroy(&m_condition);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
void condition_impl::notify_one()
|
||||
void condition::notify_one()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_cond_signal(&m_condition);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
void condition_impl::notify_all()
|
||||
void condition::notify_all()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_cond_broadcast(&m_condition);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
void condition_impl::do_wait(pthread_mutex_t* pmutex)
|
||||
void condition::do_wait(pthread_mutex_t* pmutex)
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_cond_wait(&m_condition, pmutex);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
bool condition_impl::do_timed_wait(const xtime& xt, pthread_mutex_t* pmutex)
|
||||
bool condition::do_timed_wait(const xtime& xt, pthread_mutex_t* pmutex)
|
||||
{
|
||||
timespec ts;
|
||||
to_timespec(xt, ts);
|
||||
@@ -387,7 +377,7 @@ bool condition_impl::do_timed_wait(const xtime& xt, pthread_mutex_t* pmutex)
|
||||
using threads::mac::detail::safe_enter_critical_region;
|
||||
using threads::mac::detail::safe_wait_on_semaphore;
|
||||
|
||||
condition_impl::condition_impl()
|
||||
condition::condition()
|
||||
: m_gone(0), m_blocked(0), m_waiting(0)
|
||||
{
|
||||
threads::mac::detail::thread_init();
|
||||
@@ -399,23 +389,23 @@ condition_impl::condition_impl()
|
||||
lStatus = MPCreateSemaphore(ULONG_MAX, 0, &m_queue);
|
||||
|
||||
if(lStatus != noErr || !m_gate || !m_queue)
|
||||
{
|
||||
if (m_gate)
|
||||
{
|
||||
if (m_gate)
|
||||
{
|
||||
lStatus = MPDeleteSemaphore(m_gate);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
if (m_queue)
|
||||
{
|
||||
lStatus = MPDeleteSemaphore(m_queue);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
throw thread_resource_error();
|
||||
lStatus = MPDeleteSemaphore(m_gate);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
if (m_queue)
|
||||
{
|
||||
lStatus = MPDeleteSemaphore(m_queue);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
throw thread_resource_error();
|
||||
}
|
||||
}
|
||||
|
||||
condition_impl::~condition_impl()
|
||||
condition::~condition()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = MPDeleteSemaphore(m_gate);
|
||||
@@ -424,113 +414,111 @@ condition_impl::~condition_impl()
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
void condition_impl::notify_one()
|
||||
void condition::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)
|
||||
{
|
||||
if (m_blocked == 0)
|
||||
{
|
||||
lStatus = MPExitCriticalRegion(m_mutex);
|
||||
assert(lStatus == noErr);
|
||||
return;
|
||||
}
|
||||
lStatus = MPExitCriticalRegion(m_mutex);
|
||||
assert(lStatus == noErr);
|
||||
return;
|
||||
}
|
||||
|
||||
++m_waiting;
|
||||
++m_waiting;
|
||||
--m_blocked;
|
||||
}
|
||||
else
|
||||
{
|
||||
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
|
||||
assert(lStatus == noErr);
|
||||
if (m_blocked > m_gone)
|
||||
{
|
||||
if (m_gone != 0)
|
||||
{
|
||||
m_blocked -= m_gone;
|
||||
m_gone = 0;
|
||||
}
|
||||
signals = m_waiting = 1;
|
||||
--m_blocked;
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
|
||||
lStatus = MPSignalSemaphore(m_gate);
|
||||
assert(lStatus == noErr);
|
||||
if (m_blocked > m_gone)
|
||||
{
|
||||
if (m_gone != 0)
|
||||
{
|
||||
m_blocked -= m_gone;
|
||||
m_gone = 0;
|
||||
}
|
||||
signals = m_waiting = 1;
|
||||
--m_blocked;
|
||||
}
|
||||
else
|
||||
{
|
||||
lStatus = MPSignalSemaphore(m_gate);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
lStatus = MPExitCriticalRegion(m_mutex);
|
||||
assert(lStatus == noErr);
|
||||
|
||||
while (signals)
|
||||
{
|
||||
lStatus = MPSignalSemaphore(m_queue);
|
||||
assert(lStatus == noErr);
|
||||
--signals;
|
||||
}
|
||||
}
|
||||
|
||||
lStatus = MPExitCriticalRegion(m_mutex);
|
||||
assert(lStatus == noErr);
|
||||
|
||||
while (signals)
|
||||
{
|
||||
lStatus = MPSignalSemaphore(m_queue);
|
||||
assert(lStatus == noErr);
|
||||
--signals;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void condition_impl::notify_all()
|
||||
void condition::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)
|
||||
{
|
||||
if (m_blocked == 0)
|
||||
{
|
||||
lStatus = MPExitCriticalRegion(m_mutex);
|
||||
assert(lStatus == noErr);
|
||||
return;
|
||||
}
|
||||
|
||||
m_waiting += (signals = m_blocked);
|
||||
m_blocked = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
|
||||
assert(lStatus == noErr);
|
||||
if (m_blocked > m_gone)
|
||||
{
|
||||
if (m_gone != 0)
|
||||
{
|
||||
m_blocked -= m_gone;
|
||||
m_gone = 0;
|
||||
}
|
||||
signals = m_waiting = m_blocked;
|
||||
m_blocked = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
lStatus = MPSignalSemaphore(m_gate);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
lStatus = MPExitCriticalRegion(m_mutex);
|
||||
assert(lStatus == noErr);
|
||||
|
||||
while (signals)
|
||||
{
|
||||
lStatus = MPSignalSemaphore(m_queue);
|
||||
assert(lStatus == noErr);
|
||||
--signals;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
m_waiting += (signals = m_blocked);
|
||||
m_blocked = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
|
||||
assert(lStatus == noErr);
|
||||
if (m_blocked > m_gone)
|
||||
{
|
||||
if (m_gone != 0)
|
||||
{
|
||||
m_blocked -= m_gone;
|
||||
m_gone = 0;
|
||||
}
|
||||
signals = m_waiting = m_blocked;
|
||||
m_blocked = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
lStatus = MPSignalSemaphore(m_gate);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
lStatus = MPExitCriticalRegion(m_mutex);
|
||||
assert(lStatus == noErr);
|
||||
|
||||
while (signals)
|
||||
{
|
||||
lStatus = MPSignalSemaphore(m_queue);
|
||||
assert(lStatus == noErr);
|
||||
--signals;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void condition_impl::enter_wait()
|
||||
void condition::enter_wait()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
|
||||
@@ -540,7 +528,7 @@ void condition_impl::enter_wait()
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
void condition_impl::do_wait()
|
||||
void condition::do_wait()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = safe_wait_on_semaphore(m_queue, kDurationForever);
|
||||
@@ -549,54 +537,53 @@ 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_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_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)
|
||||
{
|
||||
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);
|
||||
// better now than spurious later
|
||||
lStatus = safe_wait_on_semaphore(m_queue, kDurationForever);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
lStatus = MPSignalSemaphore(m_gate);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
}
|
||||
|
||||
bool condition_impl::do_timed_wait(const xtime& xt)
|
||||
bool condition::do_timed_wait(const xtime& xt)
|
||||
{
|
||||
int milliseconds;
|
||||
to_duration(xt, milliseconds);
|
||||
@@ -610,68 +597,64 @@ 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 (!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_blocked != 0)
|
||||
--m_blocked;
|
||||
else
|
||||
++m_gone; // count spurious wakeups
|
||||
}
|
||||
if (--m_waiting == 0)
|
||||
{
|
||||
if (m_blocked != 0)
|
||||
{
|
||||
lStatus = MPSignalSemaphore(m_gate); // open m_gate
|
||||
assert(lStatus == noErr);
|
||||
was_waiting = 0;
|
||||
}
|
||||
else if (m_gone != 0)
|
||||
m_gone = 0;
|
||||
}
|
||||
}
|
||||
else if (++m_gone == (std::numeric_limits<unsigned>::max() / 2))
|
||||
{
|
||||
// timeout occured, normalize the m_gone count
|
||||
// this may occur if many calls to wait with a timeout are made and
|
||||
// no call to notify_* is made
|
||||
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
|
||||
assert(lStatus == noErr);
|
||||
m_blocked -= m_gone;
|
||||
lStatus = MPSignalSemaphore(m_gate);
|
||||
assert(lStatus == noErr);
|
||||
m_gone = 0;
|
||||
}
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
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);
|
||||
// better now than spurious later
|
||||
lStatus = safe_wait_on_semaphore(m_queue, kDurationForever);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
lStatus = MPSignalSemaphore(m_gate);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace boost
|
||||
|
||||
// Change Log:
|
||||
// 8 Feb 01 WEKEMPF Initial version.
|
||||
// 22 May 01 WEKEMPF Modified to use xtime for time outs.
|
||||
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// Copyright (C) 2001
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
@@ -14,13 +14,11 @@
|
||||
|
||||
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-2003
|
||||
// Copyright (C) 2001
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <boost/limits.hpp>
|
||||
#include <stdexcept>
|
||||
#include <cassert>
|
||||
#include <new>
|
||||
#include "timeconv.inl"
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
@@ -24,23 +25,18 @@
|
||||
#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() : m_mutex(0)
|
||||
mutex::mutex()
|
||||
{
|
||||
try
|
||||
{
|
||||
m_mutex = reinterpret_cast<void*>(new CRITICAL_SECTION);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
m_mutex = reinterpret_cast<void*>(new(std::nothrow) CRITICAL_SECTION);
|
||||
if (!m_mutex)
|
||||
throw thread_resource_error();
|
||||
InitializeCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(m_mutex));
|
||||
@@ -155,8 +151,7 @@ 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)
|
||||
@@ -432,8 +427,7 @@ 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);
|
||||
}
|
||||
|
||||
@@ -465,8 +459,7 @@ 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);
|
||||
}
|
||||
|
||||
@@ -506,8 +499,7 @@ 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);
|
||||
}
|
||||
|
||||
|
||||
129
src/once.cpp
129
src/once.cpp
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// Copyright (C) 2001
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
@@ -17,16 +17,14 @@
|
||||
# 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
|
||||
@@ -35,7 +33,7 @@ private:
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_NO_STDC_NAMESPACE
|
||||
namespace std { using ::sprintf; }
|
||||
namespace std { using ::sprintf; }
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
@@ -48,70 +46,64 @@ 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)
|
||||
{
|
||||
std::pair<void (*)(), boost::once_flag *> &rData(
|
||||
*reinterpret_cast<std::pair<void (*)(), boost::once_flag *> *>(pData));
|
||||
|
||||
if(*rData.second == false)
|
||||
void *remote_call_proxy(void *pData)
|
||||
{
|
||||
rData.first();
|
||||
*rData.second = true;
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
@@ -124,15 +116,13 @@ 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());
|
||||
#else
|
||||
std::ostringstream strm;
|
||||
strm << "2AC1A572DB6944B0A65C38C4140AF2F4" << std::hex
|
||||
<< GetCurrentProcessId() << &flag;
|
||||
HANDLE mutex = CreateMutexA(NULL, FALSE, strm.str().c_str());
|
||||
strm << "2AC1A572DB6944B0A65C38C4140AF2F4" << std::hex << GetCurrentProcessId() << &flag;
|
||||
HANDLE mutex = CreateMutex(NULL, FALSE, strm.str().c_str());
|
||||
#endif
|
||||
assert(mutex != NULL);
|
||||
|
||||
@@ -158,8 +148,7 @@ 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-2003
|
||||
// Copyright (C) 2001
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
@@ -23,23 +23,17 @@
|
||||
#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_mutex(0), m_count(0)
|
||||
: m_count(0)
|
||||
{
|
||||
try
|
||||
{
|
||||
m_mutex = reinterpret_cast<void*>(new CRITICAL_SECTION);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
m_mutex = reinterpret_cast<void*>(new(std::nothrow) CRITICAL_SECTION);
|
||||
if (!m_mutex)
|
||||
throw thread_resource_error();
|
||||
InitializeCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(m_mutex));
|
||||
@@ -207,8 +201,7 @@ 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)
|
||||
@@ -805,8 +798,7 @@ 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)
|
||||
@@ -829,8 +821,7 @@ 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;
|
||||
@@ -858,8 +849,7 @@ 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)
|
||||
@@ -900,8 +890,7 @@ 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;
|
||||
@@ -929,8 +918,7 @@ 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)
|
||||
@@ -993,8 +981,7 @@ 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-2003
|
||||
// Copyright (C) 2001
|
||||
// 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,10 +32,7 @@ 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);
|
||||
@@ -59,28 +56,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
|
||||
{
|
||||
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();
|
||||
#endif
|
||||
return 0;
|
||||
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();
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -107,8 +104,7 @@ 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)
|
||||
@@ -125,11 +121,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);
|
||||
@@ -185,8 +181,7 @@ 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
|
||||
@@ -265,20 +260,17 @@ 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();
|
||||
@@ -288,11 +280,9 @@ 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);
|
||||
@@ -302,11 +292,9 @@ 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);
|
||||
@@ -315,11 +303,8 @@ 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,23 +1,12 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
// threadmon.cpp : Defines the entry point for the DLL application.
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#define BOOST_THREADMON_EXPORTS
|
||||
#include "threadmon.hpp"
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
#ifdef BOOST_HAS_WINTHREADS
|
||||
|
||||
#if defined(BOOST_THREAD_BUILD_DLL)
|
||||
|
||||
#include <boost/thread/detail/threadmon.hpp>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||
#include <windows.h>
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
@@ -34,9 +23,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__)
|
||||
@@ -44,75 +33,61 @@ registered_handlers registry;
|
||||
#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:
|
||||
{
|
||||
// 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)
|
||||
case DLL_PROCESS_ATTACH:
|
||||
InitializeCriticalSection(&cs);
|
||||
key = TlsAlloc();
|
||||
break;
|
||||
case DLL_THREAD_ATTACH:
|
||||
break;
|
||||
case DLL_THREAD_DETACH:
|
||||
{
|
||||
(*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;
|
||||
}
|
||||
}
|
||||
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)
|
||||
// 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:
|
||||
{
|
||||
(*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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
extern "C" BOOST_THREAD_DECL int on_thread_exit(void (__cdecl * func)(void))
|
||||
int on_thread_exit(void (__cdecl * func)(void))
|
||||
{
|
||||
// Get the exit handlers for the current thread, creating and registering
|
||||
// one if it doesn't exist.
|
||||
@@ -122,7 +97,7 @@ extern "C" BOOST_THREAD_DECL int on_thread_exit(void (__cdecl * func)(void))
|
||||
try
|
||||
{
|
||||
handlers = new exit_handlers;
|
||||
// Handle broken implementations of operator new that don't throw.
|
||||
// Handle "broken" implementations of operator new that don't throw.
|
||||
if (!handlers)
|
||||
return -1;
|
||||
}
|
||||
@@ -154,8 +129,8 @@ extern "C" BOOST_THREAD_DECL int on_thread_exit(void (__cdecl * func)(void))
|
||||
}
|
||||
}
|
||||
|
||||
// Attempt to add the handler to the list of exit handlers. If it's been
|
||||
// previously added just report success and exit.
|
||||
// Attempt to add the handler to the list of exit handlers. If it's been previously
|
||||
// added just report success and exit.
|
||||
try
|
||||
{
|
||||
handlers->push_front(func);
|
||||
@@ -168,6 +143,4 @@ extern "C" BOOST_THREAD_DECL int on_thread_exit(void (__cdecl * func)(void))
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // BOOST_THREAD_BUILD_DLL
|
||||
|
||||
#endif // BOOST_HAS_WINTHREADS
|
||||
|
||||
23
src/threadmon.hpp
Normal file
23
src/threadmon.hpp
Normal file
@@ -0,0 +1,23 @@
|
||||
#include <boost/config.hpp>
|
||||
#ifndef BOOST_HAS_THREADS
|
||||
# error Thread support is unavailable!
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_HAS_WINTHREADS
|
||||
|
||||
// The following ifdef block is the standard way of creating macros which make exporting
|
||||
// from a DLL simpler. All files within this DLL are compiled with the BOOST_THREADMON_EXPORTS
|
||||
// symbol defined on the command line. this symbol should not be defined on any project
|
||||
// that uses this DLL. This way any other project whose source files include this file see
|
||||
// BOOST_THREADMON_API functions as being imported from a DLL, wheras this DLL sees symbols
|
||||
// defined with this macro as being exported.
|
||||
|
||||
#ifdef BOOST_THREADMON_EXPORTS
|
||||
#define BOOST_THREADMON_API __declspec(dllexport)
|
||||
#else
|
||||
#define BOOST_THREADMON_API __declspec(dllimport)
|
||||
#endif
|
||||
|
||||
extern "C" BOOST_THREADMON_API int on_thread_exit(void (__cdecl * func)(void));
|
||||
|
||||
#endif // BOOST_HAS_WINTHREADS
|
||||
174
src/timeconv.inl
174
src/timeconv.inl
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// Copyright (C) 2001
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
@@ -10,119 +10,113 @@
|
||||
// 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)
|
||||
{
|
||||
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))
|
||||
inline void to_time(int milliseconds, boost::xtime& xt)
|
||||
{
|
||||
++xt.sec;
|
||||
xt.nsec -= 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
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))
|
||||
inline void to_timespec(const boost::xtime& xt, timespec& ts)
|
||||
{
|
||||
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;
|
||||
}
|
||||
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 += 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);
|
||||
|
||||
if (boost::xtime_cmp(xt, cur) <= 0)
|
||||
milliseconds = 0;
|
||||
else
|
||||
inline void to_duration(const boost::xtime& xt, int& milliseconds)
|
||||
{
|
||||
if (cur.nsec > xt.nsec)
|
||||
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
|
||||
{
|
||||
xt.nsec += NANOSECONDS_PER_SECOND;
|
||||
--xt.sec;
|
||||
}
|
||||
milliseconds = (int)((xt.sec - cur.sec) * MILLISECONDS_PER_SECOND) +
|
||||
(((xt.nsec - cur.nsec) + (NANOSECONDS_PER_MILLISECOND/2)) /
|
||||
milliseconds = ((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)
|
||||
{
|
||||
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
|
||||
inline void to_microduration(const boost::xtime& xt, int& microseconds)
|
||||
{
|
||||
microseconds = (int)((xt.sec - cur.sec) * MICROSECONDS_PER_SECOND) +
|
||||
(((xt.nsec - cur.nsec) + (NANOSECONDS_PER_MICROSECOND/2)) /
|
||||
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)) /
|
||||
NANOSECONDS_PER_MICROSECOND);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Change Log:
|
||||
// 1 Jun 01 Initial creation.
|
||||
|
||||
163
src/tss.cpp
163
src/tss.cpp
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// Copyright (C) 2001
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
@@ -20,103 +20,97 @@
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
#include <boost/thread/detail/threadmon.hpp>
|
||||
#include "threadmon.hpp"
|
||||
#include <map>
|
||||
namespace {
|
||||
typedef std::pair<void(*)(void*), void*> cleanup_info;
|
||||
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()
|
||||
{
|
||||
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)
|
||||
void init_cleanup_key()
|
||||
{
|
||||
cleanup_info info = it->second;
|
||||
if (info.second)
|
||||
info.first(info.second);
|
||||
}
|
||||
delete handlers;
|
||||
}
|
||||
|
||||
cleanup_handlers* get_handlers()
|
||||
{
|
||||
boost::call_once(&init_cleanup_key, once);
|
||||
|
||||
cleanup_handlers* handlers = static_cast<cleanup_handlers*>(
|
||||
TlsGetValue(key));
|
||||
if (!handlers)
|
||||
{
|
||||
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);
|
||||
key = TlsAlloc();
|
||||
assert(key != 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
return handlers;
|
||||
}
|
||||
void __cdecl cleanup()
|
||||
{
|
||||
cleanup_handlers* handlers = static_cast<cleanup_handlers*>(TlsGetValue(key));
|
||||
for (cleanup_handlers::iterator it = handlers->begin(); it != handlers->end(); ++it)
|
||||
{
|
||||
cleanup_info info = it->second;
|
||||
if (info.second)
|
||||
info.first(info.second);
|
||||
}
|
||||
delete handlers;
|
||||
}
|
||||
|
||||
cleanup_handlers* get_handlers()
|
||||
{
|
||||
boost::call_once(&init_cleanup_key, once);
|
||||
|
||||
cleanup_handlers* handlers = static_cast<cleanup_handlers*>(TlsGetValue(key));
|
||||
if (!handlers)
|
||||
{
|
||||
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 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()
|
||||
{
|
||||
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)
|
||||
void init_cleanup_key()
|
||||
{
|
||||
try
|
||||
{
|
||||
handlers = new cleanup_handlers;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = MPSetTaskStorageValue(key,
|
||||
reinterpret_cast<TaskStorageValue>(handlers));
|
||||
OSStatus lStatus = MPAllocateTaskStorageIndex(&key);
|
||||
assert(lStatus == noErr);
|
||||
// TODO - create a generalized mechanism for registering thread exit
|
||||
// functions and use it here.
|
||||
}
|
||||
|
||||
return handlers;
|
||||
}
|
||||
cleanup_handlers* get_handlers()
|
||||
{
|
||||
boost::call_once(&init_cleanup_key, once);
|
||||
|
||||
cleanup_handlers* handlers = reinterpret_cast<cleanup_handlers*>(MPGetTaskStorageValue(key));
|
||||
if (!handlers)
|
||||
{
|
||||
try
|
||||
{
|
||||
handlers = new cleanup_handlers;
|
||||
}
|
||||
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 {
|
||||
@@ -126,12 +120,10 @@ 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)
|
||||
@@ -243,8 +235,7 @@ 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-2003
|
||||
// Copyright (C) 2001
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
@@ -33,30 +33,29 @@ 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;
|
||||
}
|
||||
|
||||
@@ -78,13 +77,10 @@ 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;
|
||||
@@ -100,16 +96,12 @@ 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;
|
||||
|
||||
49
test/Jamfile
49
test/Jamfile
@@ -1,10 +1,12 @@
|
||||
# (C) Copyright William E. Kempf 2001. Permission to copy, use, modify, sell
|
||||
# and distribute this software is granted provided this copyright notice
|
||||
# appears in all copies. This software is provided "as is" without express or
|
||||
# implied warranty, and with no claim as to its suitability for any purpose.
|
||||
# (C) Copyright William E. Kempf 2001. Permission to copy, use, modify, sell and
|
||||
# distribute this software is granted provided this copyright notice appears
|
||||
# in all copies. This software is provided "as is" without express or implied
|
||||
# warranty, and with no claim as to its suitability for any purpose.
|
||||
#
|
||||
# Boost.Threads test Jamfile
|
||||
#
|
||||
# Declares the following targets:
|
||||
# 1. test_thread, a unit test executable.
|
||||
# Additional configuration variables used:
|
||||
# 1. PTW32 may be used on Win32 platforms to specify that the pthreads-win32
|
||||
# library should be used instead of "native" threads. This feature is
|
||||
@@ -28,24 +30,23 @@ include threads.jam ;
|
||||
SEARCH on testing.jam = $(BOOST_BUILD_PATH) ;
|
||||
include testing.jam ;
|
||||
|
||||
{
|
||||
template test
|
||||
## sources ##
|
||||
: <template>thread_base
|
||||
<dll>../build/boost_thread
|
||||
<lib>../../test/build/boost_unit_test_framework
|
||||
## requirements ##
|
||||
:
|
||||
## default build ##
|
||||
:
|
||||
;
|
||||
sources = test.cpp test_thread.cpp test_mutex.cpp test_condition.cpp test_tss.cpp test_once.cpp ;
|
||||
|
||||
test-suite "threads"
|
||||
: [ run test_thread.cpp <template>test ]
|
||||
[ run test_mutex.cpp <template>test ]
|
||||
[ run test_condition.cpp <template>test ]
|
||||
[ run test_tss.cpp <template>test ]
|
||||
[ run test_once.cpp <template>test ]
|
||||
[ run test_xtime.cpp <template>test ]
|
||||
;
|
||||
}
|
||||
template test
|
||||
## sources ##
|
||||
: <template>thread_base <lib>../build/boost_thread <lib>../../test/build/unit_test_framework $(threadmon)
|
||||
## requirements ##
|
||||
:
|
||||
## default build ##
|
||||
: debug release <runtime-link>static/dynamic
|
||||
;
|
||||
|
||||
#######################
|
||||
# Declare the Boost.Threads unit test program test_thread.
|
||||
|
||||
run test_thread.cpp <template>test ;
|
||||
run test_mutex.cpp <template>test ;
|
||||
run test_condition.cpp <template>test ;
|
||||
run test_tss.cpp <template>test ;
|
||||
run test_once.cpp <template>test ;
|
||||
run test_xtime.cpp <template>test ;
|
||||
|
||||
@@ -1,97 +1,103 @@
|
||||
// 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>
|
||||
|
||||
#include "util.inl"
|
||||
|
||||
struct condition_test_data
|
||||
namespace
|
||||
{
|
||||
condition_test_data() : notified(0), awoken(0) { }
|
||||
struct condition_test_data
|
||||
{
|
||||
condition_test_data() : notified(0), awoken(0) { }
|
||||
|
||||
boost::mutex mutex;
|
||||
boost::condition condition;
|
||||
int notified;
|
||||
int awoken;
|
||||
};
|
||||
boost::mutex mutex;
|
||||
boost::condition condition;
|
||||
int notified;
|
||||
int awoken;
|
||||
};
|
||||
|
||||
void condition_test_thread(condition_test_data* data)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(data->mutex);
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
while (!(data->notified > 0))
|
||||
data->condition.wait(lock);
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
data->awoken++;
|
||||
void condition_test_thread(void* param)
|
||||
{
|
||||
condition_test_data* data = static_cast<condition_test_data*>(param);
|
||||
boost::mutex::scoped_lock lock(data->mutex);
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
while (!(data->notified > 0))
|
||||
data->condition.wait(lock);
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
data->awoken++;
|
||||
}
|
||||
|
||||
class thread_adapter
|
||||
{
|
||||
public:
|
||||
thread_adapter(void (*func)(void*), void* param) : _func(func), _param(param) { }
|
||||
void operator()() const { _func(_param); }
|
||||
private:
|
||||
void (*_func)(void*);
|
||||
void* _param;
|
||||
};
|
||||
|
||||
struct cond_predicate
|
||||
{
|
||||
cond_predicate(int& var, int val) : _var(var), _val(val) { }
|
||||
|
||||
bool operator()() { return _var == _val; }
|
||||
|
||||
int& _var;
|
||||
int _val;
|
||||
};
|
||||
|
||||
void condition_test_waits(void* param)
|
||||
{
|
||||
condition_test_data* data = static_cast<condition_test_data*>(param);
|
||||
|
||||
boost::mutex::scoped_lock lock(data->mutex);
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
|
||||
// Test wait.
|
||||
while (data->notified != 1)
|
||||
data->condition.wait(lock);
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
BOOST_CHECK_EQUAL(data->notified, 1);
|
||||
data->awoken++;
|
||||
data->condition.notify_one();
|
||||
|
||||
// Test predicate wait.
|
||||
data->condition.wait(lock, cond_predicate(data->notified, 2));
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
BOOST_CHECK_EQUAL(data->notified, 2);
|
||||
data->awoken++;
|
||||
data->condition.notify_one();
|
||||
|
||||
// Test timed_wait.
|
||||
boost::xtime xt;
|
||||
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
|
||||
xt.sec += 10;
|
||||
while (data->notified != 3)
|
||||
data->condition.timed_wait(lock, xt);
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
BOOST_CHECK_EQUAL(data->notified, 3);
|
||||
data->awoken++;
|
||||
data->condition.notify_one();
|
||||
|
||||
// Test predicate timed_wait.
|
||||
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
|
||||
xt.sec += 10;
|
||||
cond_predicate pred(data->notified, 4);
|
||||
BOOST_CHECK(data->condition.timed_wait(lock, xt, pred));
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
BOOST_CHECK(pred());
|
||||
BOOST_CHECK_EQUAL(data->notified, 4);
|
||||
data->awoken++;
|
||||
data->condition.notify_one();
|
||||
}
|
||||
}
|
||||
|
||||
struct cond_predicate
|
||||
{
|
||||
cond_predicate(int& var, int val) : _var(var), _val(val) { }
|
||||
|
||||
bool operator()() { return _var == _val; }
|
||||
|
||||
int& _var;
|
||||
int _val;
|
||||
};
|
||||
|
||||
void condition_test_waits(condition_test_data* data)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(data->mutex);
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
|
||||
// Test wait.
|
||||
while (data->notified != 1)
|
||||
data->condition.wait(lock);
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
BOOST_CHECK_EQUAL(data->notified, 1);
|
||||
data->awoken++;
|
||||
data->condition.notify_one();
|
||||
|
||||
// Test predicate wait.
|
||||
data->condition.wait(lock, cond_predicate(data->notified, 2));
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
BOOST_CHECK_EQUAL(data->notified, 2);
|
||||
data->awoken++;
|
||||
data->condition.notify_one();
|
||||
|
||||
// Test timed_wait.
|
||||
boost::xtime xt = delay(10);
|
||||
while (data->notified != 3)
|
||||
data->condition.timed_wait(lock, xt);
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
BOOST_CHECK_EQUAL(data->notified, 3);
|
||||
data->awoken++;
|
||||
data->condition.notify_one();
|
||||
|
||||
// Test predicate timed_wait.
|
||||
xt = delay(10);
|
||||
cond_predicate pred(data->notified, 4);
|
||||
BOOST_CHECK(data->condition.timed_wait(lock, xt, pred));
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
BOOST_CHECK(pred());
|
||||
BOOST_CHECK_EQUAL(data->notified, 4);
|
||||
data->awoken++;
|
||||
data->condition.notify_one();
|
||||
}
|
||||
|
||||
void do_test_condition_notify_one()
|
||||
void test_condition_notify_one()
|
||||
{
|
||||
condition_test_data data;
|
||||
|
||||
boost::thread thread(bind(&condition_test_thread, &data));
|
||||
boost::thread thread(thread_adapter(&condition_test_thread, &data));
|
||||
|
||||
{
|
||||
boost::mutex::scoped_lock lock(data.mutex);
|
||||
@@ -104,19 +110,14 @@ void do_test_condition_notify_one()
|
||||
BOOST_CHECK_EQUAL(data.awoken, 1);
|
||||
}
|
||||
|
||||
void test_condition_notify_one()
|
||||
{
|
||||
timed_test(&do_test_condition_notify_one, 2, execution_monitor::use_mutex);
|
||||
}
|
||||
|
||||
void do_test_condition_notify_all()
|
||||
void test_condition_notify_all()
|
||||
{
|
||||
const int NUMTHREADS = 5;
|
||||
boost::thread_group threads;
|
||||
condition_test_data data;
|
||||
|
||||
for (int i = 0; i < NUMTHREADS; ++i)
|
||||
threads.create_thread(bind(&condition_test_thread, &data));
|
||||
threads.create_thread(thread_adapter(&condition_test_thread, &data));
|
||||
|
||||
{
|
||||
boost::mutex::scoped_lock lock(data.mutex);
|
||||
@@ -129,25 +130,21 @@ void do_test_condition_notify_all()
|
||||
BOOST_CHECK_EQUAL(data.awoken, NUMTHREADS);
|
||||
}
|
||||
|
||||
void test_condition_notify_all()
|
||||
{
|
||||
// We should have already tested notify_one here, so
|
||||
// a timed test with the default execution_monitor::use_condition
|
||||
// should be OK, and gives the fastest performance
|
||||
timed_test(&do_test_condition_notify_all, 3);
|
||||
}
|
||||
|
||||
void do_test_condition_waits()
|
||||
void test_condition_waits()
|
||||
{
|
||||
condition_test_data data;
|
||||
|
||||
boost::thread thread(bind(&condition_test_waits, &data));
|
||||
boost::thread thread(thread_adapter(&condition_test_waits, &data));
|
||||
|
||||
boost::xtime xt;
|
||||
|
||||
{
|
||||
boost::mutex::scoped_lock lock(data.mutex);
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
|
||||
boost::thread::sleep(delay(1));
|
||||
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
|
||||
xt.sec += 1;
|
||||
boost::thread::sleep(xt);
|
||||
data.notified++;
|
||||
data.condition.notify_one();
|
||||
while (data.awoken != 1)
|
||||
@@ -155,7 +152,9 @@ void do_test_condition_waits()
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
BOOST_CHECK_EQUAL(data.awoken, 1);
|
||||
|
||||
boost::thread::sleep(delay(1));
|
||||
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
|
||||
xt.sec += 1;
|
||||
boost::thread::sleep(xt);
|
||||
data.notified++;
|
||||
data.condition.notify_one();
|
||||
while (data.awoken != 2)
|
||||
@@ -163,7 +162,9 @@ void do_test_condition_waits()
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
BOOST_CHECK_EQUAL(data.awoken, 2);
|
||||
|
||||
boost::thread::sleep(delay(1));
|
||||
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
|
||||
xt.sec += 1;
|
||||
boost::thread::sleep(xt);
|
||||
data.notified++;
|
||||
data.condition.notify_one();
|
||||
while (data.awoken != 3)
|
||||
@@ -171,7 +172,9 @@ void do_test_condition_waits()
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
BOOST_CHECK_EQUAL(data.awoken, 3);
|
||||
|
||||
boost::thread::sleep(delay(1));
|
||||
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
|
||||
xt.sec += 1;
|
||||
boost::thread::sleep(xt);
|
||||
data.notified++;
|
||||
data.condition.notify_one();
|
||||
while (data.awoken != 4)
|
||||
@@ -180,22 +183,16 @@ void do_test_condition_waits()
|
||||
BOOST_CHECK_EQUAL(data.awoken, 4);
|
||||
}
|
||||
|
||||
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
|
||||
xt.sec += 1;
|
||||
boost::thread::sleep(xt);
|
||||
thread.join();
|
||||
BOOST_CHECK_EQUAL(data.awoken, 4);
|
||||
}
|
||||
|
||||
void test_condition_waits()
|
||||
{
|
||||
// We should have already tested notify_one here, so
|
||||
// a timed test with the default execution_monitor::use_condition
|
||||
// should be OK, and gives the fastest performance
|
||||
timed_test(&do_test_condition_waits, 12);
|
||||
}
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: condition test suite");
|
||||
boost::unit_test_framework::test_suite* test = BOOST_TEST_SUITE("Boost.Threads: condition test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(&test_condition_notify_one));
|
||||
test->add(BOOST_TEST_CASE(&test_condition_notify_all));
|
||||
|
||||
@@ -1,14 +1,3 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
@@ -17,8 +6,22 @@
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/test/unit_test_suite_ex.hpp>
|
||||
|
||||
#define DEFAULT_EXECUTION_MONITOR_TYPE execution_monitor::use_sleep_only
|
||||
#include "util.inl"
|
||||
namespace
|
||||
{
|
||||
inline bool xtime_in_range(boost::xtime& xt, int less_seconds, int greater_seconds)
|
||||
{
|
||||
boost::xtime cur;
|
||||
BOOST_CHECK_EQUAL(boost::xtime_get(&cur, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
|
||||
|
||||
boost::xtime less = cur;
|
||||
less.sec += less_seconds;
|
||||
|
||||
boost::xtime greater = cur;
|
||||
greater.sec += greater_seconds;
|
||||
|
||||
return (boost::xtime_cmp(xt, less) >= 0) && (boost::xtime_cmp(xt, greater) <= 0);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename M>
|
||||
struct test_lock
|
||||
@@ -40,7 +43,9 @@ struct test_lock
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
|
||||
// Construct and initialize an xtime for a fast time out.
|
||||
boost::xtime xt = delay(0, 100);
|
||||
boost::xtime xt;
|
||||
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
|
||||
xt.nsec += 100000000;
|
||||
|
||||
// Test the lock and the mutex with condition variables.
|
||||
// No one is going to notify this condition variable. We expect to
|
||||
@@ -80,7 +85,9 @@ struct test_trylock
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
|
||||
// Construct and initialize an xtime for a fast time out.
|
||||
boost::xtime xt = delay(0, 100);
|
||||
boost::xtime xt;
|
||||
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
|
||||
xt.nsec += 100000000;
|
||||
|
||||
// Test the lock and the mutex with condition variables.
|
||||
// No one is going to notify this condition variable. We expect to
|
||||
@@ -114,7 +121,9 @@ struct test_timedlock
|
||||
// Test the lock's constructors.
|
||||
{
|
||||
// Construct and initialize an xtime for a fast time out.
|
||||
boost::xtime xt = delay(0, 100);
|
||||
boost::xtime xt;
|
||||
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
|
||||
xt.nsec += 100000000;
|
||||
|
||||
timed_lock_type lock(mutex, xt);
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
@@ -127,14 +136,16 @@ struct test_timedlock
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
|
||||
// Construct and initialize an xtime for a fast time out.
|
||||
boost::xtime xt = delay(0, 100);
|
||||
boost::xtime xt;
|
||||
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
|
||||
xt.nsec += 100000000;
|
||||
|
||||
// Test the lock and the mutex with condition variables.
|
||||
// No one is going to notify this condition variable. We expect to
|
||||
// time out.
|
||||
BOOST_CHECK(!condition.timed_wait(lock, xt));
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
BOOST_CHECK(in_range(xt));
|
||||
BOOST_CHECK(xtime_in_range(xt, -1, 0));
|
||||
|
||||
// Test the lock, unlock and timedlock methods.
|
||||
lock.unlock();
|
||||
@@ -143,7 +154,8 @@ struct test_timedlock
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
lock.unlock();
|
||||
BOOST_CHECK(!lock);
|
||||
xt = delay(0, 100);
|
||||
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
|
||||
xt.nsec += 100000000;
|
||||
BOOST_CHECK(lock.timed_lock(xt));
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
}
|
||||
@@ -163,63 +175,38 @@ struct test_recursive_lock
|
||||
}
|
||||
};
|
||||
|
||||
void do_test_mutex()
|
||||
void test_mutex()
|
||||
{
|
||||
test_lock<boost::mutex>()();
|
||||
}
|
||||
|
||||
void test_mutex()
|
||||
{
|
||||
timed_test(&do_test_mutex, 3);
|
||||
}
|
||||
|
||||
void do_test_try_mutex()
|
||||
void test_try_mutex()
|
||||
{
|
||||
test_lock<boost::try_mutex>()();
|
||||
test_trylock<boost::try_mutex>()();
|
||||
}
|
||||
|
||||
void test_try_mutex()
|
||||
{
|
||||
timed_test(&do_test_try_mutex, 3);
|
||||
}
|
||||
|
||||
void do_test_timed_mutex()
|
||||
void test_timed_mutex()
|
||||
{
|
||||
test_lock<boost::timed_mutex>()();
|
||||
test_trylock<boost::timed_mutex>()();
|
||||
test_timedlock<boost::timed_mutex>()();
|
||||
}
|
||||
|
||||
void test_timed_mutex()
|
||||
{
|
||||
timed_test(&do_test_timed_mutex, 3);
|
||||
}
|
||||
|
||||
void do_test_recursive_mutex()
|
||||
void test_recursive_mutex()
|
||||
{
|
||||
test_lock<boost::recursive_mutex>()();
|
||||
test_recursive_lock<boost::recursive_mutex>()();
|
||||
}
|
||||
|
||||
void test_recursive_mutex()
|
||||
{
|
||||
timed_test(&do_test_recursive_mutex, 3);
|
||||
}
|
||||
|
||||
void do_test_recursive_try_mutex()
|
||||
void test_recursive_try_mutex()
|
||||
{
|
||||
test_lock<boost::recursive_try_mutex>()();
|
||||
test_trylock<boost::recursive_try_mutex>()();
|
||||
test_recursive_lock<boost::recursive_try_mutex>()();
|
||||
}
|
||||
|
||||
void test_recursive_try_mutex()
|
||||
{
|
||||
timed_test(&do_test_recursive_try_mutex, 3);
|
||||
}
|
||||
|
||||
void do_test_recursive_timed_mutex()
|
||||
void test_recursive_timed_mutex()
|
||||
{
|
||||
test_lock<boost::recursive_timed_mutex>()();
|
||||
test_trylock<boost::recursive_timed_mutex>()();
|
||||
@@ -227,15 +214,9 @@ void do_test_recursive_timed_mutex()
|
||||
test_recursive_lock<boost::recursive_timed_mutex>()();
|
||||
}
|
||||
|
||||
void test_recursive_timed_mutex()
|
||||
{
|
||||
timed_test(&do_test_recursive_timed_mutex, 3);
|
||||
}
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: mutex test suite");
|
||||
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,35 +1,25 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <boost/thread/once.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include "util.inl"
|
||||
|
||||
int once_value = 0;
|
||||
boost::once_flag once = BOOST_ONCE_INIT;
|
||||
|
||||
void init_once_value()
|
||||
namespace
|
||||
{
|
||||
once_value++;
|
||||
int once_value = 0;
|
||||
boost::once_flag once = BOOST_ONCE_INIT;
|
||||
|
||||
void init_once_value()
|
||||
{
|
||||
once_value++;
|
||||
}
|
||||
|
||||
void test_once_thread()
|
||||
{
|
||||
boost::call_once(init_once_value, once);
|
||||
}
|
||||
}
|
||||
|
||||
void test_once_thread()
|
||||
{
|
||||
boost::call_once(init_once_value, once);
|
||||
}
|
||||
|
||||
void do_test_once()
|
||||
void test_once()
|
||||
{
|
||||
const int NUMTHREADS=5;
|
||||
boost::thread_group threads;
|
||||
@@ -39,15 +29,9 @@ void do_test_once()
|
||||
BOOST_CHECK_EQUAL(once_value, 1);
|
||||
}
|
||||
|
||||
void test_once()
|
||||
{
|
||||
timed_test(&do_test_once, 2);
|
||||
}
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: once test suite");
|
||||
boost::unit_test_framework::test_suite* test = BOOST_TEST_SUITE("Boost.Threads: once test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(test_once));
|
||||
|
||||
|
||||
@@ -1,47 +1,68 @@
|
||||
// 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>
|
||||
|
||||
#define DEFAULT_EXECUTION_MONITOR_TYPE execution_monitor::use_sleep_only
|
||||
#include "util.inl"
|
||||
|
||||
int test_value;
|
||||
|
||||
void simple_thread()
|
||||
namespace
|
||||
{
|
||||
test_value = 999;
|
||||
}
|
||||
inline bool xtime_in_range(boost::xtime& xt, int less_seconds, int greater_seconds)
|
||||
{
|
||||
boost::xtime cur;
|
||||
BOOST_CHECK_EQUAL(boost::xtime_get(&cur, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
|
||||
|
||||
void comparison_thread(boost::thread* parent)
|
||||
{
|
||||
boost::thread thrd;
|
||||
BOOST_TEST(thrd != *parent);
|
||||
BOOST_TEST(thrd == boost::thread());
|
||||
boost::xtime less = cur;
|
||||
less.sec += less_seconds;
|
||||
|
||||
boost::xtime greater = cur;
|
||||
greater.sec += greater_seconds;
|
||||
|
||||
return (boost::xtime_cmp(xt, less) >= 0) && (boost::xtime_cmp(xt, greater) <= 0);
|
||||
}
|
||||
|
||||
int test_value;
|
||||
|
||||
void simple_thread()
|
||||
{
|
||||
test_value = 999;
|
||||
}
|
||||
|
||||
struct thread_adapter
|
||||
{
|
||||
thread_adapter(void (*func)(boost::thread& parent), boost::thread& parent)
|
||||
: func(func), parent(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void operator()()
|
||||
{
|
||||
(*func)(parent);
|
||||
}
|
||||
|
||||
void (*func)(boost::thread& parent);
|
||||
boost::thread& parent;
|
||||
};
|
||||
|
||||
void comparison_thread(boost::thread& parent)
|
||||
{
|
||||
boost::thread thrd;
|
||||
BOOST_TEST(thrd != parent);
|
||||
BOOST_TEST(thrd == boost::thread());
|
||||
}
|
||||
}
|
||||
|
||||
void test_sleep()
|
||||
{
|
||||
boost::xtime xt = delay(3);
|
||||
boost::xtime xt;
|
||||
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
|
||||
xt.sec += 3;
|
||||
|
||||
boost::thread::sleep(xt);
|
||||
|
||||
// Ensure it's in a range instead of checking actual equality due to time
|
||||
// lapse
|
||||
BOOST_CHECK(in_range(xt));
|
||||
// Insure it's in a range instead of checking actual equality due to time lapse
|
||||
BOOST_CHECK(xtime_in_range(xt, -1, 0));
|
||||
}
|
||||
|
||||
void do_test_creation()
|
||||
void test_creation()
|
||||
{
|
||||
test_value = 0;
|
||||
boost::thread thrd(&simple_thread);
|
||||
@@ -49,27 +70,16 @@ void do_test_creation()
|
||||
BOOST_CHECK_EQUAL(test_value, 999);
|
||||
}
|
||||
|
||||
void test_creation()
|
||||
{
|
||||
timed_test(&do_test_creation, 1);
|
||||
}
|
||||
|
||||
void do_test_comparison()
|
||||
{
|
||||
boost::thread self;
|
||||
boost::thread thrd(bind(&comparison_thread, &self));
|
||||
thrd.join();
|
||||
}
|
||||
|
||||
void test_comparison()
|
||||
{
|
||||
timed_test(&do_test_comparison, 1);
|
||||
boost::thread self;
|
||||
boost::thread thrd(thread_adapter(comparison_thread, self));
|
||||
thrd.join();
|
||||
}
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
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,55 +1,45 @@
|
||||
// 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>
|
||||
|
||||
#include "util.inl"
|
||||
|
||||
boost::mutex tss_mutex;
|
||||
int tss_instances = 0;
|
||||
|
||||
struct tss_value_t
|
||||
namespace
|
||||
{
|
||||
tss_value_t()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(tss_mutex);
|
||||
++tss_instances;
|
||||
value = 0;
|
||||
}
|
||||
~tss_value_t()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(tss_mutex);
|
||||
--tss_instances;
|
||||
}
|
||||
int value;
|
||||
};
|
||||
boost::mutex tss_mutex;
|
||||
int tss_instances = 0;
|
||||
|
||||
boost::thread_specific_ptr<tss_value_t> tss_value;
|
||||
|
||||
void test_tss_thread()
|
||||
{
|
||||
tss_value.reset(new tss_value_t());
|
||||
for (int i=0; i<1000; ++i)
|
||||
struct tss_value_t
|
||||
{
|
||||
int& n = tss_value->value;
|
||||
BOOST_CHECK_EQUAL(n, i);
|
||||
++n;
|
||||
tss_value_t()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(tss_mutex);
|
||||
++tss_instances;
|
||||
value = 0;
|
||||
}
|
||||
~tss_value_t()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(tss_mutex);
|
||||
--tss_instances;
|
||||
}
|
||||
int value;
|
||||
};
|
||||
|
||||
boost::thread_specific_ptr<tss_value_t> tss_value;
|
||||
|
||||
void test_tss_thread()
|
||||
{
|
||||
tss_value.reset(new tss_value_t());
|
||||
for (int i=0; i<1000; ++i)
|
||||
{
|
||||
int& n = tss_value->value;
|
||||
BOOST_CHECK_EQUAL(n, i);
|
||||
++n;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void do_test_tss()
|
||||
void test_tss()
|
||||
{
|
||||
const int NUMTHREADS=5;
|
||||
boost::thread_group threads;
|
||||
@@ -59,15 +49,9 @@ void do_test_tss()
|
||||
BOOST_CHECK_EQUAL(tss_instances, 0);
|
||||
}
|
||||
|
||||
void test_tss()
|
||||
{
|
||||
timed_test(&do_test_tss, 2);
|
||||
}
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: tss test suite");
|
||||
boost::unit_test_framework::test_suite* test = BOOST_TEST_SUITE("Boost.Threads: tss test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(test_tss));
|
||||
|
||||
|
||||
@@ -1,14 +1,3 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <boost/thread/xtime.hpp>
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
@@ -16,9 +5,7 @@
|
||||
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;
|
||||
@@ -40,16 +27,12 @@ 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;
|
||||
@@ -58,8 +41,7 @@ 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
162
test/util.inl
@@ -1,162 +0,0 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#if !defined(UTIL_INL_WEK01242003)
|
||||
#define UTIL_INL_WEK01242003
|
||||
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/condition.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
#ifndef DEFAULT_EXECUTION_MONITOR_TYPE
|
||||
# define DEFAULT_EXECUTION_MONITOR_TYPE execution_monitor::use_condition
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
inline boost::xtime delay(int secs, int msecs=0, int nsecs=0)
|
||||
{
|
||||
const int MILLISECONDS_PER_SECOND = 1000;
|
||||
const int NANOSECONDS_PER_SECOND = 1000000000;
|
||||
const int NANOSECONDS_PER_MILLISECOND = 1000000;
|
||||
|
||||
boost::xtime xt;
|
||||
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC),
|
||||
static_cast<int>(boost::TIME_UTC));
|
||||
|
||||
nsecs += xt.nsec;
|
||||
msecs += nsecs / NANOSECONDS_PER_MILLISECOND;
|
||||
secs += msecs / MILLISECONDS_PER_SECOND;
|
||||
nsecs += (msecs % MILLISECONDS_PER_SECOND) * NANOSECONDS_PER_MILLISECOND;
|
||||
xt.nsec = nsecs % NANOSECONDS_PER_SECOND;
|
||||
xt.sec += secs + (nsecs / NANOSECONDS_PER_SECOND);
|
||||
|
||||
return xt;
|
||||
}
|
||||
|
||||
inline bool in_range(const boost::xtime& xt, int secs=1)
|
||||
{
|
||||
boost::xtime min = delay(-secs);
|
||||
boost::xtime max = delay(0);
|
||||
return (boost::xtime_cmp(xt, min) >= 0) &&
|
||||
(boost::xtime_cmp(xt, max) <= 0);
|
||||
}
|
||||
|
||||
class execution_monitor
|
||||
{
|
||||
public:
|
||||
enum wait_type { use_sleep_only, use_mutex, use_condition };
|
||||
|
||||
execution_monitor(wait_type type, int secs)
|
||||
: done(false), type(type), secs(secs) { }
|
||||
void start()
|
||||
{
|
||||
if (type != use_sleep_only) {
|
||||
boost::mutex::scoped_lock lock(mutex); done = false;
|
||||
} else {
|
||||
done = false;
|
||||
}
|
||||
}
|
||||
void finish()
|
||||
{
|
||||
if (type != use_sleep_only) {
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
done = true;
|
||||
if (type == use_condition)
|
||||
cond.notify_one();
|
||||
} else {
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
bool wait()
|
||||
{
|
||||
boost::xtime xt = delay(secs);
|
||||
if (type != use_condition)
|
||||
boost::thread::sleep(xt);
|
||||
if (type != use_sleep_only) {
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
while (type == use_condition && !done) {
|
||||
if (!cond.timed_wait(lock, xt))
|
||||
break;
|
||||
}
|
||||
return done;
|
||||
}
|
||||
return done;
|
||||
}
|
||||
|
||||
private:
|
||||
boost::mutex mutex;
|
||||
boost::condition cond;
|
||||
bool done;
|
||||
wait_type type;
|
||||
int secs;
|
||||
};
|
||||
|
||||
template <typename F>
|
||||
class indirect_adapter
|
||||
{
|
||||
public:
|
||||
indirect_adapter(F func, execution_monitor& monitor)
|
||||
: func(func), monitor(monitor) { }
|
||||
void operator()() const
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::thread thrd(func);
|
||||
thrd.join();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
monitor.finish();
|
||||
throw;
|
||||
}
|
||||
monitor.finish();
|
||||
}
|
||||
|
||||
private:
|
||||
F func;
|
||||
execution_monitor& monitor;
|
||||
};
|
||||
|
||||
template <typename F>
|
||||
void timed_test(F func, int secs,
|
||||
execution_monitor::wait_type type=DEFAULT_EXECUTION_MONITOR_TYPE)
|
||||
{
|
||||
execution_monitor monitor(type, secs);
|
||||
indirect_adapter<F> ifunc(func, monitor);
|
||||
monitor.start();
|
||||
boost::thread thrd(ifunc);
|
||||
BOOST_REQUIRE_MESSAGE(monitor.wait(),
|
||||
"Timed test didn't complete in time, possible deadlock.");
|
||||
}
|
||||
|
||||
template <typename F, typename T>
|
||||
class binder
|
||||
{
|
||||
public:
|
||||
binder(const F& func, const T& param)
|
||||
: func(func), param(param) { }
|
||||
void operator()() const { func(param); }
|
||||
|
||||
private:
|
||||
F func;
|
||||
T param;
|
||||
};
|
||||
|
||||
template <typename F, typename T>
|
||||
binder<F, T> bind(const F& func, const T& param)
|
||||
{
|
||||
return binder<F, T>(func, param);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
#endif
|
||||
@@ -1,19 +1,8 @@
|
||||
# (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.
|
||||
|
||||
@@ -25,25 +14,17 @@ subproject libs/thread/tutorial ;
|
||||
SEARCH on <module@>threads.jam = $(BOOST_ROOT)/libs/thread/build ;
|
||||
include <module@>threads.jam ;
|
||||
|
||||
{
|
||||
template tutorial
|
||||
## sources ##
|
||||
: <template>thread_base
|
||||
<dll>../build/boost_thread
|
||||
## requirements ##
|
||||
:
|
||||
## default build ##
|
||||
:
|
||||
;
|
||||
template tutorial
|
||||
## sources ##
|
||||
: <template>thread_base <lib>../build/boost_thread <lib>../../test/build/unit_test_framework $(threadmon)
|
||||
## requirements ##
|
||||
:
|
||||
## default build ##
|
||||
: release <runtime-link>static
|
||||
;
|
||||
|
||||
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 factorial : <template>tutorial factorial.cpp ;
|
||||
exe factorial2 : <template>tutorial factorial2.cpp ;
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <boost/thread/condition.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
class bounded_buffer : private boost::noncopyable
|
||||
{
|
||||
public:
|
||||
typedef boost::mutex::scoped_lock lock;
|
||||
bounded_buffer(int n) : begin(0), end(0), buffered(0), circular_buf(n) { }
|
||||
void send (int m) {
|
||||
lock lk(monitor);
|
||||
while (buffered == circular_buf.size())
|
||||
buffer_not_full.wait(lk);
|
||||
circular_buf[end] = m;
|
||||
end = (end+1) % circular_buf.size();
|
||||
++buffered;
|
||||
buffer_not_empty.notify_one();
|
||||
}
|
||||
int receive() {
|
||||
lock lk(monitor);
|
||||
while (buffered == 0)
|
||||
buffer_not_empty.wait(lk);
|
||||
int i = circular_buf[begin];
|
||||
begin = (begin+1) % circular_buf.size();
|
||||
--buffered;
|
||||
buffer_not_full.notify_one();
|
||||
return i;
|
||||
}
|
||||
private:
|
||||
int begin, end, buffered;
|
||||
std::vector<int> circular_buf;
|
||||
boost::condition buffer_not_full, buffer_not_empty;
|
||||
boost::mutex monitor;
|
||||
};
|
||||
bounded_buffer buf(2);
|
||||
|
||||
void sender() {
|
||||
int n = 0;
|
||||
while (n < 100) {
|
||||
buf.send(n);
|
||||
std::cout << "sent: " << n << std::endl;
|
||||
++n;
|
||||
}
|
||||
buf.send(-1);
|
||||
}
|
||||
|
||||
void receiver() {
|
||||
int n;
|
||||
do {
|
||||
n = buf.receive();
|
||||
std::cout << "received: " << n << std::endl;
|
||||
} while (n != -1); // -1 indicates end of buffer
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
boost::thread thrd1(&sender);
|
||||
boost::thread thrd2(&receiver);
|
||||
thrd1.join();
|
||||
thrd2.join();
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <iostream>
|
||||
|
||||
boost::mutex mutex;
|
||||
int counter=0;
|
||||
|
||||
void change_count()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
int i = ++counter;
|
||||
std::cout << "count == " << i << std::endl;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
const int num_threads = 4;
|
||||
boost::thread_group thrds;
|
||||
for (int i=0; i < num_threads; ++i)
|
||||
thrds.create_thread(&change_count);
|
||||
thrds.join_all();
|
||||
}
|
||||
@@ -1,14 +1,3 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <iostream>
|
||||
|
||||
@@ -34,4 +23,4 @@ int main()
|
||||
boost::thread thrd(f);
|
||||
thrd.join();
|
||||
std::cout << "10! = " << result << std::endl;
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,3 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/ref.hpp>
|
||||
#include <iostream>
|
||||
@@ -34,4 +23,4 @@ int main()
|
||||
boost::thread thrd(boost::ref(f));
|
||||
thrd.join();
|
||||
std::cout << "10! = " << f.result() << std::endl;
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <iostream>
|
||||
|
||||
const int NUM_CALCS=5;
|
||||
|
||||
class factorial
|
||||
{
|
||||
public:
|
||||
factorial(int x, int& res) : x(x), res(res) { }
|
||||
void operator()() { res = calculate(x); }
|
||||
int result() const { return res; }
|
||||
|
||||
private:
|
||||
int calculate(int x) { return x <= 1 ? 1 : x * calculate(x-1); }
|
||||
|
||||
private:
|
||||
int x;
|
||||
int& res;
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
int results[NUM_CALCS];
|
||||
boost::thread_group thrds;
|
||||
for (int i=0; i < NUM_CALCS; ++i)
|
||||
thrds.create_thread(factorial(i*10, results[i]));
|
||||
thrds.join_all();
|
||||
for (int j=0; j < NUM_CALCS; ++j)
|
||||
std::cout << j*10 << "! = " << results[j] << std::endl;
|
||||
}
|
||||
@@ -1,14 +1,3 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <iostream>
|
||||
|
||||
@@ -21,4 +10,4 @@ int main()
|
||||
{
|
||||
boost::thread thrd(&helloworld);
|
||||
thrd.join();
|
||||
}
|
||||
}
|
||||
@@ -1,25 +1,15 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <iostream>
|
||||
|
||||
struct helloworld
|
||||
{
|
||||
helloworld() { }
|
||||
void operator()() { std::cout << "Hello World." << std::endl; }
|
||||
helloworld(const char* who) : m_who(who) { }
|
||||
void operator()() { std::cout << m_who << "says, \"Hello World.\"" << std::endl; }
|
||||
const char* m_who;
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
boost::thread thrd(helloworld());
|
||||
boost::thread thrd(helloworld("Bob"));
|
||||
thrd.join();
|
||||
}
|
||||
}
|
||||
@@ -1,26 +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>
|
||||
|
||||
struct helloworld
|
||||
void helloworld(const char* who)
|
||||
{
|
||||
helloworld(const char* who) : m_who(who) { }
|
||||
void operator()() { std::cout << m_who << "says, \"Hello World.\"" << std::endl; }
|
||||
const char* m_who;
|
||||
};
|
||||
std::cout << who << "says, \"Hello World.\"" << std::endl;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
boost::thread thrd(helloworld("Bob"));
|
||||
boost::thread thrd(boost::bind(&helloworld, "Bob"));
|
||||
thrd.join();
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <iostream>
|
||||
|
||||
void helloworld(const char* who)
|
||||
{
|
||||
std::cout << who << "says, \"Hello World.\"" << std::endl;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
boost::thread thrd(boost::bind(&helloworld, "Bob"));
|
||||
thrd.join();
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/once.hpp>
|
||||
#include <cassert>
|
||||
|
||||
int value=0;
|
||||
boost::once_flag once = BOOST_ONCE_INIT;
|
||||
|
||||
void init()
|
||||
{
|
||||
++value;
|
||||
}
|
||||
|
||||
void thread_proc()
|
||||
{
|
||||
boost::call_once(&init, once);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
boost::thread_group threads;
|
||||
for (int i=0; i<5; ++i)
|
||||
threads.create_thread(&thread_proc);
|
||||
threads.join_all();
|
||||
assert(value == 1);
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/tss.hpp>
|
||||
#include <cassert>
|
||||
|
||||
boost::thread_specific_ptr<int> value;
|
||||
|
||||
void increment()
|
||||
{
|
||||
int* p = value.get();
|
||||
++*p;
|
||||
}
|
||||
|
||||
void thread_proc()
|
||||
{
|
||||
value.reset(new int(0)); // initialize the thread's storage
|
||||
for (int i=0; i<10; ++i)
|
||||
{
|
||||
increment();
|
||||
int* p = value.get();
|
||||
assert(*p == i+1);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
boost::thread_group threads;
|
||||
for (int i=0; i<5; ++i)
|
||||
threads.create_thread(&thread_proc);
|
||||
threads.join_all();
|
||||
}
|
||||
Reference in New Issue
Block a user