mirror of
https://github.com/boostorg/thread.git
synced 2026-02-08 23:22:13 +00:00
Compare commits
1 Commits
boost-1.30
...
svn-branch
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f25e80b47c |
@@ -1,11 +1,17 @@
|
|||||||
# (C) Copyright William E. Kempf 2001. Permission to copy, use, modify,
|
# (C) Copyright William E. Kempf 2001. Permission to copy, use, modify, sell and
|
||||||
# sell and distribute this software is granted provided this copyright
|
# distribute this software is granted provided this copyright notice appears
|
||||||
# notice appears in all copies. This software is provided "as is" without
|
# in all copies. This software is provided "as is" without express or implied
|
||||||
# express or implied warranty, and with no claim as to its suitability for
|
# warranty, and with no claim as to its suitability for any purpose.
|
||||||
# any purpose.
|
|
||||||
#
|
#
|
||||||
# Boost.Threads build Jamfile
|
# Boost.Threads build Jamfile
|
||||||
#
|
#
|
||||||
|
# Declares the following targets:
|
||||||
|
# 1. libboost_thread, a static link library.
|
||||||
|
# 1a. On Win32 (when PTW32 is not defined), a dynamic link library
|
||||||
|
# boost_threadmon, which must be used in conjunction with
|
||||||
|
# libboost_thread. Note that this DLL *must* be used through static
|
||||||
|
# linking to the import library. Dynamic loading will cause undefined
|
||||||
|
# behavior.
|
||||||
# Additional configuration variables used:
|
# Additional configuration variables used:
|
||||||
# 1. PTW32 may be used on Win32 platforms to specify that the pthreads-win32
|
# 1. PTW32 may be used on Win32 platforms to specify that the pthreads-win32
|
||||||
# library should be used instead of "native" threads. This feature is
|
# library should be used instead of "native" threads. This feature is
|
||||||
@@ -25,29 +31,40 @@ subproject libs/thread/build ;
|
|||||||
SEARCH on <module@>threads.jam = $(SUBDIR) ;
|
SEARCH on <module@>threads.jam = $(SUBDIR) ;
|
||||||
include <module@>threads.jam ;
|
include <module@>threads.jam ;
|
||||||
|
|
||||||
|
#######################
|
||||||
|
# Conditionally declare the Boost.Threads dynamic link library boost_threadmon.
|
||||||
|
|
||||||
|
if $(NT) && ! $(PTW32)
|
||||||
{
|
{
|
||||||
template thread_libs
|
dll boost_threadmon
|
||||||
## sources ##
|
: ../src/threadmon.cpp
|
||||||
: <template>thread_base
|
: <sysinclude>$(BOOST_ROOT)
|
||||||
## requirements ##
|
<threading>multi
|
||||||
:
|
: debug release <runtime-link>static/dynamic
|
||||||
## default build ##
|
|
||||||
: debug release
|
|
||||||
;
|
|
||||||
|
|
||||||
# Base names of the source files for libboost_thread.
|
|
||||||
CPP_SOURCES = condition mutex recursive_mutex thread tss xtime once
|
|
||||||
exceptions threadmon ;
|
|
||||||
|
|
||||||
dll boost_thread
|
|
||||||
: <template>thread_libs ../src/$(CPP_SOURCES).cpp
|
|
||||||
: <define>BOOST_THREAD_BUILD_DLL=1
|
|
||||||
;
|
|
||||||
|
|
||||||
stage bin-stage
|
|
||||||
: <dll>boost_thread
|
|
||||||
: #<tag><runtime-link-static>"s"
|
|
||||||
<tag><debug>"d"
|
|
||||||
: debug release
|
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#######################
|
||||||
|
# Declare the Boost.Threads static link library libboost_thread.
|
||||||
|
|
||||||
|
# Base names of the source files for libboost_thread.
|
||||||
|
CPP_SOURCES =
|
||||||
|
condition mutex recursive_mutex thread tss xtime once exceptions ;
|
||||||
|
|
||||||
|
lib boost_thread
|
||||||
|
: ../src/$(CPP_SOURCES).cpp
|
||||||
|
: <sysinclude>$(BOOST_ROOT)
|
||||||
|
<threading>multi
|
||||||
|
$(pthreads-win32)
|
||||||
|
: debug release <runtime-link>static/dynamic
|
||||||
|
;
|
||||||
|
|
||||||
|
#######################
|
||||||
|
# Stage the generated targets.
|
||||||
|
|
||||||
|
#stage bin-stage
|
||||||
|
# : <lib>boost_thread $(threadmon)
|
||||||
|
# : <tag><runtime-link-static>"s"
|
||||||
|
# <tag><debug>"d"
|
||||||
|
# : debug release <runtime-link>static/dynamic
|
||||||
|
#;
|
||||||
|
|||||||
@@ -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,5 +1,6 @@
|
|||||||
# Do some OS-specific setup
|
# Do some OS-specific setup
|
||||||
{
|
|
||||||
|
threadmon = ;
|
||||||
pthreads-win32 = ;
|
pthreads-win32 = ;
|
||||||
|
|
||||||
if $(NT)
|
if $(NT)
|
||||||
@@ -15,15 +16,8 @@
|
|||||||
<library-file>$(install-path)/pre-built/lib/$(lib)
|
<library-file>$(install-path)/pre-built/lib/$(lib)
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
threadmon = <dll>../build/boost_threadmon ;
|
||||||
}
|
}
|
||||||
|
|
||||||
template thread_base
|
|
||||||
## sources ##
|
|
||||||
:
|
|
||||||
## requirements ##
|
|
||||||
: <sysinclude>$(BOOST_ROOT) <threading>multi $(pthreads-win32)
|
|
||||||
<borland><*><cxxflags>-w-8004
|
|
||||||
## default build ##
|
|
||||||
:
|
|
||||||
;
|
|
||||||
}
|
}
|
||||||
Binary file not shown.
@@ -27,8 +27,8 @@
|
|||||||
Win32 implementation, especially in regards to boost::condition, as well as
|
Win32 implementation, especially in regards to boost::condition, as well as
|
||||||
a lot of explanation of POSIX behavior), Greg Colvin (lots of input on the design),
|
a lot of explanation of POSIX behavior), Greg Colvin (lots of input on the design),
|
||||||
Paul Mclachlan, Thomas Matelich and Iain Hanson (for help in trying to get the
|
Paul Mclachlan, Thomas Matelich and Iain Hanson (for help in trying to get the
|
||||||
build to work on other platforms), Kevin S. Van Horn (for several updates/corrections
|
build to work on other platforms), and Kevin S. Van Horn (for several updates/corrections
|
||||||
to the documentation), and Martin Johnson (shared library implementation).</p>
|
to the documentation).</p>
|
||||||
<p>The documentation was written by William E. Kempf. Beman Dawes provided additional
|
<p>The documentation was written by William E. Kempf. Beman Dawes provided additional
|
||||||
documentation material and editing.</p>
|
documentation material and editing.</p>
|
||||||
<p>Discussions on the boost.org mailing list were essential in the development
|
<p>Discussions on the boost.org mailing list were essential in the development
|
||||||
|
|||||||
@@ -1,77 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
|
||||||
<link rel="stylesheet" type="text/css" href="../../../boost.css">
|
|
||||||
<title>{{Library}} - Overview</title>
|
|
||||||
</head>
|
|
||||||
<body link="#0000ff" vlink="#800080">
|
|
||||||
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
|
|
||||||
"header">
|
|
||||||
<tr>
|
|
||||||
<td valign="top" width="300">
|
|
||||||
<h3><a href="../../../index.htm"><img height="86" width="277" alt="C++ Boost" src="../../../c++boost.gif" border="0"></a></h3>
|
|
||||||
</td>
|
|
||||||
<td valign="top">
|
|
||||||
<h1 align="center">Boost.Threads</h1>
|
|
||||||
<h2 align="center">Building and Testing</h2>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<hr>
|
|
||||||
<dl class="index">
|
|
||||||
<dt><a href="#introduction">Introduction</a></dt>
|
|
||||||
<dt><a href="#topic1">First topic</a></dt>
|
|
||||||
<dt><a href="#topic2">Second topic</a></dt>
|
|
||||||
<dt><a href="#footnotes">Footnotes</a></dt>
|
|
||||||
</dl>
|
|
||||||
<h2><a name="introduction"></a>Introduction</h2>
|
|
||||||
<p>How you build the Boost.Threads libraries, and how you build your own applications
|
|
||||||
that use those libraries, are some of the most frequently asked questions. Build
|
|
||||||
processes are difficult to deal with in a portable manner. That's one reason
|
|
||||||
why Boost.Threads makes use of <a href="../../../tools/build/index.html">Boost.Build</a>.
|
|
||||||
In general you should refer to the documentation for <a href="../../../tools/build/index.html">Boost.Build</a>.
|
|
||||||
This document will only supply you with some simple usage examples for how to
|
|
||||||
use <em>bjam</em> to build and test Boost.Threads. In addition, this document
|
|
||||||
will try and explain the build requirements so that users may create their own
|
|
||||||
build processes (for instance, create an IDE specific project), both for building
|
|
||||||
and testing Boost.Threads, as well as for building their own projects using
|
|
||||||
Boost.Threads. </p>
|
|
||||||
<h2><a name="topic1"></a>Building the Boost.Threads Libraries</h2>
|
|
||||||
<p>To build the Boost.Thread libraries using Boost.Build, simply change to the
|
|
||||||
directory <em>boost_root</em>/libs/thread/build and execute the command:</p>
|
|
||||||
<pre>bjam -sTOOLS=<em>toolset</em></pre>
|
|
||||||
<p>This will create four variants of the Boost.Threads library with the permuations
|
|
||||||
of debug/release and runtime-link-dynamic/runtime-link-static. <em><strong>Note:</strong></em>
|
|
||||||
Invoking the above command in <em>boost_root</em> will build all of the Boost
|
|
||||||
distribution, including Boost.Threads.</p>
|
|
||||||
<p>The Jamfile supplied with Boost.Threads produces a static library named <em>libboostthread</em>.
|
|
||||||
In addition, on Win32 platforms a <em>boostthreadmon.dll</em> and a coresponding
|
|
||||||
import library are created. The source files that are used to create the <em>libboostthread</em>
|
|
||||||
library are all of the *.cpp files found in <em>boost_root</em>/libs/thread/src,
|
|
||||||
except for <em>threadmon.cpp</em>. These need to be built with the compiler's
|
|
||||||
and linker's multi-threading support enabled. On Win32 platforms the <em>boostthreadmon.dll</em>
|
|
||||||
is created from <em>boost_root</em>/libs/thread/src/threadmon.cpp. This, too,
|
|
||||||
needs to be built with the compiler's and linker's multi-threading support enabled.
|
|
||||||
If you want to create your own build solution you'll have to follow these same
|
|
||||||
guidelines. One of the most frequently reported problems when trying to do this
|
|
||||||
occurs from not enabling the compiler's and linker's support for multi-threading.</p>
|
|
||||||
<h2><a name="topic2"></a>Testing the Boost.Threads Libraries</h2>
|
|
||||||
<p>To test the Boost.Threads libraries using Boost.Build, simply change to the
|
|
||||||
directory <em>boost_root</em>/libs/thread/test and execute the command:</p>
|
|
||||||
<pre><code>bjam -sTOOLS=<em>toolset</em> test</code></pre>
|
|
||||||
<p> </p>
|
|
||||||
<h2><a name="footnotes"></a>Footnotes</h2>
|
|
||||||
<dl>
|
|
||||||
<dt><a name="footnote1" class="footnote">(1)</a> {{text}}</dt>
|
|
||||||
<dt><a name="footnote2" class="footnote">(2)</a> {{text}}</dt>
|
|
||||||
</dl>
|
|
||||||
<hr>
|
|
||||||
<p>Revised
|
|
||||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
|
||||||
05 November, 2001
|
|
||||||
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
|
|
||||||
</p>
|
|
||||||
<p><i>© Copyright <a href="mailto:{{address}}">{{author}}</a>
|
|
||||||
2002. All Rights Reserved.</i></p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -61,9 +61,10 @@
|
|||||||
states <a href="definitions.html#state"> blocked</a> and <a href="definitions.html#state">ready</a>.
|
states <a href="definitions.html#state"> blocked</a> and <a href="definitions.html#state">ready</a>.
|
||||||
Note that "waiting" is a synonym for blocked.</p>
|
Note that "waiting" is a synonym for blocked.</p>
|
||||||
<h4><a name="class-condition-synopsis"></a>Class <code>condition</code> synopsis</h4>
|
<h4><a name="class-condition-synopsis"></a>Class <code>condition</code> synopsis</h4>
|
||||||
<pre>namespace boost
|
<pre>
|
||||||
|
namespace boost
|
||||||
{
|
{
|
||||||
class condition : private <a href="../../utility/utility.htm#Class_noncopyable">boost::noncopyable</a> // Exposition only.
|
class condition : private <a href="../../utility/utility.htm#Class noncopyable">boost::noncopyable</a> // Exposition only.
|
||||||
// Class condition meets the <a href="overview.html#non-copyable">NonCopyable</a> requirement.
|
// Class condition meets the <a href="overview.html#non-copyable">NonCopyable</a> requirement.
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -85,19 +86,22 @@
|
|||||||
</pre>
|
</pre>
|
||||||
<h4><a name="class-condition-ctors"></a>Class <code>condition</code> constructors
|
<h4><a name="class-condition-ctors"></a>Class <code>condition</code> constructors
|
||||||
and destructor</h4>
|
and destructor</h4>
|
||||||
<pre>condition();
|
<pre>
|
||||||
|
condition();
|
||||||
</pre>
|
</pre>
|
||||||
<dl class="function-semantics">
|
<dl class="function-semantics">
|
||||||
<dt><b>Effects:</b> Constructs a <code>condition</code> object.</dt>
|
<dt><b>Effects:</b> Constructs a <code>condition</code> object.</dt>
|
||||||
</dl>
|
</dl>
|
||||||
<pre>~condition();
|
<pre>
|
||||||
|
~condition();
|
||||||
</pre>
|
</pre>
|
||||||
<dl class="function-semantics">
|
<dl class="function-semantics">
|
||||||
<dt><b>Effects:</b> Destroys <code>*this</code>.</dt>
|
<dt><b>Effects:</b> Destroys <code>*this</code>.</dt>
|
||||||
</dl>
|
</dl>
|
||||||
<h4><a name="class-condition-modifiers"></a>Class <code>condition</code> modifier
|
<h4><a name="class-condition-modifiers"></a>Class <code>condition</code> modifier
|
||||||
functions</h4>
|
functions</h4>
|
||||||
<pre>void notify_one();
|
<pre>
|
||||||
|
void notify_one();
|
||||||
</pre>
|
</pre>
|
||||||
<dl class="function-semantics">
|
<dl class="function-semantics">
|
||||||
<dt><b>Effects:</b> If there is a thread waiting on <code>*this</code>, change
|
<dt><b>Effects:</b> If there is a thread waiting on <code>*this</code>, change
|
||||||
@@ -107,14 +111,16 @@
|
|||||||
thread must still acquire the mutex again (which occurs within the call to
|
thread must still acquire the mutex again (which occurs within the call to
|
||||||
one of the <code>condition</code> object's wait functions).</dt>
|
one of the <code>condition</code> object's wait functions).</dt>
|
||||||
</dl>
|
</dl>
|
||||||
<pre>void notify_all();
|
<pre>
|
||||||
|
void notify_all();
|
||||||
</pre>
|
</pre>
|
||||||
<dl class="function-semantics">
|
<dl class="function-semantics">
|
||||||
<dt><b>Effects:</b> Change the state of all threads waiting on <code> *this</code>
|
<dt><b>Effects:</b> Change the state of all threads waiting on <code> *this</code>
|
||||||
to ready. If there are no waiting threads, <code> notify_all()</code> has
|
to ready. If there are no waiting threads, <code> notify_all()</code> has
|
||||||
no effect.</dt>
|
no effect.</dt>
|
||||||
</dl>
|
</dl>
|
||||||
<pre>template <typename ScopedLock>
|
<pre>
|
||||||
|
template <typename ScopedLock>
|
||||||
void wait(ScopedLock& lock);
|
void wait(ScopedLock& lock);
|
||||||
</pre>
|
</pre>
|
||||||
<dl class="function-semantics">
|
<dl class="function-semantics">
|
||||||
@@ -132,7 +138,8 @@
|
|||||||
wake ups". The second version encapsulates this loop idiom internally
|
wake ups". The second version encapsulates this loop idiom internally
|
||||||
and is generally the preferred method.</dt>
|
and is generally the preferred method.</dt>
|
||||||
</dl>
|
</dl>
|
||||||
<pre>Template<typename ScopedLock, typename Pr>
|
<pre>
|
||||||
|
Template<typename ScopedLock, typename Pr>
|
||||||
void wait(ScopedLock& lock, Pr pred);
|
void wait(ScopedLock& lock, Pr pred);
|
||||||
</pre>
|
</pre>
|
||||||
<dl class="function-semantics">
|
<dl class="function-semantics">
|
||||||
@@ -142,7 +149,8 @@
|
|||||||
<dt><b>Throws:</b> <code><a href="exceptions.html#class-lock_error">lock_error</a></code>
|
<dt><b>Throws:</b> <code><a href="exceptions.html#class-lock_error">lock_error</a></code>
|
||||||
if <code>!lock.locked()</code></dt>
|
if <code>!lock.locked()</code></dt>
|
||||||
</dl>
|
</dl>
|
||||||
<pre>template <typename ScopedLock>
|
<pre>
|
||||||
|
template <typename ScopedLock>
|
||||||
bool timed_wait(ScopedLock& lock, const <a href="xtime.html">xtime</a>& XT);
|
bool timed_wait(ScopedLock& lock, const <a href="xtime.html">xtime</a>& XT);
|
||||||
</pre>
|
</pre>
|
||||||
<dl class="function-semantics">
|
<dl class="function-semantics">
|
||||||
@@ -163,14 +171,16 @@
|
|||||||
ups". The second version encapsulates this loop idiom internally and
|
ups". The second version encapsulates this loop idiom internally and
|
||||||
is generally the preferred method.</dt>
|
is generally the preferred method.</dt>
|
||||||
</dl>
|
</dl>
|
||||||
<pre>Template<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);
|
bool timed_wait(ScopedLock& lock, const <a href="xtime.html">xtime</a>& XT, Pr pred);
|
||||||
</pre>
|
</pre>
|
||||||
<dl class="function-semantics">
|
<dl class="function-semantics">
|
||||||
<dt><b>Requires:</b> <code>ScopedLock</code> meets the <a href="lock_concept.html#ScopedLock">ScopedLock</a>
|
<dt><b>Requires:</b> <code>ScopedLock</code> meets the <a href="lock_concept.html#ScopedLock">ScopedLock</a>
|
||||||
requirements, return from <code>pred()</code> convertible to bool.</dt>
|
requirements, return from <code>pred()</code> convertible to bool.</dt>
|
||||||
<dt><b>Effects:</b> As if:<br>
|
<dt><b>Effects:</b> As if:<br>
|
||||||
<pre>while (!pred())
|
<pre>
|
||||||
|
while (!pred())
|
||||||
{
|
{
|
||||||
if (!timed_wait(lock, XT))
|
if (!timed_wait(lock, XT))
|
||||||
return false;
|
return false;
|
||||||
@@ -184,9 +194,79 @@ return true;
|
|||||||
if <code>!lock.locked()</code></dt>
|
if <code>!lock.locked()</code></dt>
|
||||||
</dl>
|
</dl>
|
||||||
<h2><a name="examples"></a>Example(s)</h2>
|
<h2><a name="examples"></a>Example(s)</h2>
|
||||||
<p><a href="../example/condition.cpp">libs/thread/example/condition.cpp</a></p>
|
<pre>
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <a href="../../../boost/utility.hpp"><boost/utility.hpp></a>
|
||||||
|
#include <a href="../../../boost/thread/condition.hpp"><boost/thread/condition.hpp></a>
|
||||||
|
#include <a href="../../../boost/thread/thread.hpp"><boost/thread/thread.hpp></a>
|
||||||
|
|
||||||
|
class bounded_buffer : private boost::noncopyable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef boost::mutex::scoped_lock lock;
|
||||||
|
|
||||||
|
bounded_buffer(int n) : begin(0), end(0), buffered(0), circular_buf(n) { }
|
||||||
|
|
||||||
|
void send (int m) {
|
||||||
|
lock lk(monitor);
|
||||||
|
while (buffered == circular_buf.size())
|
||||||
|
buffer_not_full.wait(lk);
|
||||||
|
circular_buf[end] = m;
|
||||||
|
end = (end+1) % circular_buf.size();
|
||||||
|
++buffered;
|
||||||
|
buffer_not_empty.notify_one();
|
||||||
|
}
|
||||||
|
int receive() {
|
||||||
|
lock lk(monitor);
|
||||||
|
while (buffered == 0)
|
||||||
|
buffer_not_empty.wait(lk);
|
||||||
|
int i = circular_buf[begin];
|
||||||
|
begin = (begin+1) % circular_buf.size();
|
||||||
|
--buffered;
|
||||||
|
buffer_not_full.notify_one();
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int begin, end, buffered;
|
||||||
|
std::vector<int> circular_buf;
|
||||||
|
boost::condition buffer_not_full, buffer_not_empty;
|
||||||
|
boost::mutex monitor;
|
||||||
|
};
|
||||||
|
|
||||||
|
bounded_buffer buf(2);
|
||||||
|
|
||||||
|
void sender() {
|
||||||
|
int n = 0;
|
||||||
|
while (n < 100) {
|
||||||
|
buf.send(n);
|
||||||
|
std::cout << "sent: " << n << std::endl;
|
||||||
|
++n;
|
||||||
|
}
|
||||||
|
buf.send(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void receiver() {
|
||||||
|
int n;
|
||||||
|
do {
|
||||||
|
n = buf.receive();
|
||||||
|
std::cout << "received: " << n << std::endl;
|
||||||
|
} while (n != -1); // -1 indicates end of buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int, char*[])
|
||||||
|
{
|
||||||
|
boost::thread thrd1(&sender);
|
||||||
|
boost::thread thrd2(&receiver);
|
||||||
|
thrd1.join();
|
||||||
|
thrd2.join();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
<p>Typical output (dependent on scheduling policies) is:</p>
|
<p>Typical output (dependent on scheduling policies) is:</p>
|
||||||
<pre>sent: 0
|
<pre>
|
||||||
|
sent: 0
|
||||||
sent: 1
|
sent: 1
|
||||||
received: 0
|
received: 0
|
||||||
received: 1
|
received: 1
|
||||||
@@ -198,7 +278,9 @@ sent: 4
|
|||||||
received: 4
|
received: 4
|
||||||
</pre>
|
</pre>
|
||||||
<p>Revised
|
<p>Revised
|
||||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->09 January, 2003<!--webbot bot="Timestamp" endspan i-checksum="38582" -->
|
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
||||||
|
05 November, 2001
|
||||||
|
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
|
||||||
</p>
|
</p>
|
||||||
<p><i>© Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
|
<p><i>© Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
|
||||||
All Rights Reserved.</i></p>
|
All Rights Reserved.</i></p>
|
||||||
|
|||||||
@@ -241,17 +241,18 @@
|
|||||||
there is no matching exception handler in a program [15.3/9]. That is, terminate()
|
there is no matching exception handler in a program [15.3/9]. That is, terminate()
|
||||||
is called, and it is implementation defined whether or not the stack is unwound.</p>
|
is called, and it is implementation defined whether or not the stack is unwound.</p>
|
||||||
<h2><a name="acknowledgements"></a>Acknowledgments</h2>
|
<h2><a name="acknowledgements"></a>Acknowledgments</h2>
|
||||||
<p>This document was originally written by Beman Dawes, and then much improved by the incorporation of comments from
|
<p>This document has been much improved by the incorporation of comments from
|
||||||
William Kempf, who now maintains the contents.</p>
|
William Kempf.</p>
|
||||||
<p>The visibility rules are based on <a href=
|
<p>The visibility rules are based on <a href=
|
||||||
"bibliography.html#Butenhof-97">[Butenhof 97]</a>.</p>
|
"bibliography.html#Butenhof-97">[Butenhof 97]</a>.</p>
|
||||||
<hr>
|
<hr>
|
||||||
<p>Revised
|
<p>Revised
|
||||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->06 October, 2002<!--webbot bot="Timestamp" endspan i-checksum="38429" -->
|
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
||||||
|
05 November, 2001
|
||||||
|
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
|
||||||
</p>
|
</p>
|
||||||
<p><i>© Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
|
<p><i>© Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
|
||||||
All Rights Reserved.<br>
|
All Rights Reserved.</i></p>
|
||||||
</i>© Copyright Beman Dawes, 2001</p>
|
|
||||||
<p>Permission to use, copy, modify, distribute and sell this software and its
|
<p>Permission to use, copy, modify, distribute and sell this software and its
|
||||||
documentation for any purpose is hereby granted without fee, provided that the
|
documentation for any purpose is hereby granted without fee, provided that the
|
||||||
above copyright notice appear in all copies and that both that copyright notice
|
above copyright notice appear in all copies and that both that copyright notice
|
||||||
|
|||||||
11
doc/faq.html
11
doc/faq.html
@@ -86,7 +86,8 @@
|
|||||||
"definitions.html#Thread-safe">thread-safe</a>. The following is a simple
|
"definitions.html#Thread-safe">thread-safe</a>. The following is a simple
|
||||||
example of a class with copyable semantics and internal synchronization through
|
example of a class with copyable semantics and internal synchronization through
|
||||||
a mutex member.</p>
|
a mutex member.</p>
|
||||||
<pre>class counter
|
<pre>
|
||||||
|
class counter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// Doesn't need synchronization since there can be no references to *this
|
// Doesn't need synchronization since there can be no references to *this
|
||||||
@@ -144,8 +145,8 @@ private:
|
|||||||
a mutex member as mutable clearly documents the intended semantics.</p>
|
a mutex member as mutable clearly documents the intended semantics.</p>
|
||||||
<h2><a name="question7"></a>7. Why supply <a href="condition.html">condition variables</a>
|
<h2><a name="question7"></a>7. Why supply <a href="condition.html">condition variables</a>
|
||||||
rather than <a href="rationale.html#Events">event variables</a>?</h2>
|
rather than <a href="rationale.html#Events">event variables</a>?</h2>
|
||||||
<p>Condition variables result in user code much less prone to
|
<p>Condition variables result in user code much less prone to <a href=
|
||||||
<a href="definitions.html#definition-race-condition">race conditions</a> than event variables.
|
"definitions.html#Race condition">race conditions</a> than event variables.
|
||||||
See <a href="rationale.html#Events">Rationale</a> for analysis. Also see <a href="bibliography.html#Hoare-74">[Hoare
|
See <a href="rationale.html#Events">Rationale</a> for analysis. Also see <a href="bibliography.html#Hoare-74">[Hoare
|
||||||
74]</a> and <a href="bibliography.html#Schmidt-00">[Schmidt 00]</a>.</p>
|
74]</a> and <a href="bibliography.html#Schmidt-00">[Schmidt 00]</a>.</p>
|
||||||
<h2><a name="question8"></a>8. Why isn't thread cancellation or termination
|
<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>
|
greater safety by the combination of a mutex and a condition variable.</p>
|
||||||
<hr>
|
<hr>
|
||||||
<p>Revised
|
<p>Revised
|
||||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->09 January, 2003<!--webbot bot="Timestamp" endspan i-checksum="38582" -->
|
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
||||||
|
05 November, 2001
|
||||||
|
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
|
||||||
</p>
|
</p>
|
||||||
<p><i>© Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
|
<p><i>© Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
|
||||||
All Rights Reserved.</i></p>
|
All Rights Reserved.</i></p>
|
||||||
|
|||||||
@@ -130,7 +130,6 @@
|
|||||||
</dl>
|
</dl>
|
||||||
</dl>
|
</dl>
|
||||||
<dt><a href="configuration.html">Configuration Information</a></dt>
|
<dt><a href="configuration.html">Configuration Information</a></dt>
|
||||||
<dt><a href="build.html">Building and Testing</a></dt>
|
|
||||||
<dt><a href="introduction.html">Introduction to Design</a></dt>
|
<dt><a href="introduction.html">Introduction to Design</a></dt>
|
||||||
<dt><a href="rationale.html">Rationale</a></dt>
|
<dt><a href="rationale.html">Rationale</a></dt>
|
||||||
<dt><a href="definitions.html">Definitions</a></dt>
|
<dt><a href="definitions.html">Definitions</a></dt>
|
||||||
|
|||||||
@@ -217,7 +217,52 @@ timed_mutex();
|
|||||||
resulting in undefined behavior such as a program crash.</dt>
|
resulting in undefined behavior such as a program crash.</dt>
|
||||||
</dl>
|
</dl>
|
||||||
<h2><a name="examples"></a>Example(s)</h2>
|
<h2><a name="examples"></a>Example(s)</h2>
|
||||||
<p><a href="../example/mutex.cpp">libs/thread/example/mutex.cpp</a></p>
|
<pre>
|
||||||
|
#include <a href=
|
||||||
|
"../../../boost/thread/mutex.hpp"><boost/thread/mutex.hpp></a>
|
||||||
|
#include <a href=
|
||||||
|
"../../../boost/thread/thread.hpp"><boost/thread/thread.hpp></a>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
boost::mutex io_mutex; // The iostreams are not guaranteed to be <a href=
|
||||||
|
"definitions.html#Thread-safe">thread-safe</a>!
|
||||||
|
|
||||||
|
class counter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
counter() : count(0) { }
|
||||||
|
|
||||||
|
int increment() {
|
||||||
|
boost::mutex::scoped_lock scoped_lock(mutex);
|
||||||
|
return ++count;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
boost::mutex mutex;
|
||||||
|
int count;
|
||||||
|
};
|
||||||
|
|
||||||
|
counter c;
|
||||||
|
|
||||||
|
void change_count()
|
||||||
|
{
|
||||||
|
int i = c.increment();
|
||||||
|
boost::mutex::scoped_lock scoped_lock(io_mutex);
|
||||||
|
std::cout << "count == " << i << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int, char*[])
|
||||||
|
{
|
||||||
|
const int num_threads = 4;
|
||||||
|
boost::thread_group thrds;
|
||||||
|
for (int i=0; i < num_threads; ++i)
|
||||||
|
thrds.create_thread(&change_count);
|
||||||
|
|
||||||
|
thrds.join_all();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
<p>The output is:</p>
|
<p>The output is:</p>
|
||||||
<pre>
|
<pre>
|
||||||
count == 1
|
count == 1
|
||||||
|
|||||||
@@ -145,7 +145,7 @@
|
|||||||
<p>A Mutex object has two states: locked and unlocked. Mutex object state can
|
<p>A Mutex object has two states: locked and unlocked. Mutex object state can
|
||||||
only be determined by an object meeting the <a href="lock_concept.html#ScopedLock">ScopedLock</a>
|
only be determined by an object meeting the <a href="lock_concept.html#ScopedLock">ScopedLock</a>
|
||||||
requirements and constructed for the Mutex object.</p>
|
requirements and constructed for the Mutex object.</p>
|
||||||
<p>A Mutex is <a href="../../utility/utility.htm#Class_noncopyable">NonCopyable</a>.</p>
|
<p>A Mutex is <a href="../../utility/utility.htm#Class noncopyable">NonCopyable</a>.</p>
|
||||||
<p>For a Mutex type M and an object m of that type, the following expressions
|
<p>For a Mutex type M and an object m of that type, the following expressions
|
||||||
must be well-formed and have the indicated effects.</p>
|
must be well-formed and have the indicated effects.</p>
|
||||||
<table summary="Mutex expressions" border="1" cellpadding="5">
|
<table summary="Mutex expressions" border="1" cellpadding="5">
|
||||||
@@ -223,7 +223,9 @@
|
|||||||
</table>
|
</table>
|
||||||
<hr>
|
<hr>
|
||||||
<p>Revised
|
<p>Revised
|
||||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->09 January, 2003<!--webbot bot="Timestamp" endspan i-checksum="38582" -->
|
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
||||||
|
05 November, 2001
|
||||||
|
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
|
||||||
</p>
|
</p>
|
||||||
<p><i>© Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
|
<p><i>© Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
|
||||||
All Rights Reserved.</i></p>
|
All Rights Reserved.</i></p>
|
||||||
|
|||||||
@@ -71,7 +71,33 @@ if (flag == BOOST_ONCE_INIT)
|
|||||||
<dt><b>Postconditions:</b> <code>flag != BOOST_ONCE_INIT</code></dt>
|
<dt><b>Postconditions:</b> <code>flag != BOOST_ONCE_INIT</code></dt>
|
||||||
</dl>
|
</dl>
|
||||||
<h2><a name="examples"></a>Example(s)</h2>
|
<h2><a name="examples"></a>Example(s)</h2>
|
||||||
<p><a href="../example/once.cpp">libs/thread/example/once.cpp</a></p>
|
<pre>
|
||||||
|
#include <a href="../../../boost/thread/thread.hpp"><boost/thread/thread.hpp></a>
|
||||||
|
#include <a href="../../../boost/thread/tss.hpp"><boost/thread/once.hpp></a>
|
||||||
|
#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);
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
<hr>
|
<hr>
|
||||||
<p>Revised
|
<p>Revised
|
||||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
||||||
|
|||||||
@@ -110,8 +110,7 @@
|
|||||||
<p><b>Warning:</b> Multithreaded programs such as those using <b> Boost.Threads</b>
|
<p><b>Warning:</b> Multithreaded programs such as those using <b> Boost.Threads</b>
|
||||||
must link to <a href="definitions.html#Thread-safe"> thread-safe</a> versions
|
must link to <a href="definitions.html#Thread-safe"> thread-safe</a> versions
|
||||||
of all runtime libraries used by the program, including the runtime library
|
of all runtime libraries used by the program, including the runtime library
|
||||||
for the C++ Standard Library. Otherwise
|
for the C++ Standard Library. Otherwise <a href="definitions.html#Race condition">race
|
||||||
<a href="definitions.html#definition-race-condition">race
|
|
||||||
conditions</a> will occur when multiple threads simultaneously execute runtime
|
conditions</a> will occur when multiple threads simultaneously execute runtime
|
||||||
library functions for <i>new</i>, <i>delete</i>, or other language features
|
library functions for <i>new</i>, <i>delete</i>, or other language features
|
||||||
which imply shared state.</p>
|
which imply shared state.</p>
|
||||||
@@ -158,7 +157,9 @@
|
|||||||
as implementations are free to meet the NonCopyable requirement in other ways.</p>
|
as implementations are free to meet the NonCopyable requirement in other ways.</p>
|
||||||
<hr>
|
<hr>
|
||||||
<p>Revised
|
<p>Revised
|
||||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->09 January, 2003<!--webbot bot="Timestamp" endspan i-checksum="38582" -->
|
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
||||||
|
05 November, 2001
|
||||||
|
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
|
||||||
</p>
|
</p>
|
||||||
<p><i>© Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
|
<p><i>© Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
|
||||||
All Rights Reserved.</i></p>
|
All Rights Reserved.</i></p>
|
||||||
|
|||||||
@@ -144,27 +144,31 @@
|
|||||||
appear to bear them out. To illustrate the analysis we'll first provide
|
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>
|
pseudo-code illustrating the six typical usage patterns of a thread object.</p>
|
||||||
<h3>1. Simple creation of a thread.</h3>
|
<h3>1. Simple creation of a thread.</h3>
|
||||||
<pre>void foo()
|
<pre>
|
||||||
|
void foo()
|
||||||
{
|
{
|
||||||
create_thread(&bar);
|
create_thread(&bar);
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
<h3>2. Creation of a thread that's later joined.</h3>
|
<h3>2. Creation of a thread that's later joined.</h3>
|
||||||
<pre>Void foo()
|
<pre>
|
||||||
|
Void foo()
|
||||||
{
|
{
|
||||||
thread = create_thread(&bar);
|
thread = create_thread(&bar);
|
||||||
join(thread);
|
join(thread);
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
<h3>3. Simple creation of several threads in a loop.</h3>
|
<h3>3. Simple creation of several threads in a loop.</h3>
|
||||||
<pre>Void foo()
|
<pre>
|
||||||
|
Void foo()
|
||||||
{
|
{
|
||||||
for (int i=0; i<NUM_THREADS; ++i)
|
for (int i=0; i<NUM_THREADS; ++i)
|
||||||
create_thread(&bar);
|
create_thread(&bar);
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
<h3>4. Creation of several threads in a loop which are later joined.</h3>
|
<h3>4. Creation of several threads in a loop which are later joined.</h3>
|
||||||
<pre>Void foo()
|
<pre>
|
||||||
|
Void foo()
|
||||||
{
|
{
|
||||||
for (int i=0; i<NUM_THREADS; ++i)
|
for (int i=0; i<NUM_THREADS; ++i)
|
||||||
threads[i] = create_thread(&bar);
|
threads[i] = create_thread(&bar);
|
||||||
@@ -173,14 +177,16 @@
|
|||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
<h3>5. Creation of a thread whose ownership is passed to another object/method.</h3>
|
<h3>5. Creation of a thread whose ownership is passed to another object/method.</h3>
|
||||||
<pre>Void foo()
|
<pre>
|
||||||
|
Void foo()
|
||||||
{
|
{
|
||||||
thread = create_thread(&bar);
|
thread = create_thread(&bar);
|
||||||
manager.owns(thread);
|
manager.owns(thread);
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
<h3>6. Creation of a thread whose ownership is shared between multiple objects.</h3>
|
<h3>6. Creation of a thread whose ownership is shared between multiple objects.</h3>
|
||||||
<pre>Void foo()
|
<pre>
|
||||||
|
Void foo()
|
||||||
{
|
{
|
||||||
thread = create_thread(&bar);
|
thread = create_thread(&bar);
|
||||||
manager1.add(thread);
|
manager1.add(thread);
|
||||||
@@ -205,7 +211,8 @@
|
|||||||
for any of the usage patterns there would be a good argument for choosing the
|
for any of the usage patterns there would be a good argument for choosing the
|
||||||
other design. So we'll code all six usage patterns using both designs.</p>
|
other design. So we'll code all six usage patterns using both designs.</p>
|
||||||
<h3>1.</h3>
|
<h3>1.</h3>
|
||||||
<pre>void foo()
|
<pre>
|
||||||
|
void foo()
|
||||||
{
|
{
|
||||||
thread thrd(&bar);
|
thread thrd(&bar);
|
||||||
}
|
}
|
||||||
@@ -216,7 +223,8 @@ void foo()
|
|||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
<h3>2.</h3>
|
<h3>2.</h3>
|
||||||
<pre>void foo()
|
<pre>
|
||||||
|
void foo()
|
||||||
{
|
{
|
||||||
thread thrd(&bar);
|
thread thrd(&bar);
|
||||||
thrd.join();
|
thrd.join();
|
||||||
@@ -229,7 +237,8 @@ void foo()
|
|||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
<h3>3.</h3>
|
<h3>3.</h3>
|
||||||
<pre>void foo()
|
<pre>
|
||||||
|
void foo()
|
||||||
{
|
{
|
||||||
for (int i=0; i<NUM_THREADS; ++i)
|
for (int i=0; i<NUM_THREADS; ++i)
|
||||||
thread thrd(&bar);
|
thread thrd(&bar);
|
||||||
@@ -242,7 +251,8 @@ void foo()
|
|||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
<h3>4.</h3>
|
<h3>4.</h3>
|
||||||
<pre>void foo()
|
<pre>
|
||||||
|
void foo()
|
||||||
{
|
{
|
||||||
std::auto_ptr<thread> threads[NUM_THREADS];
|
std::auto_ptr<thread> threads[NUM_THREADS];
|
||||||
for (int i=0; i<NUM_THREADS; ++i)
|
for (int i=0; i<NUM_THREADS; ++i)
|
||||||
@@ -261,7 +271,8 @@ void foo()
|
|||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
<h3>5.</h3>
|
<h3>5.</h3>
|
||||||
<pre>void foo()
|
<pre>
|
||||||
|
void foo()
|
||||||
{
|
{
|
||||||
thread thrd* = new thread(&bar);
|
thread thrd* = new thread(&bar);
|
||||||
manager.owns(thread);
|
manager.owns(thread);
|
||||||
@@ -274,7 +285,8 @@ void foo()
|
|||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
<h3>6.</h3>
|
<h3>6.</h3>
|
||||||
<pre>void foo()
|
<pre>
|
||||||
|
void foo()
|
||||||
{
|
{
|
||||||
boost::shared_ptr<thread> thrd(new thread(&bar));
|
boost::shared_ptr<thread> thrd(new thread(&bar));
|
||||||
manager1.add(thrd);
|
manager1.add(thrd);
|
||||||
@@ -296,7 +308,8 @@ void foo()
|
|||||||
the presence of operator new in user code, but this can be eliminated by proper
|
the presence of operator new in user code, but this can be eliminated by proper
|
||||||
design of higher level concepts, such as the boost::thread_group class that
|
design of higher level concepts, such as the boost::thread_group class that
|
||||||
simplifies example (4) down to:</p>
|
simplifies example (4) down to:</p>
|
||||||
<pre>void foo()
|
<pre>
|
||||||
|
void foo()
|
||||||
{
|
{
|
||||||
thread_group threads;
|
thread_group threads;
|
||||||
for (int i=0; i<NUM_THREADS; ++i)
|
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
|
variables are a continuing source of errors, even after previous bad experiences
|
||||||
caused them to be very careful in their use of event variables. Overt problems
|
caused them to be very careful in their use of event variables. Overt problems
|
||||||
can be avoided, for example, by teaming the event variable with a mutex, but
|
can be avoided, for example, by teaming the event variable with a mutex, but
|
||||||
that may just convert a <a href="definitions.html#definition-race-condition">race condition</a> into another problem,
|
that may just convert a <a href=
|
||||||
|
"definitions.html#Race condition">race condition</a> into another problem,
|
||||||
such as excessive resource use. One of the most distressing aspects of the experience
|
such as excessive resource use. One of the most distressing aspects of the experience
|
||||||
reports is the claim that many defects are latent. That is, the programs appear
|
reports is the claim that many defects are latent. That is, the programs appear
|
||||||
to work correctly, but contain hidden timing dependencies which will cause them
|
to work correctly, but contain hidden timing dependencies which will cause them
|
||||||
@@ -369,7 +383,9 @@ void foo()
|
|||||||
<p>[Rationale provided by Beman Dawes]</p>
|
<p>[Rationale provided by Beman Dawes]</p>
|
||||||
<hr>
|
<hr>
|
||||||
<p>Revised
|
<p>Revised
|
||||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->09 January, 2003<!--webbot bot="Timestamp" endspan i-checksum="38582" -->
|
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
||||||
|
05 November, 2001
|
||||||
|
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
|
||||||
</p>
|
</p>
|
||||||
<p><i>© Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
|
<p><i>© Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
|
||||||
All Rights Reserved.</i></p>
|
All Rights Reserved.</i></p>
|
||||||
|
|||||||
@@ -218,7 +218,51 @@ recursive_timed_mutex();
|
|||||||
resulting in undefined behavior such as a program crash.</dt>
|
resulting in undefined behavior such as a program crash.</dt>
|
||||||
</dl>
|
</dl>
|
||||||
<h2><a name="examples"></a>Example(s)</h2>
|
<h2><a name="examples"></a>Example(s)</h2>
|
||||||
<p><a href="../example/recursive_mutex.cpp">libs/thread/example/recursive_mutex.cpp</a></p>
|
<pre>
|
||||||
|
#include <a href="../../../boost/thread/recursive_mutex.hpp"><boost/thread/recursive_mutex.hpp></a>
|
||||||
|
#include <a href="../../../boost/thread/thread.hpp"><boost/thread/thread.hpp></a>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
class counter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
counter() : count(0) { }
|
||||||
|
|
||||||
|
int add(int val) {
|
||||||
|
boost::recursive_mutex::scoped_lock scoped_lock(mutex);
|
||||||
|
count += val;
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
int increment() {
|
||||||
|
boost::recursive_mutex::scoped_lock scoped_lock(mutex);
|
||||||
|
return add(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
boost::recursive_mutex mutex;
|
||||||
|
int count;
|
||||||
|
};
|
||||||
|
|
||||||
|
counter c;
|
||||||
|
|
||||||
|
void change_count(void*)
|
||||||
|
{
|
||||||
|
std::cout << "count == " << c.increment() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int, char*[])
|
||||||
|
{
|
||||||
|
const int num_threads=4;
|
||||||
|
|
||||||
|
boost::thread_group threads;
|
||||||
|
for (int i=0; i < num_threads; ++i)
|
||||||
|
threads.create_thread(&change_count, 0);
|
||||||
|
|
||||||
|
threads.join_all();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
<p>The output is:</p>
|
<p>The output is:</p>
|
||||||
<pre>
|
<pre>
|
||||||
count == 1
|
count == 1
|
||||||
|
|||||||
119
doc/thread.html
119
doc/thread.html
@@ -85,8 +85,10 @@
|
|||||||
having first been called, the thread of execution continues until its initial
|
having first been called, the thread of execution continues until its initial
|
||||||
function completes.</p>
|
function completes.</p>
|
||||||
<h4><a name="class-thread-synopsis"></a>Class <code>thread</code> synopsis</h4>
|
<h4><a name="class-thread-synopsis"></a>Class <code>thread</code> synopsis</h4>
|
||||||
<pre>namespace boost {
|
<pre>
|
||||||
class thread : <a href="../../utility/utility.htm#Class_noncopyable">boost::noncopyable</a> // Exposition only.
|
namespace boost {
|
||||||
|
class thread : <a href=
|
||||||
|
"../../utility/utility.htm#Class noncopyable">boost::noncopyable</a> // Exposition only.
|
||||||
// Class thread meets the <a href=
|
// Class thread meets the <a href=
|
||||||
"overview.html#non-copyable">NonCopyable</a> requirement.
|
"overview.html#non-copyable">NonCopyable</a> requirement.
|
||||||
{
|
{
|
||||||
@@ -107,7 +109,8 @@ public:
|
|||||||
</pre>
|
</pre>
|
||||||
<h4><a name="class-thread-ctors"></a>Class <code>thread</code> constructors and
|
<h4><a name="class-thread-ctors"></a>Class <code>thread</code> constructors and
|
||||||
destructor</h4>
|
destructor</h4>
|
||||||
<pre>thread();
|
<pre>
|
||||||
|
thread();
|
||||||
</pre>
|
</pre>
|
||||||
<dl class="function-semantics">
|
<dl class="function-semantics">
|
||||||
<dt><b>Effects:</b> Constructs a <code>thread</code> object representing the
|
<dt><b>Effects:</b> Constructs a <code>thread</code> object representing the
|
||||||
@@ -115,7 +118,8 @@ public:
|
|||||||
<dt><b>Postconditions:</b> <code>*this</code> is non-joinable.</dt>
|
<dt><b>Postconditions:</b> <code>*this</code> is non-joinable.</dt>
|
||||||
<dt><b>Danger:</b> <code>*this</code> is valid only within the current thread.</dt>
|
<dt><b>Danger:</b> <code>*this</code> is valid only within the current thread.</dt>
|
||||||
</dl>
|
</dl>
|
||||||
<pre>thread(const <a href="../../function/index.html">boost::function0</a><void>& threadfunc);
|
<pre>
|
||||||
|
thread(const <a href="../../function/index.html">boost::function0</a><void>& threadfunc);
|
||||||
</pre>
|
</pre>
|
||||||
<dl class="function-semantics">
|
<dl class="function-semantics">
|
||||||
<dt><b>Effects:</b> Starts a new thread of execution and constructs a <code>thread</code>
|
<dt><b>Effects:</b> Starts a new thread of execution and constructs a <code>thread</code>
|
||||||
@@ -128,7 +132,8 @@ public:
|
|||||||
<dt><b>Throws:</b> <code>boost::thread_resource_error</code> if a new thread
|
<dt><b>Throws:</b> <code>boost::thread_resource_error</code> if a new thread
|
||||||
of execution cannot be started.</dt>
|
of execution cannot be started.</dt>
|
||||||
</dl>
|
</dl>
|
||||||
<pre>~Thread();
|
<pre>
|
||||||
|
~Thread();
|
||||||
</pre>
|
</pre>
|
||||||
<dl class="function-semantics">
|
<dl class="function-semantics">
|
||||||
<dt><b>Effects:</b> Destroys <code>*this</code>. The actual thread of execution
|
<dt><b>Effects:</b> Destroys <code>*this</code>. The actual thread of execution
|
||||||
@@ -141,21 +146,24 @@ public:
|
|||||||
</dl>
|
</dl>
|
||||||
<h4><a name="class-thread-comparisons"></a>Class <code>thread</code> comparison
|
<h4><a name="class-thread-comparisons"></a>Class <code>thread</code> comparison
|
||||||
functions</h4>
|
functions</h4>
|
||||||
<pre>bool operator==(const thread& rhs) const;
|
<pre>
|
||||||
|
bool operator==(const thread& rhs) const;
|
||||||
</pre>
|
</pre>
|
||||||
<dl class="function-semantics">
|
<dl class="function-semantics">
|
||||||
<dt><b>Requires:</b> The thread is non-terminated or <code>*this</code> is joinable.</dt>
|
<dt><b>Requires:</b> The thread is non-terminated or <code>*this</code> is joinable.</dt>
|
||||||
<dt><b>Returns:</b> <code>true</code> if <code>*this</code> and <code> rhs</code>
|
<dt><b>Returns:</b> <code>true</code> if <code>*this</code> and <code> rhs</code>
|
||||||
represent the same thread of execution.</dt>
|
represent the same thread of execution.</dt>
|
||||||
</dl>
|
</dl>
|
||||||
<pre>bool operator!=(const thread& rhs) const;
|
<pre>
|
||||||
|
bool operator!=(const thread& rhs) const;
|
||||||
</pre>
|
</pre>
|
||||||
<dl class="function-semantics">
|
<dl class="function-semantics">
|
||||||
<dt><b>Requires:</b> The thread is non-terminated or <code>*this</code> is joinable.</dt>
|
<dt><b>Requires:</b> The thread is non-terminated or <code>*this</code> is joinable.</dt>
|
||||||
<dt><b>Returns:</b> <code>!(*this==rhs)</code>.</dt>
|
<dt><b>Returns:</b> <code>!(*this==rhs)</code>.</dt>
|
||||||
</dl>
|
</dl>
|
||||||
<h4><a name="class-thread-modifiers"></a>Class <code>thread</code> modifier functions</h4>
|
<h4><a name="class-thread-modifiers"></a>Class <code>thread</code> modifier functions</h4>
|
||||||
<pre>void join();
|
<pre>
|
||||||
|
void join();
|
||||||
</pre>
|
</pre>
|
||||||
<dl class="function-semantics">
|
<dl class="function-semantics">
|
||||||
<dt><b>Requires:</b> <code>*this</code> is joinable.</dt>
|
<dt><b>Requires:</b> <code>*this</code> is joinable.</dt>
|
||||||
@@ -168,13 +176,15 @@ public:
|
|||||||
<a href="definitions.html#Deadlock"> deadlock</a>.</dt>
|
<a href="definitions.html#Deadlock"> deadlock</a>.</dt>
|
||||||
</dl>
|
</dl>
|
||||||
<h4><a name="class-thread-statics"></a>Class <code>thread</code> static functions</h4>
|
<h4><a name="class-thread-statics"></a>Class <code>thread</code> static functions</h4>
|
||||||
<pre>static void sleep(const <a href="xtime.html">xtime</a>& XT);
|
<pre>
|
||||||
|
static void sleep(const <a href="xtime.html">xtime</a>& XT);
|
||||||
</pre>
|
</pre>
|
||||||
<dl class="function-semantics">
|
<dl class="function-semantics">
|
||||||
<dt><b>Effects:</b> The current thread of execution blocks until <code> XT</code>
|
<dt><b>Effects:</b> The current thread of execution blocks until <code> XT</code>
|
||||||
is reached.</dt>
|
is reached.</dt>
|
||||||
</dl>
|
</dl>
|
||||||
<pre>static void yield();
|
<pre>
|
||||||
|
static void yield();
|
||||||
</pre>
|
</pre>
|
||||||
<dl class="function-semantics">
|
<dl class="function-semantics">
|
||||||
<dt><b>Effects:</b> The current thread of execution is placed in the "ready"
|
<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>
|
"definitions.html#thread-safe">thread-safe</a>, except destruction.</p>
|
||||||
<h4><a name="class-thread_group-synopsis"></a>Class <code>thread_group</code>
|
<h4><a name="class-thread_group-synopsis"></a>Class <code>thread_group</code>
|
||||||
synopsis</h4>
|
synopsis</h4>
|
||||||
<pre>namespace boost {
|
<pre>
|
||||||
|
namespace boost {
|
||||||
class thread_group : <a href=
|
class thread_group : <a href=
|
||||||
"../../utility/utility.htm#Class_noncopyable">boost::noncopyable</a>
|
"../../utility/utility.htm#Class noncopyable">boost::noncopyable</a>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
thread_group();
|
thread_group();
|
||||||
@@ -207,12 +218,14 @@ public:
|
|||||||
</pre>
|
</pre>
|
||||||
<h4><a name="class-thread_group-ctors"></a>Class <code>thread_group</code> constructors
|
<h4><a name="class-thread_group-ctors"></a>Class <code>thread_group</code> constructors
|
||||||
and destructor</h4>
|
and destructor</h4>
|
||||||
<pre>thread_group();
|
<pre>
|
||||||
|
thread_group();
|
||||||
</pre>
|
</pre>
|
||||||
<dl class="function-semantics">
|
<dl class="function-semantics">
|
||||||
<dt><b>Effects:</b> Constructs an empty <code>thread_group</code> container.</dt>
|
<dt><b>Effects:</b> Constructs an empty <code>thread_group</code> container.</dt>
|
||||||
</dl>
|
</dl>
|
||||||
<pre>~thread_group();
|
<pre>
|
||||||
|
~thread_group();
|
||||||
</pre>
|
</pre>
|
||||||
<dl class="function-semantics">
|
<dl class="function-semantics">
|
||||||
<dt><b>Effects:</b> Destroys each contained thread object. Destroys <code>*this</code>.</dt>
|
<dt><b>Effects:</b> Destroys each contained thread object. Destroys <code>*this</code>.</dt>
|
||||||
@@ -221,7 +234,8 @@ public:
|
|||||||
</dl>
|
</dl>
|
||||||
<h4><a name="class-thread_group-modifiers"></a>Class <code>thread_group</code>
|
<h4><a name="class-thread_group-modifiers"></a>Class <code>thread_group</code>
|
||||||
modifier functions</h4>
|
modifier functions</h4>
|
||||||
<pre>thread* create_thread(const boost::function0<void>& threadfunc);
|
<pre>
|
||||||
|
thread* create_thread(const boost::function0<void>& threadfunc);
|
||||||
</pre>
|
</pre>
|
||||||
<dl class="function-semantics">
|
<dl class="function-semantics">
|
||||||
<dt><b>Effects:</b> Creates a new <tt>thread</tt> object that executes <tt>threadfunc</tt>
|
<dt><b>Effects:</b> Creates a new <tt>thread</tt> object that executes <tt>threadfunc</tt>
|
||||||
@@ -229,14 +243,16 @@ public:
|
|||||||
<tt>thread</tt> objects.</dt>
|
<tt>thread</tt> objects.</dt>
|
||||||
<dt><b>Returns:</b> Pointer to the newly created thread.</dt>
|
<dt><b>Returns:</b> Pointer to the newly created thread.</dt>
|
||||||
</dl>
|
</dl>
|
||||||
<pre>void add_thread(thread* thrd);
|
<pre>
|
||||||
|
void add_thread(thread* thrd);
|
||||||
</pre>
|
</pre>
|
||||||
<dl class="function-semantics">
|
<dl class="function-semantics">
|
||||||
<dt><b>Effects:</b> Adds <tt>thrd</tt> to the <tt>thread_group</tt> object's
|
<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
|
list of managed <tt>thread</tt> objects. The <tt>thrd</tt> object must have
|
||||||
been allocated via operator new and will be deleted when the group is destroyed.</dt>
|
been allocated via operator new and will be deleted when the group is destroyed.</dt>
|
||||||
</dl>
|
</dl>
|
||||||
<pre>Void remove_thread(thread* thrd);
|
<pre>
|
||||||
|
Void remove_thread(thread* thrd);
|
||||||
</pre>
|
</pre>
|
||||||
<dl class="function-semantics">
|
<dl class="function-semantics">
|
||||||
<dt><b>Effects:</b> Removes <code>*this</code>'s list of managed <tt>thread</tt>
|
<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
|
<dt><b>Throws:</b> ? if <tt>thrd</tt> is not it <code>*this</code>'s list
|
||||||
of managed <tt>thread</tt> objects.</dt>
|
of managed <tt>thread</tt> objects.</dt>
|
||||||
</dl>
|
</dl>
|
||||||
<pre>Void join_all();
|
<pre>
|
||||||
|
Void join_all();
|
||||||
</pre>
|
</pre>
|
||||||
<dl class="function-semantics">
|
<dl class="function-semantics">
|
||||||
<dt><b>Effects:</b> Calls <code>join()</code> on each of the managed <tt>thread</tt>
|
<dt><b>Effects:</b> Calls <code>join()</code> on each of the managed <tt>thread</tt>
|
||||||
objects.</dt>
|
objects.</dt>
|
||||||
</dl>
|
</dl>
|
||||||
<h2><a name="functions"></a>Functions</h2>
|
<h2><a name="functions"></a>Functions</h2>
|
||||||
<pre><a name="function-spec"></a>{{function}}
|
<pre>
|
||||||
|
<a name="function-spec"></a>{{function}}
|
||||||
</pre>
|
</pre>
|
||||||
<dl class="function-semantics">
|
<dl class="function-semantics">
|
||||||
<dt><b>Requires:</b> {{text}}</dt>
|
<dt><b>Requires:</b> {{text}}</dt>
|
||||||
@@ -266,15 +284,66 @@ public:
|
|||||||
<p><a name="object-spec"></a>{{Object specifications}}</p>
|
<p><a name="object-spec"></a>{{Object specifications}}</p>
|
||||||
<h2><a name="examples"></a>Example(s)</h2>
|
<h2><a name="examples"></a>Example(s)</h2>
|
||||||
<h3><a name="example-thread"></a>Simple usage of <code>boost::thread</code></h3>
|
<h3><a name="example-thread"></a>Simple usage of <code>boost::thread</code></h3>
|
||||||
<p><a href="../example/thread.cpp">libs/thread/example/thread.cpp</a></p>
|
<pre>
|
||||||
|
#include <boost/thread/thread.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
struct thread_alarm
|
||||||
|
{
|
||||||
|
thread_alarm(int secs) : m_secs(secs) { }
|
||||||
|
void operator()()
|
||||||
|
{
|
||||||
|
boost::xtime XT;
|
||||||
|
boost::xtime_get(&XT, boost::TIME_UTC);
|
||||||
|
xt.sec += m_secs;
|
||||||
|
|
||||||
|
boost::thread::sleep(XT);
|
||||||
|
|
||||||
|
std::cout << "alarm sounded..." << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
int m_secs;
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
int secs = 5;
|
||||||
|
std::cout << "setting alarm for 5 seconds..." << std::endl;
|
||||||
|
thread_alarm alarm(secs);
|
||||||
|
boost::thread thrd(alarm);
|
||||||
|
thrd.join();
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
<p>The output is:</p>
|
<p>The output is:</p>
|
||||||
<pre>setting alarm for 5 seconds...
|
<pre>
|
||||||
|
setting alarm for 5 seconds...
|
||||||
alarm sounded...
|
alarm sounded...
|
||||||
</pre>
|
</pre>
|
||||||
<h3><a name="example-thread_group"></a>Simple usage of <code>boost::thread_group</code></h3>
|
<h3><a name="example-thread_group"></a>Simple usage of <code>boost::thread_group</code></h3>
|
||||||
<p><a href="../example/thread_group.cpp">libs/thread/example/thread_group.cpp</a></p>
|
<pre>
|
||||||
|
#include <boost/thread/thread.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
boost::mutex mutex;
|
||||||
|
|
||||||
|
void increment_count()
|
||||||
|
{
|
||||||
|
boost::mutex::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();
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
<p>The output is:</p>
|
<p>The output is:</p>
|
||||||
<pre>count = 1
|
<pre>
|
||||||
|
count = 1
|
||||||
count = 2
|
count = 2
|
||||||
count = 3
|
count = 3
|
||||||
count = 4
|
count = 4
|
||||||
@@ -287,7 +356,9 @@ count = 10
|
|||||||
</pre>
|
</pre>
|
||||||
<hr>
|
<hr>
|
||||||
<p>Revised
|
<p>Revised
|
||||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->09 January, 2003<!--webbot bot="Timestamp" endspan i-checksum="38582" -->
|
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
||||||
|
05 November, 2001
|
||||||
|
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
|
||||||
</p>
|
</p>
|
||||||
<p><i>© Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
|
<p><i>© Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
|
||||||
All Rights Reserved.</i></p>
|
All Rights Reserved.</i></p>
|
||||||
|
|||||||
33
doc/tss.html
33
doc/tss.html
@@ -150,7 +150,38 @@ T& operator*() const;
|
|||||||
<dt><b>Returns:</b> <code>this-<get()</code>.</dt>
|
<dt><b>Returns:</b> <code>this-<get()</code>.</dt>
|
||||||
</dl>
|
</dl>
|
||||||
<h2><a name="examples"></a>Example(s)</h2>
|
<h2><a name="examples"></a>Example(s)</h2>
|
||||||
<p><a href="../example/tss.cpp">libs/thread/example/tss.cpp</a></p>
|
<pre>
|
||||||
|
#include <a href="../../../boost/thread/thread.hpp"><boost/thread/thread.hpp></a>
|
||||||
|
#include <a href="../../../boost/thread/tss.hpp"><boost/thread/tss.hpp></a>
|
||||||
|
#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();
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
<hr>
|
<hr>
|
||||||
<p>Revised
|
<p>Revised
|
||||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
||||||
|
|||||||
@@ -91,7 +91,18 @@ namespace boost
|
|||||||
one second.</dt>
|
one second.</dt>
|
||||||
</dl>
|
</dl>
|
||||||
<h2><a name="examples"></a>Example(s)</h2>
|
<h2><a name="examples"></a>Example(s)</h2>
|
||||||
<p><a href="../example/xtime.cpp">libs/thread/example/xtime.cpp</a></p>
|
<pre>
|
||||||
|
#include <a href="../../../boost/thread/thread.hpp"><boost/thread/thread.hpp></a>
|
||||||
|
#include <a href="../../../boost/thread/tss.hpp"><boost/thread/xtime.hpp></a>
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
<hr>
|
<hr>
|
||||||
<p>Revised
|
<p>Revised
|
||||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
||||||
|
|||||||
@@ -1,10 +1,14 @@
|
|||||||
# (C) Copyright William E. Kempf 2001. Permission to copy, use, modify, sell
|
# (C) Copyright William E. Kempf 2001. Permission to copy, use, modify, sell and
|
||||||
# and distribute this software is granted provided this copyright notice
|
# distribute this software is granted provided this copyright notice appears
|
||||||
# appears in all copies. This software is provided "as is" without express or
|
# in all copies. This software is provided "as is" without express or implied
|
||||||
# implied warranty, and with no claim as to its suitability for any purpose.
|
# warranty, and with no claim as to its suitability for any purpose.
|
||||||
#
|
#
|
||||||
# Boost.Threads example Jamfile
|
# Boost.Threads build and test Jamfile
|
||||||
#
|
#
|
||||||
|
# Declares the following targets:
|
||||||
|
# 1. monitor, an example program.
|
||||||
|
# 2. starvephil, an example program.
|
||||||
|
# 3. tennis, an example program.
|
||||||
# Additional configuration variables used:
|
# Additional configuration variables used:
|
||||||
# 1. PTW32 may be used on Win32 platforms to specify that the pthreads-win32
|
# 1. PTW32 may be used on Win32 platforms to specify that the pthreads-win32
|
||||||
# library should be used instead of "native" threads. This feature is
|
# library should be used instead of "native" threads. This feature is
|
||||||
@@ -24,26 +28,41 @@ subproject libs/thread/example ;
|
|||||||
SEARCH on <module@>threads.jam = $(BOOST_ROOT)/libs/thread/build ;
|
SEARCH on <module@>threads.jam = $(BOOST_ROOT)/libs/thread/build ;
|
||||||
include <module@>threads.jam ;
|
include <module@>threads.jam ;
|
||||||
|
|
||||||
{
|
#######################
|
||||||
template example
|
# Declare the Boost.Threads example program monitor.
|
||||||
## sources ##
|
|
||||||
: <template>thread_base
|
exe monitor
|
||||||
<dll>../build/boost_thread
|
: monitor/monitor.cpp
|
||||||
## requirements ##
|
<lib>../build/boost_thread
|
||||||
:
|
$(threadmon)
|
||||||
## default build ##
|
: <sysinclude>$(BOOST_ROOT)
|
||||||
:
|
$(pthreads-win32)
|
||||||
|
<threading>multi
|
||||||
|
: debug release <runtime-link>static/dynamic
|
||||||
;
|
;
|
||||||
|
|
||||||
exe monitor : <template>example monitor.cpp ;
|
#######################
|
||||||
exe starvephil : <template>example starvephil.cpp ;
|
# Declare the Boost.Threads example program starvephil.
|
||||||
exe tennis : <template>example tennis.cpp ;
|
|
||||||
exe condition : <template>example condition.cpp ;
|
exe starvephil
|
||||||
exe mutex : <template>example mutex.cpp ;
|
: starvephil/starvephil.cpp
|
||||||
exe once : <template>example once.cpp ;
|
<lib>../build/boost_thread
|
||||||
exe recursive_mutex : <template>example recursive_mutex.cpp ;
|
$(threadmon)
|
||||||
exe thread : <template>example thread.cpp ;
|
: <sysinclude>$(BOOST_ROOT)
|
||||||
exe thread_group : <template>example thread_group.cpp ;
|
$(pthreads-win32)
|
||||||
exe tss : <template>example tss.cpp ;
|
<threading>multi
|
||||||
exe xtime : <template>example xtime.cpp ;
|
: debug release <runtime-link>static/dynamic
|
||||||
}
|
;
|
||||||
|
|
||||||
|
#######################
|
||||||
|
# Declare the Boost.Threads example program tennis.
|
||||||
|
|
||||||
|
exe tennis
|
||||||
|
: tennis/tennis.cpp
|
||||||
|
<lib>../build/boost_thread
|
||||||
|
$(threadmon)
|
||||||
|
: <sysinclude>$(BOOST_ROOT)
|
||||||
|
$(pthreads-win32)
|
||||||
|
<threading>multi
|
||||||
|
: debug release <runtime-link>static/dynamic
|
||||||
|
;
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
|
|
||||||
exe starvephil
|
|
||||||
: starvephil.cpp ../build/boost_thread ../../test/build/unit_test_framework
|
|
||||||
;
|
|
||||||
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
// Copyright (C) 2001-2003
|
|
||||||
// William E. Kempf
|
|
||||||
//
|
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
|
||||||
// and its documentation for any purpose is hereby granted without fee,
|
|
||||||
// provided that the above copyright notice appear in all copies and
|
|
||||||
// that both that copyright notice and this permission notice appear
|
|
||||||
// in supporting documentation. William E. Kempf makes no representations
|
|
||||||
// about the suitability of this software for any purpose.
|
|
||||||
// It is provided "as is" without express or implied warranty.
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <vector>
|
|
||||||
#include <boost/utility.hpp>
|
|
||||||
#include <boost/thread/condition.hpp>
|
|
||||||
#include <boost/thread/thread.hpp>
|
|
||||||
|
|
||||||
class bounded_buffer : private boost::noncopyable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef boost::mutex::scoped_lock lock;
|
|
||||||
|
|
||||||
bounded_buffer(int n) : begin(0), end(0), buffered(0), circular_buf(n) { }
|
|
||||||
|
|
||||||
void send (int m) {
|
|
||||||
lock lk(monitor);
|
|
||||||
while (buffered == circular_buf.size())
|
|
||||||
buffer_not_full.wait(lk);
|
|
||||||
circular_buf[end] = m;
|
|
||||||
end = (end+1) % circular_buf.size();
|
|
||||||
++buffered;
|
|
||||||
buffer_not_empty.notify_one();
|
|
||||||
}
|
|
||||||
int receive() {
|
|
||||||
lock lk(monitor);
|
|
||||||
while (buffered == 0)
|
|
||||||
buffer_not_empty.wait(lk);
|
|
||||||
int i = circular_buf[begin];
|
|
||||||
begin = (begin+1) % circular_buf.size();
|
|
||||||
--buffered;
|
|
||||||
buffer_not_full.notify_one();
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
int begin, end, buffered;
|
|
||||||
std::vector<int> circular_buf;
|
|
||||||
boost::condition buffer_not_full, buffer_not_empty;
|
|
||||||
boost::mutex monitor;
|
|
||||||
};
|
|
||||||
|
|
||||||
bounded_buffer buf(2);
|
|
||||||
|
|
||||||
void sender() {
|
|
||||||
int n = 0;
|
|
||||||
while (n < 100) {
|
|
||||||
buf.send(n);
|
|
||||||
std::cout << "sent: " << n << std::endl;
|
|
||||||
++n;
|
|
||||||
}
|
|
||||||
buf.send(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void receiver() {
|
|
||||||
int n;
|
|
||||||
do {
|
|
||||||
n = buf.receive();
|
|
||||||
std::cout << "received: " << n << std::endl;
|
|
||||||
} while (n != -1); // -1 indicates end of buffer
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int, char*[])
|
|
||||||
{
|
|
||||||
boost::thread thrd1(&sender);
|
|
||||||
boost::thread thrd2(&receiver);
|
|
||||||
thrd1.join();
|
|
||||||
thrd2.join();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
1
example/monitor/Carbon.r
Normal file
1
example/monitor/Carbon.r
Normal file
@@ -0,0 +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 <vector>
|
#include <vector>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <boost/thread/condition.hpp>
|
#include <boost/thread/condition.hpp>
|
||||||
@@ -17,11 +6,9 @@
|
|||||||
#include <boost/thread/thread.hpp>
|
#include <boost/thread/thread.hpp>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
const int ITERS = 100;
|
const int ITERS = 100;
|
||||||
boost::mutex io_mutex;
|
boost::mutex io_mutex;
|
||||||
|
}
|
||||||
} // namespace
|
|
||||||
|
|
||||||
template <typename M>
|
template <typename M>
|
||||||
class buffer_t
|
class buffer_t
|
||||||
BIN
example/monitor/monitor.mcp
Normal file
BIN
example/monitor/monitor.mcp
Normal file
Binary file not shown.
@@ -1,52 +0,0 @@
|
|||||||
// Copyright (C) 2001-2003
|
|
||||||
// William E. Kempf
|
|
||||||
//
|
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
|
||||||
// and its documentation for any purpose is hereby granted without fee,
|
|
||||||
// provided that the above copyright notice appear in all copies and
|
|
||||||
// that both that copyright notice and this permission notice appear
|
|
||||||
// in supporting documentation. William E. Kempf makes no representations
|
|
||||||
// about the suitability of this software for any purpose.
|
|
||||||
// It is provided "as is" without express or implied warranty.
|
|
||||||
|
|
||||||
#include <boost/thread/mutex.hpp>
|
|
||||||
#include <boost/thread/thread.hpp>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
boost::mutex io_mutex; // The iostreams are not guaranteed to be thread-safe!
|
|
||||||
|
|
||||||
class counter
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
counter() : count(0) { }
|
|
||||||
|
|
||||||
int increment() {
|
|
||||||
boost::mutex::scoped_lock scoped_lock(mutex);
|
|
||||||
return ++count;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
boost::mutex mutex;
|
|
||||||
int count;
|
|
||||||
};
|
|
||||||
|
|
||||||
counter c;
|
|
||||||
|
|
||||||
void change_count()
|
|
||||||
{
|
|
||||||
int i = c.increment();
|
|
||||||
boost::mutex::scoped_lock scoped_lock(io_mutex);
|
|
||||||
std::cout << "count == " << i << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int, char*[])
|
|
||||||
{
|
|
||||||
const int num_threads = 4;
|
|
||||||
boost::thread_group thrds;
|
|
||||||
for (int i=0; i < num_threads; ++i)
|
|
||||||
thrds.create_thread(&change_count);
|
|
||||||
|
|
||||||
thrds.join_all();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -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,54 +0,0 @@
|
|||||||
// Copyright (C) 2001-2003
|
|
||||||
// William E. Kempf
|
|
||||||
//
|
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
|
||||||
// and its documentation for any purpose is hereby granted without fee,
|
|
||||||
// provided that the above copyright notice appear in all copies and
|
|
||||||
// that both that copyright notice and this permission notice appear
|
|
||||||
// in supporting documentation. William E. Kempf makes no representations
|
|
||||||
// about the suitability of this software for any purpose.
|
|
||||||
// It is provided "as is" without express or implied warranty.
|
|
||||||
|
|
||||||
#include <boost/thread/recursive_mutex.hpp>
|
|
||||||
#include <boost/thread/thread.hpp>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
class counter
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
counter() : count(0) { }
|
|
||||||
|
|
||||||
int add(int val) {
|
|
||||||
boost::recursive_mutex::scoped_lock scoped_lock(mutex);
|
|
||||||
count += val;
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
int increment() {
|
|
||||||
boost::recursive_mutex::scoped_lock scoped_lock(mutex);
|
|
||||||
return add(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
boost::recursive_mutex mutex;
|
|
||||||
int count;
|
|
||||||
};
|
|
||||||
|
|
||||||
counter c;
|
|
||||||
|
|
||||||
void change_count()
|
|
||||||
{
|
|
||||||
std::cout << "count == " << c.increment() << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int, char*[])
|
|
||||||
{
|
|
||||||
const int num_threads=4;
|
|
||||||
|
|
||||||
boost::thread_group threads;
|
|
||||||
for (int i=0; i < num_threads; ++i)
|
|
||||||
threads.create_thread(&change_count);
|
|
||||||
|
|
||||||
threads.join_all();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
1
example/starvephil/Carbon.r
Normal file
1
example/starvephil/Carbon.r
Normal file
@@ -0,0 +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/mutex.hpp>
|
#include <boost/thread/mutex.hpp>
|
||||||
#include <boost/thread/condition.hpp>
|
#include <boost/thread/condition.hpp>
|
||||||
#include <boost/thread/thread.hpp>
|
#include <boost/thread/thread.hpp>
|
||||||
@@ -16,10 +5,9 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
namespace {
|
namespace
|
||||||
|
{
|
||||||
boost::mutex iomx;
|
boost::mutex iomx;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class canteen
|
class canteen
|
||||||
@@ -51,9 +39,8 @@ public:
|
|||||||
boost::mutex::scoped_lock lock(m_mutex);
|
boost::mutex::scoped_lock lock(m_mutex);
|
||||||
{
|
{
|
||||||
boost::mutex::scoped_lock lock(iomx);
|
boost::mutex::scoped_lock lock(iomx);
|
||||||
std::cout << "(" << clock()
|
std::cout << "(" << clock() <<
|
||||||
<< ") Chef: ouch ... make room ... this dish is "
|
") Chef: ouch ... make room ... this dish is very hot ..." << std::endl;
|
||||||
<< "very hot ..." << std::endl;
|
|
||||||
}
|
}
|
||||||
boost::xtime xt;
|
boost::xtime xt;
|
||||||
boost::xtime_get(&xt, boost::TIME_UTC);
|
boost::xtime_get(&xt, boost::TIME_UTC);
|
||||||
@@ -109,8 +96,7 @@ struct phil
|
|||||||
void run() {
|
void run() {
|
||||||
{
|
{
|
||||||
boost::mutex::scoped_lock lock(iomx);
|
boost::mutex::scoped_lock lock(iomx);
|
||||||
std::cout << "(" << clock() << ") Phil" << m_id
|
std::cout << "(" << clock() << ") Phil" << m_id << ": starting ..." << std::endl;
|
||||||
<< ": starting ..." << std::endl;
|
|
||||||
}
|
}
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
@@ -143,10 +129,7 @@ struct phil
|
|||||||
|
|
||||||
struct thread_adapt
|
struct thread_adapt
|
||||||
{
|
{
|
||||||
thread_adapt(void (*func)(void*), void* param)
|
thread_adapt(void (*func)(void*), void* param) : _func(func), _param(param) { }
|
||||||
: _func(func), _param(param)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
int operator()() const
|
int operator()() const
|
||||||
{
|
{
|
||||||
_func(_param);
|
_func(_param);
|
||||||
@@ -160,10 +143,7 @@ struct thread_adapt
|
|||||||
class thread_adapter
|
class thread_adapter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
thread_adapter(void (*func)(void*), void* param)
|
thread_adapter(void (*func)(void*), void* param) : _func(func), _param(param) { }
|
||||||
: _func(func), _param(param)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
void operator()() const { _func(_param); }
|
void operator()() const { _func(_param); }
|
||||||
private:
|
private:
|
||||||
void (*_func)(void*);
|
void (*_func)(void*);
|
||||||
BIN
example/starvephil/starvephil.mcp
Normal file
BIN
example/starvephil/starvephil.mcp
Normal file
Binary file not shown.
1
example/tennis/Carbon.r
Normal file
1
example/tennis/Carbon.r
Normal file
@@ -0,0 +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/mutex.hpp>
|
#include <boost/thread/mutex.hpp>
|
||||||
#include <boost/thread/condition.hpp>
|
#include <boost/thread/condition.hpp>
|
||||||
#include <boost/thread/thread.hpp>
|
#include <boost/thread/thread.hpp>
|
||||||
@@ -60,8 +49,7 @@ void player(void* param)
|
|||||||
{
|
{
|
||||||
cond.wait(lock);
|
cond.wait(lock);
|
||||||
if (state == other)
|
if (state == other)
|
||||||
std::cout << "---" << player_name(active)
|
std::cout << "---" << player_name(active) << ": Spurious wakeup!" << std::endl;
|
||||||
<< ": Spurious wakeup!" << std::endl;
|
|
||||||
} while (state == other);
|
} while (state == other);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,10 +60,7 @@ void player(void* param)
|
|||||||
|
|
||||||
struct thread_adapt
|
struct thread_adapt
|
||||||
{
|
{
|
||||||
thread_adapt(void (*func)(void*), void* param)
|
thread_adapt(void (*func)(void*), void* param) : _func(func), _param(param) { }
|
||||||
: _func(func), _param(param)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
int operator()() const
|
int operator()() const
|
||||||
{
|
{
|
||||||
_func(_param);
|
_func(_param);
|
||||||
@@ -89,10 +74,7 @@ struct thread_adapt
|
|||||||
class thread_adapter
|
class thread_adapter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
thread_adapter(void (*func)(void*), void* param)
|
thread_adapter(void (*func)(void*), void* param) : _func(func), _param(param) { }
|
||||||
: _func(func), _param(param)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
void operator()() const { _func(_param); }
|
void operator()() const { _func(_param); }
|
||||||
private:
|
private:
|
||||||
void (*_func)(void*);
|
void (*_func)(void*);
|
||||||
BIN
example/tennis/tennis.mcp
Normal file
BIN
example/tennis/tennis.mcp
Normal file
Binary file not shown.
@@ -1,40 +0,0 @@
|
|||||||
// Copyright (C) 2001-2003
|
|
||||||
// William E. Kempf
|
|
||||||
//
|
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
|
||||||
// and its documentation for any purpose is hereby granted without fee,
|
|
||||||
// provided that the above copyright notice appear in all copies and
|
|
||||||
// that both that copyright notice and this permission notice appear
|
|
||||||
// in supporting documentation. William E. Kempf makes no representations
|
|
||||||
// about the suitability of this software for any purpose.
|
|
||||||
// It is provided "as is" without express or implied warranty.
|
|
||||||
|
|
||||||
#include <boost/thread/thread.hpp>
|
|
||||||
#include <boost/thread/xtime.hpp>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
struct thread_alarm
|
|
||||||
{
|
|
||||||
thread_alarm(int secs) : m_secs(secs) { }
|
|
||||||
void operator()()
|
|
||||||
{
|
|
||||||
boost::xtime xt;
|
|
||||||
boost::xtime_get(&xt, boost::TIME_UTC);
|
|
||||||
xt.sec += m_secs;
|
|
||||||
|
|
||||||
boost::thread::sleep(xt);
|
|
||||||
|
|
||||||
std::cout << "alarm sounded..." << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
int m_secs;
|
|
||||||
};
|
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
|
||||||
{
|
|
||||||
int secs = 5;
|
|
||||||
std::cout << "setting alarm for 5 seconds..." << std::endl;
|
|
||||||
thread_alarm alarm(secs);
|
|
||||||
boost::thread thrd(alarm);
|
|
||||||
thrd.join();
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
// Copyright (C) 2001-2003
|
|
||||||
// William E. Kempf
|
|
||||||
//
|
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
|
||||||
// and its documentation for any purpose is hereby granted without fee,
|
|
||||||
// provided that the above copyright notice appear in all copies and
|
|
||||||
// that both that copyright notice and this permission notice appear
|
|
||||||
// in supporting documentation. William E. Kempf makes no representations
|
|
||||||
// about the suitability of this software for any purpose.
|
|
||||||
// It is provided "as is" without express or implied warranty.
|
|
||||||
|
|
||||||
#include <boost/thread/thread.hpp>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
int count = 0;
|
|
||||||
boost::mutex mutex;
|
|
||||||
|
|
||||||
void increment_count()
|
|
||||||
{
|
|
||||||
boost::mutex::scoped_lock lock(mutex);
|
|
||||||
std::cout << "count = " << ++count << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
|
||||||
{
|
|
||||||
boost::thread_group threads;
|
|
||||||
for (int i = 0; i < 10; ++i)
|
|
||||||
threads.create_thread(&increment_count);
|
|
||||||
threads.join_all();
|
|
||||||
}
|
|
||||||
@@ -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();
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
// Copyright (C) 2001-2003
|
|
||||||
// William E. Kempf
|
|
||||||
//
|
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
|
||||||
// and its documentation for any purpose is hereby granted without fee,
|
|
||||||
// provided that the above copyright notice appear in all copies and
|
|
||||||
// that both that copyright notice and this permission notice appear
|
|
||||||
// in supporting documentation. William E. Kempf makes no representations
|
|
||||||
// about the suitability of this software for any purpose.
|
|
||||||
// It is provided "as is" without express or implied warranty.
|
|
||||||
|
|
||||||
#include <boost/thread/thread.hpp>
|
|
||||||
#include <boost/thread/xtime.hpp>
|
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
|
||||||
{
|
|
||||||
boost::xtime xt;
|
|
||||||
boost::xtime_get(&xt, boost::TIME_UTC);
|
|
||||||
xt.sec += 1;
|
|
||||||
boost::thread::sleep(xt); // Sleep for 1 second
|
|
||||||
}
|
|
||||||
@@ -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
|
// William E. Kempf
|
||||||
//
|
//
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
@@ -20,7 +20,6 @@
|
|||||||
#include <boost/thread/exceptions.hpp>
|
#include <boost/thread/exceptions.hpp>
|
||||||
#include <boost/utility.hpp>
|
#include <boost/utility.hpp>
|
||||||
#include <boost/thread/detail/lock.hpp>
|
#include <boost/thread/detail/lock.hpp>
|
||||||
#include <boost/thread/detail/config.hpp>
|
|
||||||
|
|
||||||
#if defined(BOOST_HAS_PTHREADS)
|
#if defined(BOOST_HAS_PTHREADS)
|
||||||
# include <pthread.h>
|
# include <pthread.h>
|
||||||
@@ -32,60 +31,14 @@ namespace boost {
|
|||||||
|
|
||||||
struct xtime;
|
struct xtime;
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
class BOOST_THREAD_DECL condition_impl : private noncopyable
|
|
||||||
{
|
|
||||||
friend class condition;
|
|
||||||
|
|
||||||
public:
|
|
||||||
condition_impl();
|
|
||||||
~condition_impl();
|
|
||||||
|
|
||||||
void notify_one();
|
|
||||||
void notify_all();
|
|
||||||
|
|
||||||
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
|
||||||
void enter_wait();
|
|
||||||
void do_wait();
|
|
||||||
bool do_timed_wait(const xtime& xt);
|
|
||||||
#elif defined(BOOST_HAS_PTHREADS)
|
|
||||||
void do_wait(pthread_mutex_t* pmutex);
|
|
||||||
bool do_timed_wait(const xtime& xt, pthread_mutex_t* pmutex);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(BOOST_HAS_WINTHREADS)
|
|
||||||
void* m_gate;
|
|
||||||
void* m_queue;
|
|
||||||
void* m_mutex;
|
|
||||||
unsigned m_gone; // # threads that timed out and never made it to m_queue
|
|
||||||
unsigned long m_blocked; // # threads blocked on the condition
|
|
||||||
unsigned m_waiting; // # threads no longer waiting for the condition but
|
|
||||||
// still waiting to be removed from m_queue
|
|
||||||
#elif defined(BOOST_HAS_PTHREADS)
|
|
||||||
pthread_cond_t m_condition;
|
|
||||||
#elif defined(BOOST_HAS_MPTASKS)
|
|
||||||
MPSemaphoreID m_gate;
|
|
||||||
MPSemaphoreID m_queue;
|
|
||||||
threads::mac::detail::scoped_critical_region m_mutex;
|
|
||||||
threads::mac::detail::scoped_critical_region m_mutex_mutex;
|
|
||||||
unsigned m_gone; // # threads that timed out and never made it to m_queue
|
|
||||||
unsigned long m_blocked; // # threads blocked on the condition
|
|
||||||
unsigned m_waiting; // # threads no longer waiting for the condition but
|
|
||||||
// still waiting to be removed from m_queue
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
class condition : private noncopyable
|
class condition : private noncopyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
condition() { }
|
condition();
|
||||||
~condition() { }
|
~condition();
|
||||||
|
|
||||||
void notify_one() { m_impl.notify_one(); }
|
void notify_one();
|
||||||
void notify_all() { m_impl.notify_all(); }
|
void notify_all();
|
||||||
|
|
||||||
template <typename L>
|
template <typename L>
|
||||||
void wait(L& lock)
|
void wait(L& lock)
|
||||||
@@ -131,63 +84,79 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
detail::condition_impl m_impl;
|
|
||||||
|
|
||||||
template <typename M>
|
template <typename M>
|
||||||
void do_wait(M& mutex)
|
void do_wait(M& mutex)
|
||||||
{
|
{
|
||||||
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||||
m_impl.enter_wait();
|
enter_wait();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef detail::thread::lock_ops<M>
|
typedef typename detail::thread::lock_ops<M> lock_ops;
|
||||||
#if defined(__HP_aCC) && __HP_aCC <= 33900 && !defined(BOOST_STRICT_CONFIG)
|
|
||||||
# define lock_ops lock_ops_ // HP confuses lock_ops witht the template
|
|
||||||
#endif
|
|
||||||
lock_ops;
|
|
||||||
|
|
||||||
typename lock_ops::lock_state state;
|
typename lock_ops::lock_state state;
|
||||||
lock_ops::unlock(mutex, state);
|
lock_ops::unlock(mutex, state);
|
||||||
|
|
||||||
#if defined(BOOST_HAS_PTHREADS)
|
#if defined(BOOST_HAS_PTHREADS)
|
||||||
m_impl.do_wait(state.pmutex);
|
do_wait(state.pmutex);
|
||||||
#elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
#elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||||
m_impl.do_wait();
|
do_wait();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
lock_ops::lock(mutex, state);
|
lock_ops::lock(mutex, state);
|
||||||
#undef lock_ops
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename M>
|
template <typename M>
|
||||||
bool do_timed_wait(M& mutex, const xtime& xt)
|
bool do_timed_wait(M& mutex, const xtime& xt)
|
||||||
{
|
{
|
||||||
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||||
m_impl.enter_wait();
|
enter_wait();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef detail::thread::lock_ops<M>
|
typedef typename detail::thread::lock_ops<M> lock_ops;
|
||||||
#if defined(__HP_aCC) && __HP_aCC <= 33900 && !defined(BOOST_STRICT_CONFIG)
|
|
||||||
# define lock_ops lock_ops_ // HP confuses lock_ops witht the template
|
|
||||||
#endif
|
|
||||||
lock_ops;
|
|
||||||
|
|
||||||
typename lock_ops::lock_state state;
|
typename lock_ops::lock_state state;
|
||||||
lock_ops::unlock(mutex, state);
|
lock_ops::unlock(mutex, state);
|
||||||
|
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
|
|
||||||
#if defined(BOOST_HAS_PTHREADS)
|
#if defined(BOOST_HAS_PTHREADS)
|
||||||
ret = m_impl.do_timed_wait(xt, state.pmutex);
|
ret = do_timed_wait(xt, state.pmutex);
|
||||||
#elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
#elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||||
ret = m_impl.do_timed_wait(xt);
|
ret = do_timed_wait(xt);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
lock_ops::lock(mutex, state);
|
lock_ops::lock(mutex, state);
|
||||||
#undef lock_ops
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||||
|
void enter_wait();
|
||||||
|
void do_wait();
|
||||||
|
bool do_timed_wait(const xtime& xt);
|
||||||
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
|
void do_wait(pthread_mutex_t* pmutex);
|
||||||
|
bool do_timed_wait(const xtime& xt, pthread_mutex_t* pmutex);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
void* m_gate;
|
||||||
|
void* m_queue;
|
||||||
|
void* m_mutex;
|
||||||
|
unsigned m_gone; // # threads that timed out and never made it to the m_queue
|
||||||
|
unsigned long m_blocked; // # threads m_blocked m_waiting for the condition
|
||||||
|
unsigned m_waiting; // # threads m_waiting no longer m_waiting for the condition but still
|
||||||
|
// m_waiting to be removed from the m_queue
|
||||||
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
|
pthread_cond_t m_condition;
|
||||||
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
|
MPSemaphoreID m_gate;
|
||||||
|
MPSemaphoreID m_queue;
|
||||||
|
threads::mac::detail::scoped_critical_region m_mutex;
|
||||||
|
threads::mac::detail::scoped_critical_region m_mutex_mutex;
|
||||||
|
unsigned m_gone; // # threads that timed out and never made it to the m_queue
|
||||||
|
unsigned long m_blocked; // # threads m_blocked m_waiting for the condition
|
||||||
|
unsigned m_waiting; // # threads m_waiting no longer m_waiting for the condition but still
|
||||||
|
// m_waiting to be removed from the m_queue
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace boost
|
} // namespace boost
|
||||||
@@ -195,8 +164,7 @@ private:
|
|||||||
// Change Log:
|
// Change Log:
|
||||||
// 8 Feb 01 WEKEMPF Initial version.
|
// 8 Feb 01 WEKEMPF Initial version.
|
||||||
// 22 May 01 WEKEMPF Modified to use xtime for time outs.
|
// 22 May 01 WEKEMPF Modified to use xtime for time outs.
|
||||||
// 23 May 01 WEKEMPF Removed "duration" timed_waits, as they are too
|
// 23 May 01 WEKEMPF Removed "duration" timed_waits, as they are too difficult
|
||||||
// difficult to use with spurious wakeups.
|
// to use with spurious wakeups.
|
||||||
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
|
|
||||||
|
|
||||||
#endif // BOOST_CONDITION_WEK070601_HPP
|
#endif // BOOST_CONDITION_WEK070601_HPP
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -47,8 +47,8 @@ inline singleton<T>::~singleton()
|
|||||||
template<class T>
|
template<class T>
|
||||||
/*static*/ T &singleton<T>::instance()
|
/*static*/ T &singleton<T>::instance()
|
||||||
{
|
{
|
||||||
// function-local static to force this to work correctly at static
|
// function-local static to force this to work correctly at static initialization
|
||||||
// initialization time.
|
// time.
|
||||||
static singleton<T> s_oT;
|
static singleton<T> s_oT;
|
||||||
return(s_oT);
|
return(s_oT);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
// William E. Kempf
|
||||||
//
|
//
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
@@ -12,9 +12,6 @@
|
|||||||
#ifndef BOOST_THREAD_EXCEPTIONS_PDM070801_H
|
#ifndef BOOST_THREAD_EXCEPTIONS_PDM070801_H
|
||||||
#define BOOST_THREAD_EXCEPTIONS_PDM070801_H
|
#define BOOST_THREAD_EXCEPTIONS_PDM070801_H
|
||||||
|
|
||||||
#include <boost/config.hpp>
|
|
||||||
#include <boost/thread/detail/config.hpp>
|
|
||||||
|
|
||||||
// pdm: Sorry, but this class is used all over the place & I end up
|
// pdm: Sorry, but this class is used all over the place & I end up
|
||||||
// with recursive headers if I don't separate it
|
// with recursive headers if I don't separate it
|
||||||
// wek: Not sure why recursive headers would cause compilation problems
|
// wek: Not sure why recursive headers would cause compilation problems
|
||||||
@@ -25,13 +22,13 @@
|
|||||||
|
|
||||||
namespace boost {
|
namespace boost {
|
||||||
|
|
||||||
class BOOST_THREAD_DECL lock_error : public std::logic_error
|
class lock_error : public std::logic_error
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
lock_error();
|
lock_error();
|
||||||
};
|
};
|
||||||
|
|
||||||
class BOOST_THREAD_DECL thread_resource_error : public std::runtime_error
|
class thread_resource_error : public std::runtime_error
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
thread_resource_error();
|
thread_resource_error();
|
||||||
@@ -39,7 +36,4 @@ public:
|
|||||||
|
|
||||||
} // namespace boost
|
} // namespace boost
|
||||||
|
|
||||||
// Change log:
|
|
||||||
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
|
|
||||||
|
|
||||||
#endif // BOOST_THREAD_CONFIG_PDM070801_H
|
#endif // BOOST_THREAD_CONFIG_PDM070801_H
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2001-2003
|
// Copyright (C) 2001
|
||||||
// William E. Kempf
|
// William E. Kempf
|
||||||
//
|
//
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
@@ -19,7 +19,6 @@
|
|||||||
|
|
||||||
#include <boost/utility.hpp>
|
#include <boost/utility.hpp>
|
||||||
#include <boost/thread/detail/lock.hpp>
|
#include <boost/thread/detail/lock.hpp>
|
||||||
#include <boost/thread/detail/config.hpp>
|
|
||||||
|
|
||||||
#if defined(BOOST_HAS_PTHREADS)
|
#if defined(BOOST_HAS_PTHREADS)
|
||||||
# include <pthread.h>
|
# include <pthread.h>
|
||||||
@@ -33,7 +32,7 @@ namespace boost {
|
|||||||
|
|
||||||
struct xtime;
|
struct xtime;
|
||||||
|
|
||||||
class BOOST_THREAD_DECL mutex : private noncopyable
|
class mutex : private noncopyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
friend class detail::thread::lock_ops<mutex>;
|
friend class detail::thread::lock_ops<mutex>;
|
||||||
@@ -71,7 +70,7 @@ private:
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
class BOOST_THREAD_DECL try_mutex : private noncopyable
|
class try_mutex : private noncopyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
friend class detail::thread::lock_ops<try_mutex>;
|
friend class detail::thread::lock_ops<try_mutex>;
|
||||||
@@ -111,7 +110,7 @@ private:
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
class BOOST_THREAD_DECL timed_mutex : private noncopyable
|
class timed_mutex : private noncopyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
friend class detail::thread::lock_ops<timed_mutex>;
|
friend class detail::thread::lock_ops<timed_mutex>;
|
||||||
@@ -161,6 +160,5 @@ private:
|
|||||||
// 8 Feb 01 WEKEMPF Initial version.
|
// 8 Feb 01 WEKEMPF Initial version.
|
||||||
// 22 May 01 WEKEMPF Modified to use xtime for time outs. Factored out
|
// 22 May 01 WEKEMPF Modified to use xtime for time outs. Factored out
|
||||||
// to three classes, mutex, try_mutex and timed_mutex.
|
// to three classes, mutex, try_mutex and timed_mutex.
|
||||||
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
|
|
||||||
|
|
||||||
#endif // BOOST_MUTEX_WEK070601_HPP
|
#endif // BOOST_MUTEX_WEK070601_HPP
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2001-2003
|
// Copyright (C) 2001
|
||||||
// William E. Kempf
|
// William E. Kempf
|
||||||
//
|
//
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
@@ -17,8 +17,6 @@
|
|||||||
# error Thread support is unavailable!
|
# error Thread support is unavailable!
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <boost/thread/detail/config.hpp>
|
|
||||||
|
|
||||||
#if defined(BOOST_HAS_PTHREADS)
|
#if defined(BOOST_HAS_PTHREADS)
|
||||||
# include <pthread.h>
|
# include <pthread.h>
|
||||||
#endif
|
#endif
|
||||||
@@ -32,12 +30,12 @@ typedef pthread_once_t once_flag;
|
|||||||
|
|
||||||
#elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
#elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||||
|
|
||||||
typedef long once_flag;
|
typedef bool once_flag;
|
||||||
#define BOOST_ONCE_INIT 0
|
#define BOOST_ONCE_INIT false
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void BOOST_THREAD_DECL call_once(void (*func)(), once_flag& flag);
|
void call_once(void (*func)(), once_flag& flag);
|
||||||
|
|
||||||
} // namespace boost
|
} // namespace boost
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2001-2003
|
// Copyright (C) 2001
|
||||||
// William E. Kempf
|
// William E. Kempf
|
||||||
//
|
//
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
@@ -19,7 +19,6 @@
|
|||||||
|
|
||||||
#include <boost/utility.hpp>
|
#include <boost/utility.hpp>
|
||||||
#include <boost/thread/detail/lock.hpp>
|
#include <boost/thread/detail/lock.hpp>
|
||||||
#include <boost/thread/detail/config.hpp>
|
|
||||||
|
|
||||||
#if defined(BOOST_HAS_PTHREADS)
|
#if defined(BOOST_HAS_PTHREADS)
|
||||||
# include <pthread.h>
|
# include <pthread.h>
|
||||||
@@ -31,7 +30,7 @@ namespace boost {
|
|||||||
|
|
||||||
struct xtime;
|
struct xtime;
|
||||||
|
|
||||||
class BOOST_THREAD_DECL recursive_mutex : private noncopyable
|
class recursive_mutex : private noncopyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
friend class detail::thread::lock_ops<recursive_mutex>;
|
friend class detail::thread::lock_ops<recursive_mutex>;
|
||||||
@@ -74,14 +73,13 @@ private:
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
class BOOST_THREAD_DECL recursive_try_mutex : private noncopyable
|
class recursive_try_mutex : private noncopyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
friend class detail::thread::lock_ops<recursive_try_mutex>;
|
friend class detail::thread::lock_ops<recursive_try_mutex>;
|
||||||
|
|
||||||
typedef detail::thread::scoped_lock<recursive_try_mutex> scoped_lock;
|
typedef detail::thread::scoped_lock<recursive_try_mutex> scoped_lock;
|
||||||
typedef detail::thread::scoped_try_lock<
|
typedef detail::thread::scoped_try_lock<recursive_try_mutex> scoped_try_lock;
|
||||||
recursive_try_mutex> scoped_try_lock;
|
|
||||||
|
|
||||||
recursive_try_mutex();
|
recursive_try_mutex();
|
||||||
~recursive_try_mutex();
|
~recursive_try_mutex();
|
||||||
@@ -120,16 +118,14 @@ private:
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
class BOOST_THREAD_DECL recursive_timed_mutex : private noncopyable
|
class recursive_timed_mutex : private noncopyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
friend class detail::thread::lock_ops<recursive_timed_mutex>;
|
friend class detail::thread::lock_ops<recursive_timed_mutex>;
|
||||||
|
|
||||||
typedef detail::thread::scoped_lock<recursive_timed_mutex> scoped_lock;
|
typedef detail::thread::scoped_lock<recursive_timed_mutex> scoped_lock;
|
||||||
typedef detail::thread::scoped_try_lock<
|
typedef detail::thread::scoped_try_lock<recursive_timed_mutex> scoped_try_lock;
|
||||||
recursive_timed_mutex> scoped_try_lock;
|
typedef detail::thread::scoped_timed_lock<recursive_timed_mutex> scoped_timed_lock;
|
||||||
typedef detail::thread::scoped_timed_lock<
|
|
||||||
recursive_timed_mutex> scoped_timed_lock;
|
|
||||||
|
|
||||||
recursive_timed_mutex();
|
recursive_timed_mutex();
|
||||||
~recursive_timed_mutex();
|
~recursive_timed_mutex();
|
||||||
@@ -174,7 +170,5 @@ private:
|
|||||||
// 1 Jun 01 WEKEMPF Modified to use xtime for time outs. Factored out
|
// 1 Jun 01 WEKEMPF Modified to use xtime for time outs. Factored out
|
||||||
// to three classes, mutex, try_mutex and timed_mutex.
|
// to three classes, mutex, try_mutex and timed_mutex.
|
||||||
// 11 Jun 01 WEKEMPF Modified to use PTHREAD_MUTEX_RECURSIVE if available.
|
// 11 Jun 01 WEKEMPF Modified to use PTHREAD_MUTEX_RECURSIVE if available.
|
||||||
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
|
|
||||||
|
|
||||||
|
|
||||||
#endif // BOOST_RECURSIVE_MUTEX_WEK070601_HPP
|
#endif // BOOST_RECURSIVE_MUTEX_WEK070601_HPP
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2001-2003
|
// Copyright (C) 2001
|
||||||
// William E. Kempf
|
// William E. Kempf
|
||||||
//
|
//
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
@@ -20,7 +20,6 @@
|
|||||||
#include <boost/utility.hpp>
|
#include <boost/utility.hpp>
|
||||||
#include <boost/function.hpp>
|
#include <boost/function.hpp>
|
||||||
#include <boost/thread/mutex.hpp>
|
#include <boost/thread/mutex.hpp>
|
||||||
#include <boost/thread/detail/config.hpp>
|
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
@@ -35,7 +34,7 @@ namespace boost {
|
|||||||
|
|
||||||
struct xtime;
|
struct xtime;
|
||||||
|
|
||||||
class BOOST_THREAD_DECL thread : private noncopyable
|
class thread : private noncopyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
thread();
|
thread();
|
||||||
@@ -64,7 +63,7 @@ private:
|
|||||||
bool m_joinable;
|
bool m_joinable;
|
||||||
};
|
};
|
||||||
|
|
||||||
class BOOST_THREAD_DECL thread_group : private noncopyable
|
class thread_group : private noncopyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
thread_group();
|
thread_group();
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2001-2003
|
// Copyright (C) 2001
|
||||||
// William E. Kempf
|
// William E. Kempf
|
||||||
//
|
//
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
@@ -18,7 +18,6 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <boost/utility.hpp>
|
#include <boost/utility.hpp>
|
||||||
#include <boost/thread/detail/config.hpp>
|
|
||||||
|
|
||||||
#if defined(BOOST_HAS_PTHREADS)
|
#if defined(BOOST_HAS_PTHREADS)
|
||||||
# include <pthread.h>
|
# include <pthread.h>
|
||||||
@@ -29,7 +28,7 @@
|
|||||||
namespace boost {
|
namespace boost {
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
class BOOST_THREAD_DECL tss : private noncopyable
|
class tss : private noncopyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
tss(void (*cleanup)(void*)=0);
|
tss(void (*cleanup)(void*)=0);
|
||||||
@@ -65,13 +64,7 @@ public:
|
|||||||
T* operator->() const { return get(); }
|
T* operator->() const { return get(); }
|
||||||
T& operator*() const { return *get(); }
|
T& operator*() const { return *get(); }
|
||||||
T* release() { T* temp = get(); m_tss.set(0); return temp; }
|
T* release() { T* temp = get(); m_tss.set(0); return temp; }
|
||||||
void reset(T* p=0)
|
void reset(T* p=0) { T* cur = get(); if (cur == p) return; delete cur; m_tss.set(p); }
|
||||||
{
|
|
||||||
T* cur = get();
|
|
||||||
if (cur == p) return;
|
|
||||||
delete cur;
|
|
||||||
m_tss.set(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void cleanup(void* p) { delete static_cast<T*>(p); }
|
static void cleanup(void* p) { delete static_cast<T*>(p); }
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2001-2003
|
// Copyright (C) 2001
|
||||||
// William E. Kempf
|
// William E. Kempf
|
||||||
//
|
//
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
@@ -12,9 +12,8 @@
|
|||||||
#ifndef BOOST_XTIME_WEK070601_HPP
|
#ifndef BOOST_XTIME_WEK070601_HPP
|
||||||
#define BOOST_XTIME_WEK070601_HPP
|
#define BOOST_XTIME_WEK070601_HPP
|
||||||
|
|
||||||
#include <boost/config.hpp>
|
|
||||||
#include <boost/cstdint.hpp>
|
#include <boost/cstdint.hpp>
|
||||||
#include <boost/thread/detail/config.hpp>
|
#include <boost/config.hpp>
|
||||||
|
|
||||||
namespace boost {
|
namespace boost {
|
||||||
|
|
||||||
@@ -40,7 +39,7 @@ struct xtime
|
|||||||
int_fast32_t nsec;
|
int_fast32_t nsec;
|
||||||
};
|
};
|
||||||
|
|
||||||
int BOOST_THREAD_DECL xtime_get(struct xtime* xtp, int clock_type);
|
int xtime_get(struct xtime* xtp, int clock_type);
|
||||||
inline int xtime_cmp(const xtime& xt1, const xtime& xt2)
|
inline int xtime_cmp(const xtime& xt1, const xtime& xt2)
|
||||||
{
|
{
|
||||||
int res = (int)(xt1.sec - xt2.sec);
|
int res = (int)(xt1.sec - xt2.sec);
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="refresh" content="0; URL=doc/index.html">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
Automatic redirection failed, please go to <a href="doc/index.html">doc/index.html</a>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2001-2003
|
// Copyright (C) 2001
|
||||||
// William E. Kempf
|
// William E. Kempf
|
||||||
//
|
//
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
@@ -32,16 +32,12 @@
|
|||||||
|
|
||||||
namespace boost {
|
namespace boost {
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
#if defined(BOOST_HAS_WINTHREADS)
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
condition_impl::condition_impl()
|
condition::condition()
|
||||||
: m_gone(0), m_blocked(0), m_waiting(0)
|
: m_gone(0), m_blocked(0), m_waiting(0)
|
||||||
{
|
{
|
||||||
m_gate = reinterpret_cast<void*>(CreateSemaphore(0, 1, 1, 0));
|
m_gate = reinterpret_cast<void*>(CreateSemaphore(0, 1, 1, 0));
|
||||||
m_queue = reinterpret_cast<void*>(CreateSemaphore(0, 0,
|
m_queue = reinterpret_cast<void*>(CreateSemaphore(0, 0, std::numeric_limits<long>::max(), 0));
|
||||||
std::numeric_limits<long>::max(),
|
|
||||||
0));
|
|
||||||
m_mutex = reinterpret_cast<void*>(CreateMutex(0, 0, 0));
|
m_mutex = reinterpret_cast<void*>(CreateMutex(0, 0, 0));
|
||||||
|
|
||||||
if (!m_gate || !m_queue || !m_mutex)
|
if (!m_gate || !m_queue || !m_mutex)
|
||||||
@@ -67,7 +63,7 @@ condition_impl::condition_impl()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
condition_impl::~condition_impl()
|
condition::~condition()
|
||||||
{
|
{
|
||||||
int res = 0;
|
int res = 0;
|
||||||
res = CloseHandle(reinterpret_cast<HANDLE>(m_gate));
|
res = CloseHandle(reinterpret_cast<HANDLE>(m_gate));
|
||||||
@@ -78,7 +74,7 @@ condition_impl::~condition_impl()
|
|||||||
assert(res);
|
assert(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
void condition_impl::notify_one()
|
void condition::notify_one()
|
||||||
{
|
{
|
||||||
unsigned signals = 0;
|
unsigned signals = 0;
|
||||||
|
|
||||||
@@ -130,7 +126,7 @@ void condition_impl::notify_one()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void condition_impl::notify_all()
|
void condition::notify_all()
|
||||||
{
|
{
|
||||||
unsigned signals = 0;
|
unsigned signals = 0;
|
||||||
|
|
||||||
@@ -169,20 +165,19 @@ void condition_impl::notify_all()
|
|||||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||||
assert(res);
|
assert(res);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||||
assert(res);
|
assert(res);
|
||||||
|
|
||||||
if (signals)
|
if (signals)
|
||||||
{
|
{
|
||||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_queue), signals,
|
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_queue), signals, 0);
|
||||||
0);
|
|
||||||
assert(res);
|
assert(res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void condition_impl::enter_wait()
|
void condition::enter_wait()
|
||||||
{
|
{
|
||||||
int res = 0;
|
int res = 0;
|
||||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
|
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
|
||||||
@@ -192,7 +187,7 @@ void condition_impl::enter_wait()
|
|||||||
assert(res);
|
assert(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
void condition_impl::do_wait()
|
void condition::do_wait()
|
||||||
{
|
{
|
||||||
int res = 0;
|
int res = 0;
|
||||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue), INFINITE);
|
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue), INFINITE);
|
||||||
@@ -211,8 +206,7 @@ void condition_impl::do_wait()
|
|||||||
{
|
{
|
||||||
if (m_blocked != 0)
|
if (m_blocked != 0)
|
||||||
{
|
{
|
||||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1,
|
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0); // open m_gate
|
||||||
0); // open m_gate
|
|
||||||
assert(res);
|
assert(res);
|
||||||
was_waiting = 0;
|
was_waiting = 0;
|
||||||
}
|
}
|
||||||
@@ -240,8 +234,7 @@ void condition_impl::do_wait()
|
|||||||
for (/**/ ; was_gone; --was_gone)
|
for (/**/ ; was_gone; --was_gone)
|
||||||
{
|
{
|
||||||
// better now than spurious later
|
// better now than spurious later
|
||||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue),
|
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue), INFINITE);
|
||||||
INFINITE);
|
|
||||||
assert(res == WAIT_OBJECT_0);
|
assert(res == WAIT_OBJECT_0);
|
||||||
}
|
}
|
||||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||||
@@ -249,31 +242,16 @@ void condition_impl::do_wait()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool condition_impl::do_timed_wait(const xtime& xt)
|
bool condition::do_timed_wait(const xtime& xt)
|
||||||
{
|
|
||||||
bool ret = false;
|
|
||||||
unsigned int res = 0;
|
|
||||||
|
|
||||||
for (;;)
|
|
||||||
{
|
{
|
||||||
int milliseconds;
|
int milliseconds;
|
||||||
to_duration(xt, milliseconds);
|
to_duration(xt, milliseconds);
|
||||||
|
|
||||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue),
|
unsigned int res = 0;
|
||||||
milliseconds);
|
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue), milliseconds);
|
||||||
assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
|
assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
|
||||||
ret = (res == WAIT_OBJECT_0);
|
|
||||||
|
|
||||||
if (res == WAIT_TIMEOUT)
|
bool ret = (res == WAIT_OBJECT_0);
|
||||||
{
|
|
||||||
xtime cur;
|
|
||||||
xtime_get(&cur, TIME_UTC);
|
|
||||||
if (xtime_cmp(xt, cur) > 0)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned was_waiting=0;
|
unsigned was_waiting=0;
|
||||||
unsigned was_gone=0;
|
unsigned was_gone=0;
|
||||||
@@ -295,8 +273,7 @@ bool condition_impl::do_timed_wait(const xtime& xt)
|
|||||||
{
|
{
|
||||||
if (m_blocked != 0)
|
if (m_blocked != 0)
|
||||||
{
|
{
|
||||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1,
|
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0); // open m_gate
|
||||||
0); // open m_gate
|
|
||||||
assert(res);
|
assert(res);
|
||||||
was_waiting = 0;
|
was_waiting = 0;
|
||||||
}
|
}
|
||||||
@@ -324,8 +301,7 @@ bool condition_impl::do_timed_wait(const xtime& xt)
|
|||||||
for (/**/ ; was_gone; --was_gone)
|
for (/**/ ; was_gone; --was_gone)
|
||||||
{
|
{
|
||||||
// better now than spurious later
|
// better now than spurious later
|
||||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue),
|
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue), INFINITE);
|
||||||
INFINITE);
|
|
||||||
assert(res == WAIT_OBJECT_0);
|
assert(res == WAIT_OBJECT_0);
|
||||||
}
|
}
|
||||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||||
@@ -335,7 +311,7 @@ bool condition_impl::do_timed_wait(const xtime& xt)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
#elif defined(BOOST_HAS_PTHREADS)
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
condition_impl::condition_impl()
|
condition::condition()
|
||||||
{
|
{
|
||||||
int res = 0;
|
int res = 0;
|
||||||
res = pthread_cond_init(&m_condition, 0);
|
res = pthread_cond_init(&m_condition, 0);
|
||||||
@@ -343,35 +319,35 @@ condition_impl::condition_impl()
|
|||||||
throw thread_resource_error();
|
throw thread_resource_error();
|
||||||
}
|
}
|
||||||
|
|
||||||
condition_impl::~condition_impl()
|
condition::~condition()
|
||||||
{
|
{
|
||||||
int res = 0;
|
int res = 0;
|
||||||
res = pthread_cond_destroy(&m_condition);
|
res = pthread_cond_destroy(&m_condition);
|
||||||
assert(res == 0);
|
assert(res == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void condition_impl::notify_one()
|
void condition::notify_one()
|
||||||
{
|
{
|
||||||
int res = 0;
|
int res = 0;
|
||||||
res = pthread_cond_signal(&m_condition);
|
res = pthread_cond_signal(&m_condition);
|
||||||
assert(res == 0);
|
assert(res == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void condition_impl::notify_all()
|
void condition::notify_all()
|
||||||
{
|
{
|
||||||
int res = 0;
|
int res = 0;
|
||||||
res = pthread_cond_broadcast(&m_condition);
|
res = pthread_cond_broadcast(&m_condition);
|
||||||
assert(res == 0);
|
assert(res == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void condition_impl::do_wait(pthread_mutex_t* pmutex)
|
void condition::do_wait(pthread_mutex_t* pmutex)
|
||||||
{
|
{
|
||||||
int res = 0;
|
int res = 0;
|
||||||
res = pthread_cond_wait(&m_condition, pmutex);
|
res = pthread_cond_wait(&m_condition, pmutex);
|
||||||
assert(res == 0);
|
assert(res == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool condition_impl::do_timed_wait(const xtime& xt, pthread_mutex_t* pmutex)
|
bool condition::do_timed_wait(const xtime& xt, pthread_mutex_t* pmutex)
|
||||||
{
|
{
|
||||||
timespec ts;
|
timespec ts;
|
||||||
to_timespec(xt, ts);
|
to_timespec(xt, ts);
|
||||||
@@ -387,7 +363,7 @@ bool condition_impl::do_timed_wait(const xtime& xt, pthread_mutex_t* pmutex)
|
|||||||
using threads::mac::detail::safe_enter_critical_region;
|
using threads::mac::detail::safe_enter_critical_region;
|
||||||
using threads::mac::detail::safe_wait_on_semaphore;
|
using threads::mac::detail::safe_wait_on_semaphore;
|
||||||
|
|
||||||
condition_impl::condition_impl()
|
condition::condition()
|
||||||
: m_gone(0), m_blocked(0), m_waiting(0)
|
: m_gone(0), m_blocked(0), m_waiting(0)
|
||||||
{
|
{
|
||||||
threads::mac::detail::thread_init();
|
threads::mac::detail::thread_init();
|
||||||
@@ -415,7 +391,7 @@ condition_impl::condition_impl()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
condition_impl::~condition_impl()
|
condition::~condition()
|
||||||
{
|
{
|
||||||
OSStatus lStatus = noErr;
|
OSStatus lStatus = noErr;
|
||||||
lStatus = MPDeleteSemaphore(m_gate);
|
lStatus = MPDeleteSemaphore(m_gate);
|
||||||
@@ -424,13 +400,12 @@ condition_impl::~condition_impl()
|
|||||||
assert(lStatus == noErr);
|
assert(lStatus == noErr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void condition_impl::notify_one()
|
void condition::notify_one()
|
||||||
{
|
{
|
||||||
unsigned signals = 0;
|
unsigned signals = 0;
|
||||||
|
|
||||||
OSStatus lStatus = noErr;
|
OSStatus lStatus = noErr;
|
||||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
||||||
m_mutex_mutex);
|
|
||||||
assert(lStatus == noErr);
|
assert(lStatus == noErr);
|
||||||
|
|
||||||
if (m_waiting != 0) // the m_gate is already closed
|
if (m_waiting != 0) // the m_gate is already closed
|
||||||
@@ -477,13 +452,12 @@ void condition_impl::notify_one()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void condition_impl::notify_all()
|
void condition::notify_all()
|
||||||
{
|
{
|
||||||
unsigned signals = 0;
|
unsigned signals = 0;
|
||||||
|
|
||||||
OSStatus lStatus = noErr;
|
OSStatus lStatus = noErr;
|
||||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
||||||
m_mutex_mutex);
|
|
||||||
assert(lStatus == noErr);
|
assert(lStatus == noErr);
|
||||||
|
|
||||||
if (m_waiting != 0) // the m_gate is already closed
|
if (m_waiting != 0) // the m_gate is already closed
|
||||||
@@ -530,7 +504,7 @@ void condition_impl::notify_all()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void condition_impl::enter_wait()
|
void condition::enter_wait()
|
||||||
{
|
{
|
||||||
OSStatus lStatus = noErr;
|
OSStatus lStatus = noErr;
|
||||||
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
|
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
|
||||||
@@ -540,7 +514,7 @@ void condition_impl::enter_wait()
|
|||||||
assert(lStatus == noErr);
|
assert(lStatus == noErr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void condition_impl::do_wait()
|
void condition::do_wait()
|
||||||
{
|
{
|
||||||
OSStatus lStatus = noErr;
|
OSStatus lStatus = noErr;
|
||||||
lStatus = safe_wait_on_semaphore(m_queue, kDurationForever);
|
lStatus = safe_wait_on_semaphore(m_queue, kDurationForever);
|
||||||
@@ -549,8 +523,7 @@ void condition_impl::do_wait()
|
|||||||
unsigned was_waiting=0;
|
unsigned was_waiting=0;
|
||||||
unsigned was_gone=0;
|
unsigned was_gone=0;
|
||||||
|
|
||||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
||||||
m_mutex_mutex);
|
|
||||||
assert(lStatus == noErr);
|
assert(lStatus == noErr);
|
||||||
was_waiting = m_waiting;
|
was_waiting = m_waiting;
|
||||||
was_gone = m_gone;
|
was_gone = m_gone;
|
||||||
@@ -596,7 +569,7 @@ void condition_impl::do_wait()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool condition_impl::do_timed_wait(const xtime& xt)
|
bool condition::do_timed_wait(const xtime& xt)
|
||||||
{
|
{
|
||||||
int milliseconds;
|
int milliseconds;
|
||||||
to_duration(xt, milliseconds);
|
to_duration(xt, milliseconds);
|
||||||
@@ -610,8 +583,7 @@ bool condition_impl::do_timed_wait(const xtime& xt)
|
|||||||
unsigned was_waiting=0;
|
unsigned was_waiting=0;
|
||||||
unsigned was_gone=0;
|
unsigned was_gone=0;
|
||||||
|
|
||||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
||||||
m_mutex_mutex);
|
|
||||||
assert(lStatus == noErr);
|
assert(lStatus == noErr);
|
||||||
was_waiting = m_waiting;
|
was_waiting = m_waiting;
|
||||||
was_gone = m_gone;
|
was_gone = m_gone;
|
||||||
@@ -667,11 +639,8 @@ bool condition_impl::do_timed_wait(const xtime& xt)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
} // namespace boost
|
} // namespace boost
|
||||||
|
|
||||||
// Change Log:
|
// Change Log:
|
||||||
// 8 Feb 01 WEKEMPF Initial version.
|
// 8 Feb 01 WEKEMPF Initial version.
|
||||||
// 22 May 01 WEKEMPF Modified to use xtime for time outs.
|
// 22 May 01 WEKEMPF Modified to use xtime for time outs.
|
||||||
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2001-2003
|
// Copyright (C) 2001
|
||||||
// William E. Kempf
|
// William E. Kempf
|
||||||
//
|
//
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
@@ -14,13 +14,11 @@
|
|||||||
|
|
||||||
namespace boost {
|
namespace boost {
|
||||||
|
|
||||||
lock_error::lock_error()
|
lock_error::lock_error() : std::logic_error("thread lock error")
|
||||||
: std::logic_error("thread lock error")
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
thread_resource_error::thread_resource_error()
|
thread_resource_error::thread_resource_error() : std::runtime_error("thread resource error")
|
||||||
: std::runtime_error("thread resource error")
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2001-2003
|
// Copyright (C) 2001
|
||||||
// William E. Kempf
|
// William E. Kempf
|
||||||
//
|
//
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
@@ -16,6 +16,7 @@
|
|||||||
#include <boost/limits.hpp>
|
#include <boost/limits.hpp>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <new>
|
||||||
#include "timeconv.inl"
|
#include "timeconv.inl"
|
||||||
|
|
||||||
#if defined(BOOST_HAS_WINTHREADS)
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
@@ -25,6 +26,7 @@
|
|||||||
# include <errno.h>
|
# include <errno.h>
|
||||||
#elif defined(BOOST_HAS_MPTASKS)
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
# include <MacErrors.h>
|
# include <MacErrors.h>
|
||||||
|
|
||||||
# include "mac/init.hpp"
|
# include "mac/init.hpp"
|
||||||
# include "mac/safe.hpp"
|
# include "mac/safe.hpp"
|
||||||
#endif
|
#endif
|
||||||
@@ -32,15 +34,9 @@
|
|||||||
namespace boost {
|
namespace boost {
|
||||||
|
|
||||||
#if defined(BOOST_HAS_WINTHREADS)
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
mutex::mutex() : m_mutex(0)
|
mutex::mutex()
|
||||||
{
|
{
|
||||||
try
|
m_mutex = reinterpret_cast<void*>(new(std::nothrow) CRITICAL_SECTION);
|
||||||
{
|
|
||||||
m_mutex = reinterpret_cast<void*>(new CRITICAL_SECTION);
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
if (!m_mutex)
|
if (!m_mutex)
|
||||||
throw thread_resource_error();
|
throw thread_resource_error();
|
||||||
InitializeCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(m_mutex));
|
InitializeCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(m_mutex));
|
||||||
@@ -148,28 +144,14 @@ bool timed_mutex::do_trylock()
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool timed_mutex::do_timedlock(const xtime& xt)
|
bool timed_mutex::do_timedlock(const xtime& xt)
|
||||||
{
|
|
||||||
unsigned int res = 0;
|
|
||||||
for (;;)
|
|
||||||
{
|
{
|
||||||
int milliseconds;
|
int milliseconds;
|
||||||
to_duration(xt, milliseconds);
|
to_duration(xt, milliseconds);
|
||||||
|
|
||||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex),
|
unsigned int res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), milliseconds);
|
||||||
milliseconds);
|
|
||||||
assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
|
assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
|
||||||
|
|
||||||
if (res == WAIT_TIMEOUT)
|
|
||||||
{
|
|
||||||
xtime cur;
|
|
||||||
xtime_get(&cur, TIME_UTC);
|
|
||||||
if (xtime_cmp(xt, cur) > 0)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return res == WAIT_OBJECT_0;
|
return res == WAIT_OBJECT_0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void timed_mutex::do_unlock()
|
void timed_mutex::do_unlock()
|
||||||
{
|
{
|
||||||
@@ -432,8 +414,7 @@ mutex::~mutex()
|
|||||||
void mutex::do_lock()
|
void mutex::do_lock()
|
||||||
{
|
{
|
||||||
OSStatus lStatus = noErr;
|
OSStatus lStatus = noErr;
|
||||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
||||||
m_mutex_mutex);
|
|
||||||
assert(lStatus == noErr);
|
assert(lStatus == noErr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -465,8 +446,7 @@ try_mutex::~try_mutex()
|
|||||||
void try_mutex::do_lock()
|
void try_mutex::do_lock()
|
||||||
{
|
{
|
||||||
OSStatus lStatus = noErr;
|
OSStatus lStatus = noErr;
|
||||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
||||||
m_mutex_mutex);
|
|
||||||
assert(lStatus == noErr);
|
assert(lStatus == noErr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -506,8 +486,7 @@ timed_mutex::~timed_mutex()
|
|||||||
void timed_mutex::do_lock()
|
void timed_mutex::do_lock()
|
||||||
{
|
{
|
||||||
OSStatus lStatus = noErr;
|
OSStatus lStatus = noErr;
|
||||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
||||||
m_mutex_mutex);
|
|
||||||
assert(lStatus == noErr);
|
assert(lStatus == noErr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
76
src/once.cpp
76
src/once.cpp
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2001-2003
|
// Copyright (C) 2001
|
||||||
// William E. Kempf
|
// William E. Kempf
|
||||||
//
|
//
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
@@ -17,7 +17,6 @@
|
|||||||
# include <windows.h>
|
# include <windows.h>
|
||||||
# if defined(BOOST_NO_STRINGSTREAM)
|
# if defined(BOOST_NO_STRINGSTREAM)
|
||||||
# include <strstream>
|
# include <strstream>
|
||||||
|
|
||||||
class unfreezer
|
class unfreezer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -26,7 +25,6 @@ public:
|
|||||||
private:
|
private:
|
||||||
std::ostrstream& m_stream;
|
std::ostrstream& m_stream;
|
||||||
};
|
};
|
||||||
|
|
||||||
# else
|
# else
|
||||||
# include <sstream>
|
# include <sstream>
|
||||||
# endif
|
# endif
|
||||||
@@ -55,18 +53,15 @@ extern "C" {
|
|||||||
|
|
||||||
static void do_once()
|
static void do_once()
|
||||||
{
|
{
|
||||||
once_callback* cb = reinterpret_cast<once_callback*>(
|
once_callback* cb = reinterpret_cast<once_callback*>(pthread_getspecific(key));
|
||||||
pthread_getspecific(key));
|
|
||||||
(**cb)();
|
(**cb)();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
#elif defined(BOOST_HAS_MPTASKS)
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
namespace {
|
|
||||||
void *remote_call_proxy(void *pData)
|
void *remote_call_proxy(void *pData)
|
||||||
{
|
{
|
||||||
std::pair<void (*)(), boost::once_flag *> &rData(
|
std::pair<void (*)(), boost::once_flag *> &rData(*reinterpret_cast<std::pair<void (*)(), boost::once_flag *> *>(pData));
|
||||||
*reinterpret_cast<std::pair<void (*)(), boost::once_flag *> *>(pData));
|
|
||||||
|
|
||||||
if(*rData.second == false)
|
if(*rData.second == false)
|
||||||
{
|
{
|
||||||
@@ -76,43 +71,6 @@ void *remote_call_proxy(void *pData)
|
|||||||
|
|
||||||
return(NULL);
|
return(NULL);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#elif defined(BOOST_HAS_WINTHREADS)
|
|
||||||
namespace {
|
|
||||||
// The signature for InterlockedCompareExchange has changed with the
|
|
||||||
// addition of Win64 support. I can't determine any (consistent and
|
|
||||||
// portable) way of using conditional compilation to detect this, so
|
|
||||||
// we use these type wrappers. Unfortunately, the various vendors
|
|
||||||
// use different calling conventions and other signature anamolies,
|
|
||||||
// and thus have unique types as well. This is known to work on VC6,
|
|
||||||
// VC7, Borland 5.5.2 and gcc 3.2. Are there other signatures for
|
|
||||||
// other platforms?
|
|
||||||
inline LONG ice_wrapper(LONG (__stdcall *ice)(LONG*, LONG, LONG),
|
|
||||||
volatile LONG* dest, LONG exch, LONG cmp)
|
|
||||||
{
|
|
||||||
return (*ice)(const_cast<LONG*>(dest), exch, cmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline LONG ice_wrapper(LONG (__stdcall *ice)(volatile LONG*, LONG, LONG),
|
|
||||||
volatile LONG* dest, LONG exch, LONG cmp)
|
|
||||||
{
|
|
||||||
return (*ice)(dest, exch, cmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline LONG ice_wrapper(LPVOID (__stdcall *ice)(LPVOID*, LPVOID, LPVOID),
|
|
||||||
volatile LONG* dest, LONG exch, LONG cmp)
|
|
||||||
{
|
|
||||||
return (LONG)(*ice)((LPVOID*)dest, (LPVOID)exch, (LPVOID)cmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The friendly form of InterlockedCompareExchange that defers
|
|
||||||
// according to the above function type wrappers.
|
|
||||||
inline LONG compare_exchange(volatile LPLONG dest, LONG exch, LONG cmp)
|
|
||||||
{
|
|
||||||
return ice_wrapper(&InterlockedCompareExchange, dest, exch, cmp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace boost {
|
namespace boost {
|
||||||
@@ -120,19 +78,22 @@ namespace boost {
|
|||||||
void call_once(void (*func)(), once_flag& flag)
|
void call_once(void (*func)(), once_flag& flag)
|
||||||
{
|
{
|
||||||
#if defined(BOOST_HAS_WINTHREADS)
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
if (compare_exchange(&flag, 1, 1) == 0)
|
once_flag tmp = flag;
|
||||||
|
|
||||||
|
// Memory barrier would be needed here to prevent race conditions on some platforms with
|
||||||
|
// partial ordering.
|
||||||
|
|
||||||
|
if (!tmp)
|
||||||
{
|
{
|
||||||
#if defined(BOOST_NO_STRINGSTREAM)
|
#if defined(BOOST_NO_STRINGSTREAM)
|
||||||
std::ostrstream strm;
|
std::ostrstream strm;
|
||||||
strm << "2AC1A572DB6944B0A65C38C4140AF2F4" << std::hex
|
strm << "2AC1A572DB6944B0A65C38C4140AF2F4" << std::hex << GetCurrentProcessId() << &flag << std::ends;
|
||||||
<< GetCurrentProcessId() << &flag << std::ends;
|
|
||||||
unfreezer unfreeze(strm);
|
unfreezer unfreeze(strm);
|
||||||
HANDLE mutex = CreateMutex(NULL, FALSE, strm.str());
|
HANDLE mutex = CreateMutex(NULL, FALSE, strm.str());
|
||||||
#else
|
#else
|
||||||
std::ostringstream strm;
|
std::ostringstream strm;
|
||||||
strm << "2AC1A572DB6944B0A65C38C4140AF2F4" << std::hex
|
strm << "2AC1A572DB6944B0A65C38C4140AF2F4" << std::hex << GetCurrentProcessId() << &flag;
|
||||||
<< GetCurrentProcessId() << &flag;
|
HANDLE mutex = CreateMutex(NULL, FALSE, strm.str().c_str());
|
||||||
HANDLE mutex = CreateMutexA(NULL, FALSE, strm.str().c_str());
|
|
||||||
#endif
|
#endif
|
||||||
assert(mutex != NULL);
|
assert(mutex != NULL);
|
||||||
|
|
||||||
@@ -140,10 +101,16 @@ void call_once(void (*func)(), once_flag& flag)
|
|||||||
res = WaitForSingleObject(mutex, INFINITE);
|
res = WaitForSingleObject(mutex, INFINITE);
|
||||||
assert(res == WAIT_OBJECT_0);
|
assert(res == WAIT_OBJECT_0);
|
||||||
|
|
||||||
if (compare_exchange(&flag, 1, 1) == 0)
|
tmp = flag;
|
||||||
|
if (!tmp)
|
||||||
{
|
{
|
||||||
func();
|
func();
|
||||||
InterlockedExchange(&flag, 1);
|
tmp = true;
|
||||||
|
|
||||||
|
// Memory barrier would be needed here to prevent race conditions on some platforms
|
||||||
|
// with partial ordering.
|
||||||
|
|
||||||
|
flag = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = ReleaseMutex(mutex);
|
res = ReleaseMutex(mutex);
|
||||||
@@ -158,8 +125,7 @@ void call_once(void (*func)(), once_flag& flag)
|
|||||||
#elif defined(BOOST_HAS_MPTASKS)
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
if(flag == false)
|
if(flag == false)
|
||||||
{
|
{
|
||||||
// all we do here is make a remote call to blue, as blue is not
|
// all we do here is make a remote call to blue, as blue is not reentrant.
|
||||||
// reentrant.
|
|
||||||
std::pair<void (*)(), once_flag *> sData(func, &flag);
|
std::pair<void (*)(), once_flag *> sData(func, &flag);
|
||||||
MPRemoteCall(remote_call_proxy, &sData, kMPOwningProcessRemoteContext);
|
MPRemoteCall(remote_call_proxy, &sData, kMPOwningProcessRemoteContext);
|
||||||
assert(flag == true);
|
assert(flag == true);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2001-2003
|
// Copyright (C) 2001
|
||||||
// William E. Kempf
|
// William E. Kempf
|
||||||
//
|
//
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
@@ -31,15 +31,9 @@ namespace boost {
|
|||||||
|
|
||||||
#if defined(BOOST_HAS_WINTHREADS)
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
recursive_mutex::recursive_mutex()
|
recursive_mutex::recursive_mutex()
|
||||||
: m_mutex(0), m_count(0)
|
: m_count(0)
|
||||||
{
|
{
|
||||||
try
|
m_mutex = reinterpret_cast<void*>(new(std::nothrow) CRITICAL_SECTION);
|
||||||
{
|
|
||||||
m_mutex = reinterpret_cast<void*>(new CRITICAL_SECTION);
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
if (!m_mutex)
|
if (!m_mutex)
|
||||||
throw thread_resource_error();
|
throw thread_resource_error();
|
||||||
InitializeCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(m_mutex));
|
InitializeCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(m_mutex));
|
||||||
@@ -200,25 +194,14 @@ bool recursive_timed_mutex::do_trylock()
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool recursive_timed_mutex::do_timedlock(const xtime& xt)
|
bool recursive_timed_mutex::do_timedlock(const xtime& xt)
|
||||||
{
|
|
||||||
for (;;)
|
|
||||||
{
|
{
|
||||||
int milliseconds;
|
int milliseconds;
|
||||||
to_duration(xt, milliseconds);
|
to_duration(xt, milliseconds);
|
||||||
|
|
||||||
unsigned int res = 0;
|
unsigned int res = 0;
|
||||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex),
|
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), milliseconds);
|
||||||
milliseconds);
|
|
||||||
assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
|
assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
|
||||||
|
|
||||||
if (res == WAIT_TIMEOUT)
|
|
||||||
{
|
|
||||||
xtime cur;
|
|
||||||
xtime_get(&cur, TIME_UTC);
|
|
||||||
if (xtime_cmp(xt, cur) > 0)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (res == WAIT_OBJECT_0)
|
if (res == WAIT_OBJECT_0)
|
||||||
{
|
{
|
||||||
if (++m_count > 1)
|
if (++m_count > 1)
|
||||||
@@ -228,10 +211,8 @@ bool recursive_timed_mutex::do_timedlock(const xtime& xt)
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void recursive_timed_mutex::do_unlock()
|
void recursive_timed_mutex::do_unlock()
|
||||||
{
|
{
|
||||||
@@ -805,8 +786,7 @@ recursive_mutex::~recursive_mutex()
|
|||||||
void recursive_mutex::do_lock()
|
void recursive_mutex::do_lock()
|
||||||
{
|
{
|
||||||
OSStatus lStatus = noErr;
|
OSStatus lStatus = noErr;
|
||||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
||||||
m_mutex_mutex);
|
|
||||||
assert(lStatus == noErr);
|
assert(lStatus == noErr);
|
||||||
|
|
||||||
if (++m_count > 1)
|
if (++m_count > 1)
|
||||||
@@ -829,8 +809,7 @@ void recursive_mutex::do_unlock()
|
|||||||
void recursive_mutex::do_lock(cv_state& state)
|
void recursive_mutex::do_lock(cv_state& state)
|
||||||
{
|
{
|
||||||
OSStatus lStatus = noErr;
|
OSStatus lStatus = noErr;
|
||||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
||||||
m_mutex_mutex);
|
|
||||||
assert(lStatus == noErr);
|
assert(lStatus == noErr);
|
||||||
|
|
||||||
m_count = state;
|
m_count = state;
|
||||||
@@ -858,8 +837,7 @@ recursive_try_mutex::~recursive_try_mutex()
|
|||||||
void recursive_try_mutex::do_lock()
|
void recursive_try_mutex::do_lock()
|
||||||
{
|
{
|
||||||
OSStatus lStatus = noErr;
|
OSStatus lStatus = noErr;
|
||||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
||||||
m_mutex_mutex);
|
|
||||||
assert(lStatus == noErr);
|
assert(lStatus == noErr);
|
||||||
|
|
||||||
if (++m_count > 1)
|
if (++m_count > 1)
|
||||||
@@ -900,8 +878,7 @@ void recursive_try_mutex::do_unlock()
|
|||||||
void recursive_try_mutex::do_lock(cv_state& state)
|
void recursive_try_mutex::do_lock(cv_state& state)
|
||||||
{
|
{
|
||||||
OSStatus lStatus = noErr;
|
OSStatus lStatus = noErr;
|
||||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
||||||
m_mutex_mutex);
|
|
||||||
assert(lStatus == noErr);
|
assert(lStatus == noErr);
|
||||||
|
|
||||||
m_count = state;
|
m_count = state;
|
||||||
@@ -929,8 +906,7 @@ recursive_timed_mutex::~recursive_timed_mutex()
|
|||||||
void recursive_timed_mutex::do_lock()
|
void recursive_timed_mutex::do_lock()
|
||||||
{
|
{
|
||||||
OSStatus lStatus = noErr;
|
OSStatus lStatus = noErr;
|
||||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
||||||
m_mutex_mutex);
|
|
||||||
assert(lStatus == noErr);
|
assert(lStatus == noErr);
|
||||||
|
|
||||||
if (++m_count > 1)
|
if (++m_count > 1)
|
||||||
@@ -993,8 +969,7 @@ void recursive_timed_mutex::do_unlock()
|
|||||||
void recursive_timed_mutex::do_lock(cv_state& state)
|
void recursive_timed_mutex::do_lock(cv_state& state)
|
||||||
{
|
{
|
||||||
OSStatus lStatus = noErr;
|
OSStatus lStatus = noErr;
|
||||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
||||||
m_mutex_mutex);
|
|
||||||
assert(lStatus == noErr);
|
assert(lStatus == noErr);
|
||||||
|
|
||||||
m_count = state;
|
m_count = state;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2001-2003
|
// Copyright (C) 2001
|
||||||
// William E. Kempf
|
// William E. Kempf
|
||||||
//
|
//
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
@@ -32,10 +32,7 @@ namespace {
|
|||||||
class thread_param
|
class thread_param
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
thread_param(const boost::function0<void>& threadfunc)
|
thread_param(const boost::function0<void>& threadfunc) : m_threadfunc(threadfunc), m_started(false) { }
|
||||||
: m_threadfunc(threadfunc), m_started(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
void wait()
|
void wait()
|
||||||
{
|
{
|
||||||
boost::mutex::scoped_lock scoped_lock(m_mutex);
|
boost::mutex::scoped_lock scoped_lock(m_mutex);
|
||||||
@@ -107,8 +104,7 @@ thread::thread(const function0<void>& threadfunc)
|
|||||||
{
|
{
|
||||||
thread_param param(threadfunc);
|
thread_param param(threadfunc);
|
||||||
#if defined(BOOST_HAS_WINTHREADS)
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
m_thread = reinterpret_cast<void*>(_beginthreadex(0, 0, &thread_proxy,
|
m_thread = reinterpret_cast<void*>(_beginthreadex(0, 0, &thread_proxy, ¶m, 0, &m_id));
|
||||||
¶m, 0, &m_id));
|
|
||||||
if (!m_thread)
|
if (!m_thread)
|
||||||
throw thread_resource_error();
|
throw thread_resource_error();
|
||||||
#elif defined(BOOST_HAS_PTHREADS)
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
@@ -127,8 +123,8 @@ thread::thread(const function0<void>& threadfunc)
|
|||||||
lStatus = MPCreateQueue(&m_pJoinQueueID);
|
lStatus = MPCreateQueue(&m_pJoinQueueID);
|
||||||
if(lStatus != noErr) throw thread_resource_error();
|
if(lStatus != noErr) throw thread_resource_error();
|
||||||
|
|
||||||
lStatus = MPCreateTask(&thread_proxy, ¶m, 0UL, m_pJoinQueueID, NULL,
|
lStatus = MPCreateTask(&thread_proxy, ¶m, 0UL, m_pJoinQueueID, NULL, NULL,
|
||||||
NULL, 0UL, &m_pTaskID);
|
0UL, &m_pTaskID);
|
||||||
if(lStatus != noErr)
|
if(lStatus != noErr)
|
||||||
{
|
{
|
||||||
lStatus = MPDeleteQueue(m_pJoinQueueID);
|
lStatus = MPDeleteQueue(m_pJoinQueueID);
|
||||||
@@ -185,8 +181,7 @@ void thread::join()
|
|||||||
res = pthread_join(m_thread, 0);
|
res = pthread_join(m_thread, 0);
|
||||||
assert(res == 0);
|
assert(res == 0);
|
||||||
#elif defined(BOOST_HAS_MPTASKS)
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
OSStatus lStatus = threads::mac::detail::safe_wait_on_queue(
|
OSStatus lStatus = threads::mac::detail::safe_wait_on_queue(m_pJoinQueueID, NULL, NULL, NULL, kDurationForever);
|
||||||
m_pJoinQueueID, NULL, NULL, NULL, kDurationForever);
|
|
||||||
assert(lStatus == noErr);
|
assert(lStatus == noErr);
|
||||||
#endif
|
#endif
|
||||||
// This isn't a race condition since any race that could occur would
|
// This isn't a race condition since any race that could occur would
|
||||||
@@ -196,12 +191,14 @@ void thread::join()
|
|||||||
|
|
||||||
void thread::sleep(const xtime& xt)
|
void thread::sleep(const xtime& xt)
|
||||||
{
|
{
|
||||||
for (int foo=0; foo < 5; ++foo)
|
for (;;)
|
||||||
{
|
{
|
||||||
#if defined(BOOST_HAS_WINTHREADS)
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
int milliseconds;
|
int milliseconds;
|
||||||
to_duration(xt, milliseconds);
|
to_duration(xt, milliseconds);
|
||||||
Sleep(milliseconds);
|
Sleep(milliseconds);
|
||||||
|
xtime xt2;
|
||||||
|
xtime_get(&xt2, TIME_UTC);
|
||||||
#elif defined(BOOST_HAS_PTHREADS)
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
# if defined(BOOST_HAS_PTHREAD_DELAY_NP)
|
# if defined(BOOST_HAS_PTHREAD_DELAY_NP)
|
||||||
timespec ts;
|
timespec ts;
|
||||||
@@ -229,9 +226,7 @@ void thread::sleep(const xtime& xt)
|
|||||||
AbsoluteTime sWakeTime(DurationToAbsolute(lMicroseconds));
|
AbsoluteTime sWakeTime(DurationToAbsolute(lMicroseconds));
|
||||||
threads::mac::detail::safe_delay_until(&sWakeTime);
|
threads::mac::detail::safe_delay_until(&sWakeTime);
|
||||||
#endif
|
#endif
|
||||||
xtime cur;
|
if (xtime_cmp(xt, xt2) >= 0)
|
||||||
xtime_get(&cur, TIME_UTC);
|
|
||||||
if (xtime_cmp(xt, cur) <= 0)
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -265,20 +260,17 @@ thread_group::thread_group()
|
|||||||
|
|
||||||
thread_group::~thread_group()
|
thread_group::~thread_group()
|
||||||
{
|
{
|
||||||
// We shouldn't have to scoped_lock here, since referencing this object
|
// We shouldn't have to scoped_lock here, since referencing this object from another thread
|
||||||
// from another thread while we're deleting it in the current thread is
|
// while we're deleting it in the current thread is going to lead to undefined behavior
|
||||||
// going to lead to undefined behavior any way.
|
// any way.
|
||||||
for (std::list<thread*>::iterator it = m_threads.begin();
|
for (std::list<thread*>::iterator it = m_threads.begin(); it != m_threads.end(); ++it)
|
||||||
it != m_threads.end(); ++it)
|
|
||||||
{
|
|
||||||
delete (*it);
|
delete (*it);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
thread* thread_group::create_thread(const function0<void>& threadfunc)
|
thread* thread_group::create_thread(const function0<void>& threadfunc)
|
||||||
{
|
{
|
||||||
// No scoped_lock required here since the only "shared data" that's
|
// No scoped_lock required here since the only "shared data" that's modified here occurs
|
||||||
// modified here occurs inside add_thread which does scoped_lock.
|
// inside add_thread which does scoped_lock.
|
||||||
std::auto_ptr<thread> thrd(new thread(threadfunc));
|
std::auto_ptr<thread> thrd(new thread(threadfunc));
|
||||||
add_thread(thrd.get());
|
add_thread(thrd.get());
|
||||||
return thrd.release();
|
return thrd.release();
|
||||||
@@ -288,11 +280,9 @@ void thread_group::add_thread(thread* thrd)
|
|||||||
{
|
{
|
||||||
mutex::scoped_lock scoped_lock(m_mutex);
|
mutex::scoped_lock scoped_lock(m_mutex);
|
||||||
|
|
||||||
// For now we'll simply ignore requests to add a thread object multiple
|
// For now we'll simply ignore requests to add a thread object multiple times.
|
||||||
// times. Should we consider this an error and either throw or return an
|
// Should we consider this an error and either throw or return an error value?
|
||||||
// error value?
|
std::list<thread*>::iterator it = std::find(m_threads.begin(), m_threads.end(), thrd);
|
||||||
std::list<thread*>::iterator it = std::find(m_threads.begin(),
|
|
||||||
m_threads.end(), thrd);
|
|
||||||
assert(it == m_threads.end());
|
assert(it == m_threads.end());
|
||||||
if (it == m_threads.end())
|
if (it == m_threads.end())
|
||||||
m_threads.push_back(thrd);
|
m_threads.push_back(thrd);
|
||||||
@@ -302,11 +292,9 @@ void thread_group::remove_thread(thread* thrd)
|
|||||||
{
|
{
|
||||||
mutex::scoped_lock scoped_lock(m_mutex);
|
mutex::scoped_lock scoped_lock(m_mutex);
|
||||||
|
|
||||||
// For now we'll simply ignore requests to remove a thread object that's
|
// For now we'll simply ignore requests to remove a thread object that's not in the group.
|
||||||
// not in the group. Should we consider this an error and either throw or
|
// Should we consider this an error and either throw or return an error value?
|
||||||
// return an error value?
|
std::list<thread*>::iterator it = std::find(m_threads.begin(), m_threads.end(), thrd);
|
||||||
std::list<thread*>::iterator it = std::find(m_threads.begin(),
|
|
||||||
m_threads.end(), thrd);
|
|
||||||
assert(it != m_threads.end());
|
assert(it != m_threads.end());
|
||||||
if (it != m_threads.end())
|
if (it != m_threads.end())
|
||||||
m_threads.erase(it);
|
m_threads.erase(it);
|
||||||
@@ -315,12 +303,9 @@ void thread_group::remove_thread(thread* thrd)
|
|||||||
void thread_group::join_all()
|
void thread_group::join_all()
|
||||||
{
|
{
|
||||||
mutex::scoped_lock scoped_lock(m_mutex);
|
mutex::scoped_lock scoped_lock(m_mutex);
|
||||||
for (std::list<thread*>::iterator it = m_threads.begin();
|
for (std::list<thread*>::iterator it = m_threads.begin(); it != m_threads.end(); ++it)
|
||||||
it != m_threads.end(); ++it)
|
|
||||||
{
|
|
||||||
(*it)->join();
|
(*it)->join();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace boost
|
} // namespace boost
|
||||||
|
|
||||||
|
|||||||
@@ -1,21 +1,10 @@
|
|||||||
// Copyright (C) 2001-2003
|
// threadmon.cpp : Defines the entry point for the DLL application.
|
||||||
// William E. Kempf
|
|
||||||
//
|
//
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
|
||||||
// and its documentation for any purpose is hereby granted without fee,
|
|
||||||
// provided that the above copyright notice appear in all copies and
|
|
||||||
// that both that copyright notice and this permission notice appear
|
|
||||||
// in supporting documentation. William E. Kempf makes no representations
|
|
||||||
// about the suitability of this software for any purpose.
|
|
||||||
// It is provided "as is" without express or implied warranty.
|
|
||||||
|
|
||||||
#include <boost/config.hpp>
|
#define BOOST_THREADMON_EXPORTS
|
||||||
|
#include "threadmon.hpp"
|
||||||
|
|
||||||
#if defined(BOOST_HAS_WINTHREADS)
|
#ifdef BOOST_HAS_WINTHREADS
|
||||||
|
|
||||||
#if defined(BOOST_THREAD_BUILD_DLL)
|
|
||||||
|
|
||||||
#include <boost/thread/detail/threadmon.hpp>
|
|
||||||
|
|
||||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
@@ -44,7 +33,7 @@ registered_handlers registry;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
BOOL WINAPI DllMain(HANDLE /*module*/, DWORD reason, LPVOID)
|
BOOL WINAPI DllMain(HANDLE module, DWORD reason, LPVOID)
|
||||||
{
|
{
|
||||||
switch (reason)
|
switch (reason)
|
||||||
{
|
{
|
||||||
@@ -57,18 +46,13 @@ BOOL WINAPI DllMain(HANDLE /*module*/, DWORD reason, LPVOID)
|
|||||||
case DLL_THREAD_DETACH:
|
case DLL_THREAD_DETACH:
|
||||||
{
|
{
|
||||||
// Call the thread's exit handlers.
|
// Call the thread's exit handlers.
|
||||||
exit_handlers* handlers =
|
exit_handlers* handlers = static_cast<exit_handlers*>(TlsGetValue(key));
|
||||||
static_cast<exit_handlers*>(TlsGetValue(key));
|
|
||||||
if (handlers)
|
if (handlers)
|
||||||
{
|
{
|
||||||
for (exit_handlers::iterator it = handlers->begin();
|
for (exit_handlers::iterator it = handlers->begin(); it != handlers->end(); ++it)
|
||||||
it != handlers->end(); ++it)
|
|
||||||
{
|
|
||||||
(*it)();
|
(*it)();
|
||||||
}
|
|
||||||
|
|
||||||
// Remove the exit handler list from the registered lists
|
// Remove the exit handler list from the registered lists and then destroy it.
|
||||||
// and then destroy it.
|
|
||||||
EnterCriticalSection(&cs);
|
EnterCriticalSection(&cs);
|
||||||
registry.erase(handlers);
|
registry.erase(handlers);
|
||||||
LeaveCriticalSection(&cs);
|
LeaveCriticalSection(&cs);
|
||||||
@@ -78,31 +62,22 @@ BOOL WINAPI DllMain(HANDLE /*module*/, DWORD reason, LPVOID)
|
|||||||
break;
|
break;
|
||||||
case DLL_PROCESS_DETACH:
|
case DLL_PROCESS_DETACH:
|
||||||
{
|
{
|
||||||
// Assume the main thread is ending (call its handlers) and
|
// Assume the main thread is ending (call its handlers) and all other threads
|
||||||
// all other threads have already ended. If this DLL is
|
// have already ended. If this DLL is loaded and unloaded dynamically at run time
|
||||||
// loaded and unloaded dynamically at run time
|
|
||||||
// this is a bad assumption, but this is the best we can do.
|
// this is a bad assumption, but this is the best we can do.
|
||||||
exit_handlers* handlers =
|
exit_handlers* handlers = static_cast<exit_handlers*>(TlsGetValue(key));
|
||||||
static_cast<exit_handlers*>(TlsGetValue(key));
|
|
||||||
if (handlers)
|
if (handlers)
|
||||||
{
|
{
|
||||||
for (exit_handlers::iterator it = handlers->begin();
|
for (exit_handlers::iterator it = handlers->begin(); it != handlers->end(); ++it)
|
||||||
it != handlers->end(); ++it)
|
|
||||||
{
|
|
||||||
(*it)();
|
(*it)();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Destroy any remaining exit handlers. Above we assumed
|
// Destroy any remaining exit handlers. Above we assumed there'd only be the main
|
||||||
// there'd only be the main thread left, but to insure we
|
// thread left, but to insure we don't get memory leaks we won't make that assumption
|
||||||
// don't get memory leaks we won't make that assumption
|
|
||||||
// here.
|
// here.
|
||||||
EnterCriticalSection(&cs);
|
EnterCriticalSection(&cs);
|
||||||
for (registered_handlers::iterator it = registry.begin();
|
for (registered_handlers::iterator it = registry.begin(); it != registry.end(); ++it)
|
||||||
it != registry.end(); ++it)
|
|
||||||
{
|
|
||||||
delete (*it);
|
delete (*it);
|
||||||
}
|
|
||||||
LeaveCriticalSection(&cs);
|
LeaveCriticalSection(&cs);
|
||||||
DeleteCriticalSection(&cs);
|
DeleteCriticalSection(&cs);
|
||||||
TlsFree(key);
|
TlsFree(key);
|
||||||
@@ -112,7 +87,7 @@ BOOL WINAPI DllMain(HANDLE /*module*/, DWORD reason, LPVOID)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" BOOST_THREAD_DECL int on_thread_exit(void (__cdecl * func)(void))
|
int on_thread_exit(void (__cdecl * func)(void))
|
||||||
{
|
{
|
||||||
// Get the exit handlers for the current thread, creating and registering
|
// Get the exit handlers for the current thread, creating and registering
|
||||||
// one if it doesn't exist.
|
// one if it doesn't exist.
|
||||||
@@ -122,7 +97,7 @@ extern "C" BOOST_THREAD_DECL int on_thread_exit(void (__cdecl * func)(void))
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
handlers = new exit_handlers;
|
handlers = new exit_handlers;
|
||||||
// Handle broken implementations of operator new that don't throw.
|
// Handle "broken" implementations of operator new that don't throw.
|
||||||
if (!handlers)
|
if (!handlers)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -154,8 +129,8 @@ extern "C" BOOST_THREAD_DECL int on_thread_exit(void (__cdecl * func)(void))
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attempt to add the handler to the list of exit handlers. If it's been
|
// Attempt to add the handler to the list of exit handlers. If it's been previously
|
||||||
// previously added just report success and exit.
|
// added just report success and exit.
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
handlers->push_front(func);
|
handlers->push_front(func);
|
||||||
@@ -168,6 +143,4 @@ extern "C" BOOST_THREAD_DECL int on_thread_exit(void (__cdecl * func)(void))
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // BOOST_THREAD_BUILD_DLL
|
|
||||||
|
|
||||||
#endif // BOOST_HAS_WINTHREADS
|
#endif // BOOST_HAS_WINTHREADS
|
||||||
|
|||||||
23
src/threadmon.hpp
Normal file
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
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2001-2003
|
// Copyright (C) 2001
|
||||||
// William E. Kempf
|
// William E. Kempf
|
||||||
//
|
//
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
@@ -24,8 +24,7 @@ inline void to_time(int milliseconds, boost::xtime& xt)
|
|||||||
assert(res == boost::TIME_UTC);
|
assert(res == boost::TIME_UTC);
|
||||||
|
|
||||||
xt.sec += (milliseconds / MILLISECONDS_PER_SECOND);
|
xt.sec += (milliseconds / MILLISECONDS_PER_SECOND);
|
||||||
xt.nsec += ((milliseconds % MILLISECONDS_PER_SECOND) *
|
xt.nsec += ((milliseconds % MILLISECONDS_PER_SECOND) * NANOSECONDS_PER_MILLISECOND);
|
||||||
NANOSECONDS_PER_MILLISECOND);
|
|
||||||
|
|
||||||
if (xt.nsec > static_cast<const int>(NANOSECONDS_PER_SECOND))
|
if (xt.nsec > static_cast<const int>(NANOSECONDS_PER_SECOND))
|
||||||
{
|
{
|
||||||
@@ -60,7 +59,7 @@ inline void to_timespec_duration(const boost::xtime& xt, timespec& ts)
|
|||||||
res = boost::xtime_get(&cur, boost::TIME_UTC);
|
res = boost::xtime_get(&cur, boost::TIME_UTC);
|
||||||
assert(res == boost::TIME_UTC);
|
assert(res == boost::TIME_UTC);
|
||||||
|
|
||||||
if (boost::xtime_cmp(xt, cur) <= 0)
|
if (xt.sec < cur.sec || (xt.sec == cur.sec && xt.nsec < cur.nsec))
|
||||||
{
|
{
|
||||||
ts.tv_sec = 0;
|
ts.tv_sec = 0;
|
||||||
ts.tv_nsec = 0;
|
ts.tv_nsec = 0;
|
||||||
@@ -84,23 +83,18 @@ inline void to_timespec_duration(const boost::xtime& xt, timespec& ts)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
inline void to_duration(boost::xtime xt, int& milliseconds)
|
inline void to_duration(const boost::xtime& xt, int& milliseconds)
|
||||||
{
|
{
|
||||||
boost::xtime cur;
|
boost::xtime cur;
|
||||||
int res = 0;
|
int res = 0;
|
||||||
res = boost::xtime_get(&cur, boost::TIME_UTC);
|
res = boost::xtime_get(&cur, boost::TIME_UTC);
|
||||||
assert(res == boost::TIME_UTC);
|
assert(res == boost::TIME_UTC);
|
||||||
|
|
||||||
if (boost::xtime_cmp(xt, cur) <= 0)
|
if (xt.sec < cur.sec || (xt.sec == cur.sec && xt.nsec < cur.nsec))
|
||||||
milliseconds = 0;
|
milliseconds = 0;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (cur.nsec > xt.nsec)
|
milliseconds = ((xt.sec - cur.sec) * MILLISECONDS_PER_SECOND) +
|
||||||
{
|
|
||||||
xt.nsec += NANOSECONDS_PER_SECOND;
|
|
||||||
--xt.sec;
|
|
||||||
}
|
|
||||||
milliseconds = (int)((xt.sec - cur.sec) * MILLISECONDS_PER_SECOND) +
|
|
||||||
(((xt.nsec - cur.nsec) + (NANOSECONDS_PER_MILLISECOND/2)) /
|
(((xt.nsec - cur.nsec) + (NANOSECONDS_PER_MILLISECOND/2)) /
|
||||||
NANOSECONDS_PER_MILLISECOND);
|
NANOSECONDS_PER_MILLISECOND);
|
||||||
}
|
}
|
||||||
@@ -113,11 +107,11 @@ inline void to_microduration(const boost::xtime& xt, int& microseconds)
|
|||||||
res = boost::xtime_get(&cur, boost::TIME_UTC);
|
res = boost::xtime_get(&cur, boost::TIME_UTC);
|
||||||
assert(res == boost::TIME_UTC);
|
assert(res == boost::TIME_UTC);
|
||||||
|
|
||||||
if (boost::xtime_get(&cur, boost::TIME_UTC) <= 0)
|
if (xt.sec < cur.sec || (xt.sec == cur.sec && xt.nsec < cur.nsec))
|
||||||
microseconds = 0;
|
microseconds = 0;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
microseconds = (int)((xt.sec - cur.sec) * MICROSECONDS_PER_SECOND) +
|
microseconds = ((xt.sec - cur.sec) * MICROSECONDS_PER_SECOND) +
|
||||||
(((xt.nsec - cur.nsec) + (NANOSECONDS_PER_MICROSECOND/2)) /
|
(((xt.nsec - cur.nsec) + (NANOSECONDS_PER_MICROSECOND/2)) /
|
||||||
NANOSECONDS_PER_MICROSECOND);
|
NANOSECONDS_PER_MICROSECOND);
|
||||||
}
|
}
|
||||||
|
|||||||
33
src/tss.cpp
33
src/tss.cpp
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2001-2003
|
// Copyright (C) 2001
|
||||||
// William E. Kempf
|
// William E. Kempf
|
||||||
//
|
//
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(BOOST_HAS_WINTHREADS)
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
#include <boost/thread/detail/threadmon.hpp>
|
#include "threadmon.hpp"
|
||||||
#include <map>
|
#include <map>
|
||||||
namespace {
|
namespace {
|
||||||
typedef std::pair<void(*)(void*), void*> cleanup_info;
|
typedef std::pair<void(*)(void*), void*> cleanup_info;
|
||||||
@@ -37,10 +37,8 @@ void init_cleanup_key()
|
|||||||
|
|
||||||
void __cdecl cleanup()
|
void __cdecl cleanup()
|
||||||
{
|
{
|
||||||
cleanup_handlers* handlers = static_cast<cleanup_handlers*>(
|
cleanup_handlers* handlers = static_cast<cleanup_handlers*>(TlsGetValue(key));
|
||||||
TlsGetValue(key));
|
for (cleanup_handlers::iterator it = handlers->begin(); it != handlers->end(); ++it)
|
||||||
for (cleanup_handlers::iterator it = handlers->begin();
|
|
||||||
it != handlers->end(); ++it)
|
|
||||||
{
|
{
|
||||||
cleanup_info info = it->second;
|
cleanup_info info = it->second;
|
||||||
if (info.second)
|
if (info.second)
|
||||||
@@ -53,8 +51,7 @@ cleanup_handlers* get_handlers()
|
|||||||
{
|
{
|
||||||
boost::call_once(&init_cleanup_key, once);
|
boost::call_once(&init_cleanup_key, once);
|
||||||
|
|
||||||
cleanup_handlers* handlers = static_cast<cleanup_handlers*>(
|
cleanup_handlers* handlers = static_cast<cleanup_handlers*>(TlsGetValue(key));
|
||||||
TlsGetValue(key));
|
|
||||||
if (!handlers)
|
if (!handlers)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -94,8 +91,7 @@ cleanup_handlers* get_handlers()
|
|||||||
{
|
{
|
||||||
boost::call_once(&init_cleanup_key, once);
|
boost::call_once(&init_cleanup_key, once);
|
||||||
|
|
||||||
cleanup_handlers* handlers = reinterpret_cast<cleanup_handlers*>(
|
cleanup_handlers* handlers = reinterpret_cast<cleanup_handlers*>(MPGetTaskStorageValue(key));
|
||||||
MPGetTaskStorageValue(key));
|
|
||||||
if (!handlers)
|
if (!handlers)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -107,16 +103,14 @@ cleanup_handlers* get_handlers()
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
OSStatus lStatus = noErr;
|
OSStatus lStatus = noErr;
|
||||||
lStatus = MPSetTaskStorageValue(key,
|
lStatus = MPSetTaskStorageValue(key, reinterpret_cast<TaskStorageValue>(handlers));
|
||||||
reinterpret_cast<TaskStorageValue>(handlers));
|
|
||||||
assert(lStatus == noErr);
|
assert(lStatus == noErr);
|
||||||
// TODO - create a generalized mechanism for registering thread exit
|
// TODO - create a generalized mechanism for registering thread exit functions
|
||||||
// functions and use it here.
|
// and use it here.
|
||||||
}
|
}
|
||||||
|
|
||||||
return handlers;
|
return handlers;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace boost {
|
namespace boost {
|
||||||
@@ -126,12 +120,10 @@ namespace detail {
|
|||||||
|
|
||||||
void thread_cleanup()
|
void thread_cleanup()
|
||||||
{
|
{
|
||||||
cleanup_handlers* handlers = reinterpret_cast<cleanup_handlers*>(
|
cleanup_handlers* handlers = reinterpret_cast<cleanup_handlers*>(MPGetTaskStorageValue(key));
|
||||||
MPGetTaskStorageValue(key));
|
|
||||||
if(handlers != NULL)
|
if(handlers != NULL)
|
||||||
{
|
{
|
||||||
for (cleanup_handlers::iterator it = handlers->begin();
|
for (cleanup_handlers::iterator it = handlers->begin(); it != handlers->end(); ++it)
|
||||||
it != handlers->end(); ++it)
|
|
||||||
{
|
{
|
||||||
cleanup_info info = it->second;
|
cleanup_info info = it->second;
|
||||||
if (info.second)
|
if (info.second)
|
||||||
@@ -243,8 +235,7 @@ bool tss::set(void* value)
|
|||||||
cleanup_info info(m_cleanup, value);
|
cleanup_info info(m_cleanup, value);
|
||||||
(*handlers)[m_key] = info;
|
(*handlers)[m_key] = info;
|
||||||
}
|
}
|
||||||
OSStatus lStatus = MPSetTaskStorageValue(m_key,
|
OSStatus lStatus = MPSetTaskStorageValue(m_key, reinterpret_cast<TaskStorageValue>(value));
|
||||||
reinterpret_cast<TaskStorageValue>(value));
|
|
||||||
return(lStatus == noErr);
|
return(lStatus == noErr);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2001-2003
|
// Copyright (C) 2001
|
||||||
// William E. Kempf
|
// William E. Kempf
|
||||||
//
|
//
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
@@ -39,15 +39,14 @@ struct startup_time_info
|
|||||||
|
|
||||||
if(s_ulUNIXBaseSeconds == 0UL)
|
if(s_ulUNIXBaseSeconds == 0UL)
|
||||||
{
|
{
|
||||||
// calculate the number of seconds between the Mac OS base and the
|
// calculate the number of seconds between the Mac OS base and the UNIX base
|
||||||
// UNIX base the first time we enter this constructor.
|
// the first time we enter this constructor.
|
||||||
DateToSeconds(&k_sUNIXBase, &s_ulUNIXBaseSeconds);
|
DateToSeconds(&k_sUNIXBase, &s_ulUNIXBaseSeconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long ulSeconds;
|
unsigned long ulSeconds;
|
||||||
|
|
||||||
// get the time in UpTime units twice, with the time in seconds in the
|
// get the time in UpTime units twice, with the time in seconds in the middle.
|
||||||
// middle.
|
|
||||||
uint64_t ullFirstUpTime = force_cast<uint64_t>(UpTime());
|
uint64_t ullFirstUpTime = force_cast<uint64_t>(UpTime());
|
||||||
GetDateTime(&ulSeconds);
|
GetDateTime(&ulSeconds);
|
||||||
uint64_t ullSecondUpTime = force_cast<uint64_t>(UpTime());
|
uint64_t ullSecondUpTime = force_cast<uint64_t>(UpTime());
|
||||||
@@ -78,11 +77,8 @@ int xtime_get(struct xtime* xtp, int clock_type)
|
|||||||
#if defined(BOOST_HAS_FTIME)
|
#if defined(BOOST_HAS_FTIME)
|
||||||
FILETIME ft;
|
FILETIME ft;
|
||||||
GetSystemTimeAsFileTime(&ft);
|
GetSystemTimeAsFileTime(&ft);
|
||||||
const boost::uint64_t TIMESPEC_TO_FILETIME_OFFSET =
|
const boost::uint64_t TIMESPEC_TO_FILETIME_OFFSET = ((boost::uint64_t)27111902UL << 32) + (boost::uint64_t)3577643008UL;
|
||||||
((boost::uint64_t)27111902UL << 32) +
|
xtp->sec = (int)((*(__int64*)&ft - TIMESPEC_TO_FILETIME_OFFSET) / 10000000);
|
||||||
(boost::uint64_t)3577643008UL;
|
|
||||||
xtp->sec = (int)((*(__int64*)&ft - TIMESPEC_TO_FILETIME_OFFSET) /
|
|
||||||
10000000);
|
|
||||||
xtp->nsec = (int)((*(__int64*)&ft - TIMESPEC_TO_FILETIME_OFFSET -
|
xtp->nsec = (int)((*(__int64*)&ft - TIMESPEC_TO_FILETIME_OFFSET -
|
||||||
((__int64)xtp->sec * (__int64)10000000)) * 100);
|
((__int64)xtp->sec * (__int64)10000000)) * 100);
|
||||||
return clock_type;
|
return clock_type;
|
||||||
@@ -100,16 +96,12 @@ int xtime_get(struct xtime* xtp, int clock_type)
|
|||||||
return clock_type;
|
return clock_type;
|
||||||
#elif defined(BOOST_HAS_MPTASKS)
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
using detail::thread::force_cast;
|
using detail::thread::force_cast;
|
||||||
// the Mac OS does not have an MP-safe way of getting the date/time,
|
// the Mac OS does not have an MP-safe way of getting the date/time, so we use a
|
||||||
// so we use a delta from the startup time. We _could_ defer this
|
// delta from the startup time. We _could_ defer this and use something that is
|
||||||
// and use something that is interrupt-safe, but this would be _SLOW_,
|
// interrupt-safe, but this would be _SLOW_, and we need speed here.
|
||||||
// and we need speed here.
|
|
||||||
const uint64_t k_ullNanosecondsPerSecond(1000ULL * 1000ULL * 1000ULL);
|
const uint64_t k_ullNanosecondsPerSecond(1000ULL * 1000ULL * 1000ULL);
|
||||||
AbsoluteTime sUpTime(UpTime());
|
AbsoluteTime sUpTime(UpTime());
|
||||||
uint64_t ullNanoseconds(
|
uint64_t ullNanoseconds(force_cast<uint64_t>(AbsoluteDeltaToNanoseconds(sUpTime, detail::g_sStartupTimeInfo.m_sStartupAbsoluteTime)));
|
||||||
force_cast<uint64_t>(
|
|
||||||
AbsoluteDeltaToNanoseconds(sUpTime,
|
|
||||||
detail::g_sStartupTimeInfo.m_sStartupAbsoluteTime)));
|
|
||||||
uint64_t ullSeconds = (ullNanoseconds / k_ullNanosecondsPerSecond);
|
uint64_t ullSeconds = (ullNanoseconds / k_ullNanosecondsPerSecond);
|
||||||
ullNanoseconds -= (ullSeconds * k_ullNanosecondsPerSecond);
|
ullNanoseconds -= (ullSeconds * k_ullNanosecondsPerSecond);
|
||||||
xtp->sec = detail::g_sStartupTimeInfo.m_ulStartupSeconds + ullSeconds;
|
xtp->sec = detail::g_sStartupTimeInfo.m_ulStartupSeconds + ullSeconds;
|
||||||
|
|||||||
50
test/Jamfile
50
test/Jamfile
@@ -1,10 +1,12 @@
|
|||||||
# (C) Copyright William E. Kempf 2001. Permission to copy, use, modify, sell
|
# (C) Copyright William E. Kempf 2001. Permission to copy, use, modify, sell and
|
||||||
# and distribute this software is granted provided this copyright notice
|
# distribute this software is granted provided this copyright notice appears
|
||||||
# appears in all copies. This software is provided "as is" without express or
|
# in all copies. This software is provided "as is" without express or implied
|
||||||
# implied warranty, and with no claim as to its suitability for any purpose.
|
# warranty, and with no claim as to its suitability for any purpose.
|
||||||
#
|
#
|
||||||
# Boost.Threads test Jamfile
|
# Boost.Threads test Jamfile
|
||||||
#
|
#
|
||||||
|
# Declares the following targets:
|
||||||
|
# 1. test_thread, a unit test executable.
|
||||||
# Additional configuration variables used:
|
# Additional configuration variables used:
|
||||||
# 1. PTW32 may be used on Win32 platforms to specify that the pthreads-win32
|
# 1. PTW32 may be used on Win32 platforms to specify that the pthreads-win32
|
||||||
# library should be used instead of "native" threads. This feature is
|
# library should be used instead of "native" threads. This feature is
|
||||||
@@ -21,31 +23,21 @@ subproject libs/thread/test ;
|
|||||||
# Include threads.jam for Boost.Threads global build information.
|
# Include threads.jam for Boost.Threads global build information.
|
||||||
# This greatly simplifies the Jam code needed to configure the build
|
# This greatly simplifies the Jam code needed to configure the build
|
||||||
# for the various Win32 build types.
|
# for the various Win32 build types.
|
||||||
SEARCH on threads.jam = $(BOOST_ROOT)/libs/thread/build ;
|
SEARCH on <module@>threads.jam = $(BOOST_ROOT)/libs/thread/build ;
|
||||||
include threads.jam ;
|
include <module@>threads.jam ;
|
||||||
|
|
||||||
# bring in rules for testing
|
sources = test.cpp test_thread.cpp test_mutex.cpp test_condition.cpp test_tss.cpp test_once.cpp ;
|
||||||
SEARCH on testing.jam = $(BOOST_BUILD_PATH) ;
|
|
||||||
include testing.jam ;
|
|
||||||
|
|
||||||
{
|
#######################
|
||||||
template test
|
# Declare the Boost.Threads unit test program test_thread.
|
||||||
## sources ##
|
|
||||||
: <template>thread_base
|
unit-test test_thread
|
||||||
<dll>../build/boost_thread
|
: $(sources)
|
||||||
<lib>../../test/build/boost_unit_test_framework
|
<lib>../build/boost_thread
|
||||||
## requirements ##
|
<lib>../../test/build/unit_test_framework
|
||||||
:
|
$(threadmon)
|
||||||
## default build ##
|
: <sysinclude>$(BOOST_ROOT)
|
||||||
:
|
$(pthreads-win32)
|
||||||
|
<threading>multi
|
||||||
|
: debug release <runtime-link>static/dynamic
|
||||||
;
|
;
|
||||||
|
|
||||||
test-suite "threads"
|
|
||||||
: [ run test_thread.cpp <template>test ]
|
|
||||||
[ run test_mutex.cpp <template>test ]
|
|
||||||
[ run test_condition.cpp <template>test ]
|
|
||||||
[ run test_tss.cpp <template>test ]
|
|
||||||
[ run test_once.cpp <template>test ]
|
|
||||||
[ run test_xtime.cpp <template>test ]
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|||||||
20
test/test.cpp
Normal file
20
test/test.cpp
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
|
extern boost::unit_test_framework::test_suite* thread_tests();
|
||||||
|
extern boost::unit_test_framework::test_suite* mutex_tests();
|
||||||
|
extern boost::unit_test_framework::test_suite* condition_tests();
|
||||||
|
extern boost::unit_test_framework::test_suite* tss_tests();
|
||||||
|
extern boost::unit_test_framework::test_suite* once_tests();
|
||||||
|
|
||||||
|
boost::unit_test_framework::test_suite* init_unit_test_suite(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
boost::unit_test_framework::test_suite* test = BOOST_TEST_SUITE("Boost.Threads test suite");
|
||||||
|
|
||||||
|
test->add(thread_tests());
|
||||||
|
test->add(mutex_tests());
|
||||||
|
test->add(condition_tests());
|
||||||
|
test->add(tss_tests());
|
||||||
|
test->add(once_tests());
|
||||||
|
|
||||||
|
return test;
|
||||||
|
}
|
||||||
BIN
test/test.mcp
BIN
test/test.mcp
Binary file not shown.
@@ -1,22 +1,11 @@
|
|||||||
// Copyright (C) 2001-2003
|
|
||||||
// William E. Kempf
|
|
||||||
//
|
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
|
||||||
// and its documentation for any purpose is hereby granted without fee,
|
|
||||||
// provided that the above copyright notice appear in all copies and
|
|
||||||
// that both that copyright notice and this permission notice appear
|
|
||||||
// in supporting documentation. William E. Kempf makes no representations
|
|
||||||
// about the suitability of this software for any purpose.
|
|
||||||
// It is provided "as is" without express or implied warranty.
|
|
||||||
|
|
||||||
#include <boost/thread/condition.hpp>
|
#include <boost/thread/condition.hpp>
|
||||||
#include <boost/thread/thread.hpp>
|
#include <boost/thread/thread.hpp>
|
||||||
#include <boost/thread/xtime.hpp>
|
#include <boost/thread/xtime.hpp>
|
||||||
|
|
||||||
#include <boost/test/unit_test.hpp>
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
#include "util.inl"
|
namespace
|
||||||
|
{
|
||||||
struct condition_test_data
|
struct condition_test_data
|
||||||
{
|
{
|
||||||
condition_test_data() : notified(0), awoken(0) { }
|
condition_test_data() : notified(0), awoken(0) { }
|
||||||
@@ -27,16 +16,27 @@ struct condition_test_data
|
|||||||
int awoken;
|
int awoken;
|
||||||
};
|
};
|
||||||
|
|
||||||
void condition_test_thread(condition_test_data* data)
|
void condition_test_thread(void* param)
|
||||||
{
|
{
|
||||||
|
condition_test_data* data = static_cast<condition_test_data*>(param);
|
||||||
boost::mutex::scoped_lock lock(data->mutex);
|
boost::mutex::scoped_lock lock(data->mutex);
|
||||||
BOOST_CHECK(lock ? true : false);
|
BOOST_CHECK(lock);
|
||||||
while (!(data->notified > 0))
|
while (!(data->notified > 0))
|
||||||
data->condition.wait(lock);
|
data->condition.wait(lock);
|
||||||
BOOST_CHECK(lock ? true : false);
|
BOOST_CHECK(lock);
|
||||||
data->awoken++;
|
data->awoken++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class thread_adapter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
thread_adapter(void (*func)(void*), void* param) : _func(func), _param(param) { }
|
||||||
|
void operator()() const { _func(_param); }
|
||||||
|
private:
|
||||||
|
void (*_func)(void*);
|
||||||
|
void* _param;
|
||||||
|
};
|
||||||
|
|
||||||
struct cond_predicate
|
struct cond_predicate
|
||||||
{
|
{
|
||||||
cond_predicate(int& var, int val) : _var(var), _val(val) { }
|
cond_predicate(int& var, int val) : _var(var), _val(val) { }
|
||||||
@@ -47,55 +47,58 @@ struct cond_predicate
|
|||||||
int _val;
|
int _val;
|
||||||
};
|
};
|
||||||
|
|
||||||
void condition_test_waits(condition_test_data* data)
|
void condition_test_waits(void* param)
|
||||||
{
|
{
|
||||||
|
condition_test_data* data = static_cast<condition_test_data*>(param);
|
||||||
|
|
||||||
boost::mutex::scoped_lock lock(data->mutex);
|
boost::mutex::scoped_lock lock(data->mutex);
|
||||||
BOOST_CHECK(lock ? true : false);
|
BOOST_CHECK(lock);
|
||||||
|
|
||||||
// Test wait.
|
// Test wait.
|
||||||
while (data->notified != 1)
|
while (data->notified != 1)
|
||||||
data->condition.wait(lock);
|
data->condition.wait(lock);
|
||||||
BOOST_CHECK(lock ? true : false);
|
BOOST_CHECK(lock);
|
||||||
BOOST_CHECK_EQUAL(data->notified, 1);
|
BOOST_CHECK_EQUAL(data->notified, 1);
|
||||||
data->awoken++;
|
data->awoken++;
|
||||||
data->condition.notify_one();
|
data->condition.notify_one();
|
||||||
|
|
||||||
// Test predicate wait.
|
// Test predicate wait.
|
||||||
data->condition.wait(lock, cond_predicate(data->notified, 2));
|
data->condition.wait(lock, cond_predicate(data->notified, 2));
|
||||||
BOOST_CHECK(lock ? true : false);
|
BOOST_CHECK(lock);
|
||||||
BOOST_CHECK_EQUAL(data->notified, 2);
|
BOOST_CHECK_EQUAL(data->notified, 2);
|
||||||
data->awoken++;
|
data->awoken++;
|
||||||
data->condition.notify_one();
|
data->condition.notify_one();
|
||||||
|
|
||||||
// Test timed_wait.
|
// Test timed_wait.
|
||||||
boost::xtime xt = delay(10);
|
boost::xtime xt;
|
||||||
|
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), boost::TIME_UTC);
|
||||||
|
xt.nsec += 100000000;
|
||||||
while (data->notified != 3)
|
while (data->notified != 3)
|
||||||
data->condition.timed_wait(lock, xt);
|
data->condition.timed_wait(lock, xt);
|
||||||
BOOST_CHECK(lock ? true : false);
|
BOOST_CHECK(lock);
|
||||||
BOOST_CHECK_EQUAL(data->notified, 3);
|
BOOST_CHECK_EQUAL(data->notified, 3);
|
||||||
data->awoken++;
|
data->awoken++;
|
||||||
data->condition.notify_one();
|
data->condition.notify_one();
|
||||||
|
|
||||||
// Test predicate timed_wait.
|
// Test predicate timed_wait.
|
||||||
xt = delay(10);
|
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), boost::TIME_UTC);
|
||||||
cond_predicate pred(data->notified, 4);
|
xt.sec += 2;
|
||||||
BOOST_CHECK(data->condition.timed_wait(lock, xt, pred));
|
BOOST_CHECK(data->condition.timed_wait(lock, xt, cond_predicate(data->notified, 4)));
|
||||||
BOOST_CHECK(lock ? true : false);
|
BOOST_CHECK(lock);
|
||||||
BOOST_CHECK(pred());
|
|
||||||
BOOST_CHECK_EQUAL(data->notified, 4);
|
BOOST_CHECK_EQUAL(data->notified, 4);
|
||||||
data->awoken++;
|
data->awoken++;
|
||||||
data->condition.notify_one();
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_test_condition_notify_one()
|
void test_condition_notify_one()
|
||||||
{
|
{
|
||||||
condition_test_data data;
|
condition_test_data data;
|
||||||
|
|
||||||
boost::thread thread(bind(&condition_test_thread, &data));
|
boost::thread thread(thread_adapter(&condition_test_thread, &data));
|
||||||
|
|
||||||
{
|
{
|
||||||
boost::mutex::scoped_lock lock(data.mutex);
|
boost::mutex::scoped_lock lock(data.mutex);
|
||||||
BOOST_CHECK(lock ? true : false);
|
BOOST_CHECK(lock);
|
||||||
data.notified++;
|
data.notified++;
|
||||||
data.condition.notify_one();
|
data.condition.notify_one();
|
||||||
}
|
}
|
||||||
@@ -104,23 +107,18 @@ void do_test_condition_notify_one()
|
|||||||
BOOST_CHECK_EQUAL(data.awoken, 1);
|
BOOST_CHECK_EQUAL(data.awoken, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_condition_notify_one()
|
void test_condition_notify_all()
|
||||||
{
|
|
||||||
timed_test(&do_test_condition_notify_one, 2, execution_monitor::use_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void do_test_condition_notify_all()
|
|
||||||
{
|
{
|
||||||
const int NUMTHREADS = 5;
|
const int NUMTHREADS = 5;
|
||||||
boost::thread_group threads;
|
boost::thread_group threads;
|
||||||
condition_test_data data;
|
condition_test_data data;
|
||||||
|
|
||||||
for (int i = 0; i < NUMTHREADS; ++i)
|
for (int i = 0; i < NUMTHREADS; ++i)
|
||||||
threads.create_thread(bind(&condition_test_thread, &data));
|
threads.create_thread(thread_adapter(&condition_test_thread, &data));
|
||||||
|
|
||||||
{
|
{
|
||||||
boost::mutex::scoped_lock lock(data.mutex);
|
boost::mutex::scoped_lock lock(data.mutex);
|
||||||
BOOST_CHECK(lock ? true : false);
|
BOOST_CHECK(lock);
|
||||||
data.notified++;
|
data.notified++;
|
||||||
data.condition.notify_all();
|
data.condition.notify_all();
|
||||||
}
|
}
|
||||||
@@ -129,73 +127,61 @@ void do_test_condition_notify_all()
|
|||||||
BOOST_CHECK_EQUAL(data.awoken, NUMTHREADS);
|
BOOST_CHECK_EQUAL(data.awoken, NUMTHREADS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_condition_notify_all()
|
void test_condition_waits()
|
||||||
{
|
|
||||||
// We should have already tested notify_one here, so
|
|
||||||
// a timed test with the default execution_monitor::use_condition
|
|
||||||
// should be OK, and gives the fastest performance
|
|
||||||
timed_test(&do_test_condition_notify_all, 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
void do_test_condition_waits()
|
|
||||||
{
|
{
|
||||||
condition_test_data data;
|
condition_test_data data;
|
||||||
|
|
||||||
boost::thread thread(bind(&condition_test_waits, &data));
|
boost::thread thread(thread_adapter(&condition_test_waits, &data));
|
||||||
|
|
||||||
|
boost::xtime xt;
|
||||||
|
|
||||||
{
|
{
|
||||||
boost::mutex::scoped_lock lock(data.mutex);
|
boost::mutex::scoped_lock lock(data.mutex);
|
||||||
BOOST_CHECK(lock ? true : false);
|
BOOST_CHECK(lock);
|
||||||
|
|
||||||
boost::thread::sleep(delay(1));
|
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), boost::TIME_UTC);
|
||||||
|
xt.sec += 1;
|
||||||
|
boost::thread::sleep(xt);
|
||||||
data.notified++;
|
data.notified++;
|
||||||
data.condition.notify_one();
|
data.condition.notify_one();
|
||||||
while (data.awoken != 1)
|
while (data.awoken != 1)
|
||||||
data.condition.wait(lock);
|
data.condition.wait(lock);
|
||||||
BOOST_CHECK(lock ? true : false);
|
|
||||||
BOOST_CHECK_EQUAL(data.awoken, 1);
|
BOOST_CHECK_EQUAL(data.awoken, 1);
|
||||||
|
|
||||||
boost::thread::sleep(delay(1));
|
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), boost::TIME_UTC);
|
||||||
|
xt.sec += 1;
|
||||||
|
boost::thread::sleep(xt);
|
||||||
data.notified++;
|
data.notified++;
|
||||||
data.condition.notify_one();
|
data.condition.notify_one();
|
||||||
while (data.awoken != 2)
|
while (data.awoken != 2)
|
||||||
data.condition.wait(lock);
|
data.condition.wait(lock);
|
||||||
BOOST_CHECK(lock ? true : false);
|
|
||||||
BOOST_CHECK_EQUAL(data.awoken, 2);
|
BOOST_CHECK_EQUAL(data.awoken, 2);
|
||||||
|
|
||||||
boost::thread::sleep(delay(1));
|
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), boost::TIME_UTC);
|
||||||
|
xt.sec += 1;
|
||||||
|
boost::thread::sleep(xt);
|
||||||
data.notified++;
|
data.notified++;
|
||||||
data.condition.notify_one();
|
data.condition.notify_one();
|
||||||
while (data.awoken != 3)
|
while (data.awoken != 3)
|
||||||
data.condition.wait(lock);
|
data.condition.wait(lock);
|
||||||
BOOST_CHECK(lock ? true : false);
|
|
||||||
BOOST_CHECK_EQUAL(data.awoken, 3);
|
BOOST_CHECK_EQUAL(data.awoken, 3);
|
||||||
|
|
||||||
boost::thread::sleep(delay(1));
|
|
||||||
data.notified++;
|
|
||||||
data.condition.notify_one();
|
|
||||||
while (data.awoken != 4)
|
|
||||||
data.condition.wait(lock);
|
|
||||||
BOOST_CHECK(lock ? true : false);
|
|
||||||
BOOST_CHECK_EQUAL(data.awoken, 4);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), boost::TIME_UTC);
|
||||||
|
xt.sec += 1;
|
||||||
|
boost::thread::sleep(xt);
|
||||||
|
data.notified++;
|
||||||
|
data.condition.notify_one();
|
||||||
|
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), boost::TIME_UTC);
|
||||||
|
xt.sec += 1;
|
||||||
|
boost::thread::sleep(xt);
|
||||||
thread.join();
|
thread.join();
|
||||||
BOOST_CHECK_EQUAL(data.awoken, 4);
|
BOOST_CHECK_EQUAL(data.awoken, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_condition_waits()
|
boost::unit_test_framework::test_suite* condition_tests()
|
||||||
{
|
{
|
||||||
// We should have already tested notify_one here, so
|
boost::unit_test_framework::test_suite* test = BOOST_TEST_SUITE("Boost.Threads: condition test suite");
|
||||||
// a timed test with the default execution_monitor::use_condition
|
|
||||||
// should be OK, and gives the fastest performance
|
|
||||||
timed_test(&do_test_condition_waits, 12);
|
|
||||||
}
|
|
||||||
|
|
||||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
|
||||||
{
|
|
||||||
boost::unit_test_framework::test_suite* test =
|
|
||||||
BOOST_TEST_SUITE("Boost.Threads: condition test suite");
|
|
||||||
|
|
||||||
test->add(BOOST_TEST_CASE(&test_condition_notify_one));
|
test->add(BOOST_TEST_CASE(&test_condition_notify_one));
|
||||||
test->add(BOOST_TEST_CASE(&test_condition_notify_all));
|
test->add(BOOST_TEST_CASE(&test_condition_notify_all));
|
||||||
|
|||||||
@@ -1,14 +1,3 @@
|
|||||||
// Copyright (C) 2001-2003
|
|
||||||
// William E. Kempf
|
|
||||||
//
|
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
|
||||||
// and its documentation for any purpose is hereby granted without fee,
|
|
||||||
// provided that the above copyright notice appear in all copies and
|
|
||||||
// that both that copyright notice and this permission notice appear
|
|
||||||
// in supporting documentation. William E. Kempf makes no representations
|
|
||||||
// about the suitability of this software for any purpose.
|
|
||||||
// It is provided "as is" without express or implied warranty.
|
|
||||||
|
|
||||||
#include <boost/thread/mutex.hpp>
|
#include <boost/thread/mutex.hpp>
|
||||||
#include <boost/thread/recursive_mutex.hpp>
|
#include <boost/thread/recursive_mutex.hpp>
|
||||||
#include <boost/thread/xtime.hpp>
|
#include <boost/thread/xtime.hpp>
|
||||||
@@ -17,9 +6,6 @@
|
|||||||
#include <boost/test/unit_test.hpp>
|
#include <boost/test/unit_test.hpp>
|
||||||
#include <boost/test/unit_test_suite_ex.hpp>
|
#include <boost/test/unit_test_suite_ex.hpp>
|
||||||
|
|
||||||
#define DEFAULT_EXECUTION_MONITOR_TYPE execution_monitor::use_sleep_only
|
|
||||||
#include "util.inl"
|
|
||||||
|
|
||||||
template <typename M>
|
template <typename M>
|
||||||
struct test_lock
|
struct test_lock
|
||||||
{
|
{
|
||||||
@@ -37,22 +23,24 @@ struct test_lock
|
|||||||
BOOST_CHECK(!lock);
|
BOOST_CHECK(!lock);
|
||||||
}
|
}
|
||||||
lock_type lock(mutex);
|
lock_type lock(mutex);
|
||||||
BOOST_CHECK(lock ? true : false);
|
BOOST_CHECK(lock);
|
||||||
|
|
||||||
// Construct and initialize an xtime for a fast time out.
|
// Construct and initialize an xtime for a fast time out.
|
||||||
boost::xtime xt = delay(0, 100);
|
boost::xtime xt;
|
||||||
|
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), boost::TIME_UTC);
|
||||||
|
xt.nsec += 100000000;
|
||||||
|
|
||||||
// Test the lock and the mutex with condition variables.
|
// Test the lock and the mutex with condition variables.
|
||||||
// No one is going to notify this condition variable. We expect to
|
// No one is going to notify this condition variable. We expect to
|
||||||
// time out.
|
// time out.
|
||||||
BOOST_CHECK(!condition.timed_wait(lock, xt));
|
BOOST_CHECK(!condition.timed_wait(lock, xt));
|
||||||
BOOST_CHECK(lock ? true : false);
|
BOOST_CHECK(lock);
|
||||||
|
|
||||||
// Test the lock and unlock methods.
|
// Test the lock and unlock methods.
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
BOOST_CHECK(!lock);
|
BOOST_CHECK(!lock);
|
||||||
lock.lock();
|
lock.lock();
|
||||||
BOOST_CHECK(lock ? true : false);
|
BOOST_CHECK(lock);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -70,33 +58,35 @@ struct test_trylock
|
|||||||
// Test the lock's constructors.
|
// Test the lock's constructors.
|
||||||
{
|
{
|
||||||
try_lock_type lock(mutex);
|
try_lock_type lock(mutex);
|
||||||
BOOST_CHECK(lock ? true : false);
|
BOOST_CHECK(lock);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
try_lock_type lock(mutex, false);
|
try_lock_type lock(mutex, false);
|
||||||
BOOST_CHECK(!lock);
|
BOOST_CHECK(!lock);
|
||||||
}
|
}
|
||||||
try_lock_type lock(mutex, true);
|
try_lock_type lock(mutex, true);
|
||||||
BOOST_CHECK(lock ? true : false);
|
BOOST_CHECK(lock);
|
||||||
|
|
||||||
// Construct and initialize an xtime for a fast time out.
|
// Construct and initialize an xtime for a fast time out.
|
||||||
boost::xtime xt = delay(0, 100);
|
boost::xtime xt;
|
||||||
|
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), boost::TIME_UTC);
|
||||||
|
xt.nsec += 100000000;
|
||||||
|
|
||||||
// Test the lock and the mutex with condition variables.
|
// Test the lock and the mutex with condition variables.
|
||||||
// No one is going to notify this condition variable. We expect to
|
// No one is going to notify this condition variable. We expect to
|
||||||
// time out.
|
// time out.
|
||||||
BOOST_CHECK(!condition.timed_wait(lock, xt));
|
BOOST_CHECK(!condition.timed_wait(lock, xt));
|
||||||
BOOST_CHECK(lock ? true : false);
|
BOOST_CHECK(lock);
|
||||||
|
|
||||||
// Test the lock, unlock and trylock methods.
|
// Test the lock, unlock and trylock methods.
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
BOOST_CHECK(!lock);
|
BOOST_CHECK(!lock);
|
||||||
lock.lock();
|
lock.lock();
|
||||||
BOOST_CHECK(lock ? true : false);
|
BOOST_CHECK(lock);
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
BOOST_CHECK(!lock);
|
BOOST_CHECK(!lock);
|
||||||
BOOST_CHECK(lock.try_lock());
|
BOOST_CHECK(lock.try_lock());
|
||||||
BOOST_CHECK(lock ? true : false);
|
BOOST_CHECK(lock);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -114,135 +104,81 @@ struct test_timedlock
|
|||||||
// Test the lock's constructors.
|
// Test the lock's constructors.
|
||||||
{
|
{
|
||||||
// Construct and initialize an xtime for a fast time out.
|
// Construct and initialize an xtime for a fast time out.
|
||||||
boost::xtime xt = delay(0, 100);
|
boost::xtime xt;
|
||||||
|
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), boost::TIME_UTC);
|
||||||
|
xt.nsec += 100000000;
|
||||||
|
|
||||||
timed_lock_type lock(mutex, xt);
|
timed_lock_type lock(mutex, xt);
|
||||||
BOOST_CHECK(lock ? true : false);
|
BOOST_CHECK(lock);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
timed_lock_type lock(mutex, false);
|
timed_lock_type lock(mutex, false);
|
||||||
BOOST_CHECK(!lock);
|
BOOST_CHECK(!lock);
|
||||||
}
|
}
|
||||||
timed_lock_type lock(mutex, true);
|
timed_lock_type lock(mutex, true);
|
||||||
BOOST_CHECK(lock ? true : false);
|
BOOST_CHECK(lock);
|
||||||
|
|
||||||
// Construct and initialize an xtime for a fast time out.
|
// Construct and initialize an xtime for a fast time out.
|
||||||
boost::xtime xt = delay(0, 100);
|
boost::xtime xt;
|
||||||
|
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), boost::TIME_UTC);
|
||||||
|
xt.nsec += 100000000;
|
||||||
|
|
||||||
// Test the lock and the mutex with condition variables.
|
// Test the lock and the mutex with condition variables.
|
||||||
// No one is going to notify this condition variable. We expect to
|
// No one is going to notify this condition variable. We expect to
|
||||||
// time out.
|
// time out.
|
||||||
BOOST_CHECK(!condition.timed_wait(lock, xt));
|
BOOST_CHECK(!condition.timed_wait(lock, xt));
|
||||||
BOOST_CHECK(lock ? true : false);
|
BOOST_CHECK(lock);
|
||||||
BOOST_CHECK(in_range(xt));
|
|
||||||
|
|
||||||
// Test the lock, unlock and timedlock methods.
|
// Test the lock, unlock and timedlock methods.
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
BOOST_CHECK(!lock);
|
BOOST_CHECK(!lock);
|
||||||
lock.lock();
|
lock.lock();
|
||||||
BOOST_CHECK(lock ? true : false);
|
BOOST_CHECK(lock);
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
BOOST_CHECK(!lock);
|
BOOST_CHECK(!lock);
|
||||||
xt = delay(0, 100);
|
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), boost::TIME_UTC);
|
||||||
|
xt.nsec += 100000000;
|
||||||
BOOST_CHECK(lock.timed_lock(xt));
|
BOOST_CHECK(lock.timed_lock(xt));
|
||||||
BOOST_CHECK(lock ? true : false);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename M>
|
template <typename M>
|
||||||
struct test_recursive_lock
|
struct test_recursive_lock
|
||||||
{
|
{
|
||||||
typedef M mutex_type;
|
typedef M mutex;
|
||||||
typedef typename M::scoped_lock lock_type;
|
|
||||||
|
|
||||||
void operator()()
|
void operator()()
|
||||||
{
|
{
|
||||||
mutex_type mx;
|
mutex mx;
|
||||||
lock_type lock1(mx);
|
mutex::scoped_lock lock1(mx);
|
||||||
lock_type lock2(mx);
|
mutex::scoped_lock lock2(mx);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void do_test_mutex()
|
boost::unit_test_framework::test_suite* mutex_tests()
|
||||||
{
|
{
|
||||||
test_lock<boost::mutex>()();
|
boost::unit_test_framework::test_suite* test = BOOST_TEST_SUITE("Boost.Threads: mutex test suite");
|
||||||
}
|
|
||||||
|
|
||||||
void test_mutex()
|
test->add(BOOST_TEST_CASE(test_lock<boost::mutex>()));
|
||||||
{
|
|
||||||
timed_test(&do_test_mutex, 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
void do_test_try_mutex()
|
test->add(BOOST_TEST_CASE(test_lock<boost::try_mutex>()));
|
||||||
{
|
test->add(BOOST_TEST_CASE(test_trylock<boost::try_mutex>()));
|
||||||
test_lock<boost::try_mutex>()();
|
|
||||||
test_trylock<boost::try_mutex>()();
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_try_mutex()
|
test->add(BOOST_TEST_CASE(test_lock<boost::timed_mutex>()));
|
||||||
{
|
test->add(BOOST_TEST_CASE(test_trylock<boost::timed_mutex>()));
|
||||||
timed_test(&do_test_try_mutex, 3);
|
test->add(BOOST_TEST_CASE(test_timedlock<boost::timed_mutex>()));
|
||||||
}
|
|
||||||
|
|
||||||
void do_test_timed_mutex()
|
test->add(BOOST_TEST_CASE(test_lock<boost::recursive_mutex>()));
|
||||||
{
|
test->add(BOOST_TEST_CASE(test_recursive_lock<boost::recursive_mutex>()));
|
||||||
test_lock<boost::timed_mutex>()();
|
|
||||||
test_trylock<boost::timed_mutex>()();
|
|
||||||
test_timedlock<boost::timed_mutex>()();
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_timed_mutex()
|
test->add(BOOST_TEST_CASE(test_lock<boost::recursive_try_mutex>()));
|
||||||
{
|
test->add(BOOST_TEST_CASE(test_trylock<boost::recursive_try_mutex>()));
|
||||||
timed_test(&do_test_timed_mutex, 3);
|
test->add(BOOST_TEST_CASE(test_recursive_lock<boost::recursive_try_mutex>()));
|
||||||
}
|
|
||||||
|
|
||||||
void do_test_recursive_mutex()
|
test->add(BOOST_TEST_CASE(test_lock<boost::recursive_timed_mutex>()));
|
||||||
{
|
test->add(BOOST_TEST_CASE(test_trylock<boost::recursive_timed_mutex>()));
|
||||||
test_lock<boost::recursive_mutex>()();
|
test->add(BOOST_TEST_CASE(test_timedlock<boost::recursive_timed_mutex>()));
|
||||||
test_recursive_lock<boost::recursive_mutex>()();
|
test->add(BOOST_TEST_CASE(test_recursive_lock<boost::recursive_timed_mutex>()));
|
||||||
}
|
|
||||||
|
|
||||||
void test_recursive_mutex()
|
|
||||||
{
|
|
||||||
timed_test(&do_test_recursive_mutex, 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
void do_test_recursive_try_mutex()
|
|
||||||
{
|
|
||||||
test_lock<boost::recursive_try_mutex>()();
|
|
||||||
test_trylock<boost::recursive_try_mutex>()();
|
|
||||||
test_recursive_lock<boost::recursive_try_mutex>()();
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_recursive_try_mutex()
|
|
||||||
{
|
|
||||||
timed_test(&do_test_recursive_try_mutex, 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
void do_test_recursive_timed_mutex()
|
|
||||||
{
|
|
||||||
test_lock<boost::recursive_timed_mutex>()();
|
|
||||||
test_trylock<boost::recursive_timed_mutex>()();
|
|
||||||
test_timedlock<boost::recursive_timed_mutex>()();
|
|
||||||
test_recursive_lock<boost::recursive_timed_mutex>()();
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_recursive_timed_mutex()
|
|
||||||
{
|
|
||||||
timed_test(&do_test_recursive_timed_mutex, 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
|
||||||
{
|
|
||||||
boost::unit_test_framework::test_suite* test =
|
|
||||||
BOOST_TEST_SUITE("Boost.Threads: mutex test suite");
|
|
||||||
|
|
||||||
test->add(BOOST_TEST_CASE(&test_mutex));
|
|
||||||
test->add(BOOST_TEST_CASE(&test_try_mutex));
|
|
||||||
test->add(BOOST_TEST_CASE(&test_timed_mutex));
|
|
||||||
test->add(BOOST_TEST_CASE(&test_recursive_mutex));
|
|
||||||
test->add(BOOST_TEST_CASE(&test_recursive_try_mutex));
|
|
||||||
test->add(BOOST_TEST_CASE(&test_recursive_timed_mutex));
|
|
||||||
|
|
||||||
return test;
|
return test;
|
||||||
}
|
}
|
||||||
@@ -1,21 +1,10 @@
|
|||||||
// Copyright (C) 2001-2003
|
|
||||||
// William E. Kempf
|
|
||||||
//
|
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
|
||||||
// and its documentation for any purpose is hereby granted without fee,
|
|
||||||
// provided that the above copyright notice appear in all copies and
|
|
||||||
// that both that copyright notice and this permission notice appear
|
|
||||||
// in supporting documentation. William E. Kempf makes no representations
|
|
||||||
// about the suitability of this software for any purpose.
|
|
||||||
// It is provided "as is" without express or implied warranty.
|
|
||||||
|
|
||||||
#include <boost/thread/once.hpp>
|
#include <boost/thread/once.hpp>
|
||||||
#include <boost/thread/thread.hpp>
|
#include <boost/thread/thread.hpp>
|
||||||
|
|
||||||
#include <boost/test/unit_test.hpp>
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
#include "util.inl"
|
namespace
|
||||||
|
{
|
||||||
int once_value = 0;
|
int once_value = 0;
|
||||||
boost::once_flag once = BOOST_ONCE_INIT;
|
boost::once_flag once = BOOST_ONCE_INIT;
|
||||||
|
|
||||||
@@ -26,10 +15,11 @@ void init_once_value()
|
|||||||
|
|
||||||
void test_once_thread()
|
void test_once_thread()
|
||||||
{
|
{
|
||||||
boost::call_once(init_once_value, once);
|
boost::call_once(&init_once_value, once);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_test_once()
|
void test_once()
|
||||||
{
|
{
|
||||||
const int NUMTHREADS=5;
|
const int NUMTHREADS=5;
|
||||||
boost::thread_group threads;
|
boost::thread_group threads;
|
||||||
@@ -39,17 +29,11 @@ void do_test_once()
|
|||||||
BOOST_CHECK_EQUAL(once_value, 1);
|
BOOST_CHECK_EQUAL(once_value, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_once()
|
boost::unit_test_framework::test_suite* once_tests()
|
||||||
{
|
{
|
||||||
timed_test(&do_test_once, 2);
|
boost::unit_test_framework::test_suite* test = BOOST_TEST_SUITE("Boost.Threads: once test suite");
|
||||||
}
|
|
||||||
|
|
||||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
test->add(BOOST_TEST_CASE(&test_once));
|
||||||
{
|
|
||||||
boost::unit_test_framework::test_suite* test =
|
|
||||||
BOOST_TEST_SUITE("Boost.Threads: once test suite");
|
|
||||||
|
|
||||||
test->add(BOOST_TEST_CASE(test_once));
|
|
||||||
|
|
||||||
return test;
|
return test;
|
||||||
}
|
}
|
||||||
@@ -1,21 +1,23 @@
|
|||||||
// Copyright (C) 2001-2003
|
|
||||||
// William E. Kempf
|
|
||||||
//
|
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
|
||||||
// and its documentation for any purpose is hereby granted without fee,
|
|
||||||
// provided that the above copyright notice appear in all copies and
|
|
||||||
// that both that copyright notice and this permission notice appear
|
|
||||||
// in supporting documentation. William E. Kempf makes no representations
|
|
||||||
// about the suitability of this software for any purpose.
|
|
||||||
// It is provided "as is" without express or implied warranty.
|
|
||||||
|
|
||||||
#include <boost/thread/thread.hpp>
|
#include <boost/thread/thread.hpp>
|
||||||
#include <boost/thread/xtime.hpp>
|
#include <boost/thread/xtime.hpp>
|
||||||
|
|
||||||
#include <boost/test/unit_test.hpp>
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
#define DEFAULT_EXECUTION_MONITOR_TYPE execution_monitor::use_sleep_only
|
namespace
|
||||||
#include "util.inl"
|
{
|
||||||
|
inline bool xtime_in_range(boost::xtime& xt, int less_seconds, int greater_seconds)
|
||||||
|
{
|
||||||
|
boost::xtime cur;
|
||||||
|
BOOST_CHECK_EQUAL(boost::xtime_get(&cur, boost::TIME_UTC), boost::TIME_UTC);
|
||||||
|
|
||||||
|
boost::xtime less = cur;
|
||||||
|
less.sec += less_seconds;
|
||||||
|
|
||||||
|
boost::xtime greater = cur;
|
||||||
|
greater.sec += greater_seconds;
|
||||||
|
|
||||||
|
return (boost::xtime_cmp(xt, less) >= 0) && (boost::xtime_cmp(xt, greater) <= 0);
|
||||||
|
}
|
||||||
|
|
||||||
int test_value;
|
int test_value;
|
||||||
|
|
||||||
@@ -24,24 +26,43 @@ void simple_thread()
|
|||||||
test_value = 999;
|
test_value = 999;
|
||||||
}
|
}
|
||||||
|
|
||||||
void comparison_thread(boost::thread* parent)
|
struct thread_adapter
|
||||||
|
{
|
||||||
|
thread_adapter(void (*func)(boost::thread& parent), boost::thread& parent)
|
||||||
|
: func(func), parent(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator()()
|
||||||
|
{
|
||||||
|
(*func)(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void (*func)(boost::thread& parent);
|
||||||
|
boost::thread& parent;
|
||||||
|
};
|
||||||
|
|
||||||
|
void comparison_thread(boost::thread& parent)
|
||||||
{
|
{
|
||||||
boost::thread thrd;
|
boost::thread thrd;
|
||||||
BOOST_TEST(thrd != *parent);
|
BOOST_TEST(thrd != parent);
|
||||||
BOOST_TEST(thrd == boost::thread());
|
BOOST_TEST(thrd == boost::thread());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void test_sleep()
|
void test_sleep()
|
||||||
{
|
{
|
||||||
boost::xtime xt = delay(3);
|
boost::xtime xt;
|
||||||
|
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), boost::TIME_UTC);
|
||||||
|
xt.sec += 5;
|
||||||
|
|
||||||
boost::thread::sleep(xt);
|
boost::thread::sleep(xt);
|
||||||
|
|
||||||
// Ensure it's in a range instead of checking actual equality due to time
|
// Insure it's in a range instead of checking actual equality due to time lapse
|
||||||
// lapse
|
BOOST_CHECK(xtime_in_range(xt, -1, 1));
|
||||||
BOOST_CHECK(in_range(xt));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_test_creation()
|
void test_creation()
|
||||||
{
|
{
|
||||||
test_value = 0;
|
test_value = 0;
|
||||||
boost::thread thrd(&simple_thread);
|
boost::thread thrd(&simple_thread);
|
||||||
@@ -49,31 +70,20 @@ void do_test_creation()
|
|||||||
BOOST_CHECK_EQUAL(test_value, 999);
|
BOOST_CHECK_EQUAL(test_value, 999);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_creation()
|
void test_comparison()
|
||||||
{
|
|
||||||
timed_test(&do_test_creation, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void do_test_comparison()
|
|
||||||
{
|
{
|
||||||
boost::thread self;
|
boost::thread self;
|
||||||
boost::thread thrd(bind(&comparison_thread, &self));
|
boost::thread thrd(thread_adapter(&comparison_thread, self));
|
||||||
thrd.join();
|
thrd.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_comparison()
|
boost::unit_test_framework::test_suite* thread_tests()
|
||||||
{
|
{
|
||||||
timed_test(&do_test_comparison, 1);
|
boost::unit_test_framework::test_suite* test = BOOST_TEST_SUITE("Boost.Threads: thread test suite");
|
||||||
}
|
|
||||||
|
|
||||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
test->add(BOOST_TEST_CASE(&test_sleep));
|
||||||
{
|
test->add(BOOST_TEST_CASE(&test_creation));
|
||||||
boost::unit_test_framework::test_suite* test =
|
test->add(BOOST_TEST_CASE(&test_comparison));
|
||||||
BOOST_TEST_SUITE("Boost.Threads: thread test suite");
|
|
||||||
|
|
||||||
test->add(BOOST_TEST_CASE(test_sleep));
|
|
||||||
test->add(BOOST_TEST_CASE(test_creation));
|
|
||||||
test->add(BOOST_TEST_CASE(test_comparison));
|
|
||||||
|
|
||||||
return test;
|
return test;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,11 @@
|
|||||||
// Copyright (C) 2001-2003
|
|
||||||
// William E. Kempf
|
|
||||||
//
|
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
|
||||||
// and its documentation for any purpose is hereby granted without fee,
|
|
||||||
// provided that the above copyright notice appear in all copies and
|
|
||||||
// that both that copyright notice and this permission notice appear
|
|
||||||
// in supporting documentation. William E. Kempf makes no representations
|
|
||||||
// about the suitability of this software for any purpose.
|
|
||||||
// It is provided "as is" without express or implied warranty.
|
|
||||||
|
|
||||||
#include <boost/thread/tss.hpp>
|
#include <boost/thread/tss.hpp>
|
||||||
#include <boost/thread/mutex.hpp>
|
#include <boost/thread/mutex.hpp>
|
||||||
#include <boost/thread/thread.hpp>
|
#include <boost/thread/thread.hpp>
|
||||||
|
|
||||||
#include <boost/test/unit_test.hpp>
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
#include "util.inl"
|
namespace
|
||||||
|
{
|
||||||
boost::mutex tss_mutex;
|
boost::mutex tss_mutex;
|
||||||
int tss_instances = 0;
|
int tss_instances = 0;
|
||||||
|
|
||||||
@@ -48,8 +37,9 @@ void test_tss_thread()
|
|||||||
++n;
|
++n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void do_test_tss()
|
void test_tss()
|
||||||
{
|
{
|
||||||
const int NUMTHREADS=5;
|
const int NUMTHREADS=5;
|
||||||
boost::thread_group threads;
|
boost::thread_group threads;
|
||||||
@@ -59,17 +49,11 @@ void do_test_tss()
|
|||||||
BOOST_CHECK_EQUAL(tss_instances, 0);
|
BOOST_CHECK_EQUAL(tss_instances, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_tss()
|
boost::unit_test_framework::test_suite* tss_tests()
|
||||||
{
|
{
|
||||||
timed_test(&do_test_tss, 2);
|
boost::unit_test_framework::test_suite* test = BOOST_TEST_SUITE("Boost.Threads: tss test suite");
|
||||||
}
|
|
||||||
|
|
||||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
test->add(BOOST_TEST_CASE(&test_tss));
|
||||||
{
|
|
||||||
boost::unit_test_framework::test_suite* test =
|
|
||||||
BOOST_TEST_SUITE("Boost.Threads: tss test suite");
|
|
||||||
|
|
||||||
test->add(BOOST_TEST_CASE(test_tss));
|
|
||||||
|
|
||||||
return test;
|
return test;
|
||||||
}
|
}
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
// Copyright (C) 2001-2003
|
|
||||||
// William E. Kempf
|
|
||||||
//
|
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
|
||||||
// and its documentation for any purpose is hereby granted without fee,
|
|
||||||
// provided that the above copyright notice appear in all copies and
|
|
||||||
// that both that copyright notice and this permission notice appear
|
|
||||||
// in supporting documentation. William E. Kempf makes no representations
|
|
||||||
// about the suitability of this software for any purpose.
|
|
||||||
// It is provided "as is" without express or implied warranty.
|
|
||||||
|
|
||||||
#include <boost/thread/xtime.hpp>
|
|
||||||
|
|
||||||
#include <boost/test/unit_test.hpp>
|
|
||||||
|
|
||||||
void test_xtime_cmp()
|
|
||||||
{
|
|
||||||
boost::xtime xt1, xt2, cur;
|
|
||||||
BOOST_CHECK_EQUAL(
|
|
||||||
boost::xtime_get(&cur, boost::TIME_UTC),
|
|
||||||
static_cast<int>(boost::TIME_UTC));
|
|
||||||
|
|
||||||
xt1 = xt2 = cur;
|
|
||||||
xt1.nsec -= 1;
|
|
||||||
xt2.nsec += 1;
|
|
||||||
|
|
||||||
BOOST_CHECK(boost::xtime_cmp(xt1, cur) < 0);
|
|
||||||
BOOST_CHECK(boost::xtime_cmp(xt2, cur) > 0);
|
|
||||||
BOOST_CHECK(boost::xtime_cmp(cur, cur) == 0);
|
|
||||||
|
|
||||||
xt1 = xt2 = cur;
|
|
||||||
xt1.sec -= 1;
|
|
||||||
xt2.sec += 1;
|
|
||||||
|
|
||||||
BOOST_CHECK(boost::xtime_cmp(xt1, cur) < 0);
|
|
||||||
BOOST_CHECK(boost::xtime_cmp(xt2, cur) > 0);
|
|
||||||
BOOST_CHECK(boost::xtime_cmp(cur, cur) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_xtime_get()
|
|
||||||
{
|
|
||||||
boost::xtime orig, cur, old;
|
|
||||||
BOOST_CHECK_EQUAL(
|
|
||||||
boost::xtime_get(&orig,
|
|
||||||
boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
|
|
||||||
old = orig;
|
|
||||||
|
|
||||||
for (int x=0; x < 100; ++x)
|
|
||||||
{
|
|
||||||
BOOST_CHECK_EQUAL(
|
|
||||||
boost::xtime_get(&cur, boost::TIME_UTC),
|
|
||||||
static_cast<int>(boost::TIME_UTC));
|
|
||||||
BOOST_CHECK(boost::xtime_cmp(cur, orig) >= 0);
|
|
||||||
BOOST_CHECK(boost::xtime_cmp(cur, old) >= 0);
|
|
||||||
old = cur;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
|
||||||
{
|
|
||||||
boost::unit_test_framework::test_suite* test =
|
|
||||||
BOOST_TEST_SUITE("Boost.Threads: xtime test suite");
|
|
||||||
|
|
||||||
test->add(BOOST_TEST_CASE(&test_xtime_cmp));
|
|
||||||
test->add(BOOST_TEST_CASE(&test_xtime_get));
|
|
||||||
|
|
||||||
return test;
|
|
||||||
}
|
|
||||||
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,49 +0,0 @@
|
|||||||
# (C) Copyright William E. Kempf 2001. Permission to copy, use, modify, sell
|
|
||||||
# and distribute this software is granted provided this copyright notice
|
|
||||||
# appears in all copies. This software is provided "as is" without express or
|
|
||||||
# implied warranty, and with no claim as to its suitability for any purpose.
|
|
||||||
#
|
|
||||||
# Boost.Threads example Jamfile
|
|
||||||
#
|
|
||||||
# Additional configuration variables used:
|
|
||||||
# 1. PTW32 may be used on Win32 platforms to specify that the pthreads-win32
|
|
||||||
# library should be used instead of "native" threads. This feature is
|
|
||||||
# mostly used for testing and it's generally recommended you use the
|
|
||||||
# native threading libraries instead. PTW32 should be set to be a list
|
|
||||||
# of two strings, the first specifying the installation path of the
|
|
||||||
# pthreads-win32 library and the second specifying which library
|
|
||||||
# variant to link against (see the pthreads-win32 documentation).
|
|
||||||
# Example: jam -sPTW32="c:\pthreads-win32 pthreadVCE.lib"
|
|
||||||
|
|
||||||
# Declare the location of this subproject relative to the root.
|
|
||||||
|
|
||||||
subproject libs/thread/tutorial ;
|
|
||||||
|
|
||||||
# Include threads.jam for Boost.Threads global build information.
|
|
||||||
# This greatly simplifies the Jam code needed to configure the build
|
|
||||||
# for the various Win32 build types.
|
|
||||||
SEARCH on <module@>threads.jam = $(BOOST_ROOT)/libs/thread/build ;
|
|
||||||
include <module@>threads.jam ;
|
|
||||||
|
|
||||||
{
|
|
||||||
template tutorial
|
|
||||||
## sources ##
|
|
||||||
: <template>thread_base
|
|
||||||
<dll>../build/boost_thread
|
|
||||||
## requirements ##
|
|
||||||
:
|
|
||||||
## default build ##
|
|
||||||
:
|
|
||||||
;
|
|
||||||
|
|
||||||
exe helloworld : <template>tutorial helloworld.cpp ;
|
|
||||||
exe helloworld2 : <template>tutorial helloworld2.cpp ;
|
|
||||||
exe helloworld3 : <template>tutorial helloworld3.cpp ;
|
|
||||||
exe helloworld4 : <template>tutorial helloworld4.cpp ;
|
|
||||||
exe factorial : <template>tutorial factorial.cpp ;
|
|
||||||
exe factorial2 : <template>tutorial factorial2.cpp ;
|
|
||||||
exe factorial3 : <template>tutorial factorial3.cpp ;
|
|
||||||
exe counter : <template>tutorial counter.cpp ;
|
|
||||||
exe bounded_buffer : <template>tutorial bounded_buffer.cpp ;
|
|
||||||
exe once : <template>tutorial once.cpp ;
|
|
||||||
}
|
|
||||||
@@ -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,37 +0,0 @@
|
|||||||
// Copyright (C) 2001-2003
|
|
||||||
// William E. Kempf
|
|
||||||
//
|
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
|
||||||
// and its documentation for any purpose is hereby granted without fee,
|
|
||||||
// provided that the above copyright notice appear in all copies and
|
|
||||||
// that both that copyright notice and this permission notice appear
|
|
||||||
// in supporting documentation. William E. Kempf makes no representations
|
|
||||||
// about the suitability of this software for any purpose.
|
|
||||||
// It is provided "as is" without express or implied warranty.
|
|
||||||
|
|
||||||
#include <boost/thread/thread.hpp>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
class factorial
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
factorial(int x, int& res) : x(x), res(res) { }
|
|
||||||
void operator()() { res = calculate(x); }
|
|
||||||
int result() const { return res; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
int calculate(int x) { return x <= 1 ? 1 : x * calculate(x-1); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
int x;
|
|
||||||
int& res;
|
|
||||||
};
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
factorial f(10, result);
|
|
||||||
boost::thread thrd(f);
|
|
||||||
thrd.join();
|
|
||||||
std::cout << "10! = " << result << std::endl;
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
// Copyright (C) 2001-2003
|
|
||||||
// William E. Kempf
|
|
||||||
//
|
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
|
||||||
// and its documentation for any purpose is hereby granted without fee,
|
|
||||||
// provided that the above copyright notice appear in all copies and
|
|
||||||
// that both that copyright notice and this permission notice appear
|
|
||||||
// in supporting documentation. William E. Kempf makes no representations
|
|
||||||
// about the suitability of this software for any purpose.
|
|
||||||
// It is provided "as is" without express or implied warranty.
|
|
||||||
|
|
||||||
#include <boost/thread/thread.hpp>
|
|
||||||
#include <boost/ref.hpp>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
class factorial
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
factorial(int x) : x(x), res(0) { }
|
|
||||||
void operator()() { res = calculate(x); }
|
|
||||||
int result() const { return res; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
int calculate(int x) { return x <= 1 ? 1 : x * calculate(x-1); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
int x;
|
|
||||||
int res;
|
|
||||||
};
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
factorial f(10);
|
|
||||||
boost::thread thrd(boost::ref(f));
|
|
||||||
thrd.join();
|
|
||||||
std::cout << "10! = " << f.result() << std::endl;
|
|
||||||
}
|
|
||||||
@@ -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,24 +0,0 @@
|
|||||||
// Copyright (C) 2001-2003
|
|
||||||
// William E. Kempf
|
|
||||||
//
|
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
|
||||||
// and its documentation for any purpose is hereby granted without fee,
|
|
||||||
// provided that the above copyright notice appear in all copies and
|
|
||||||
// that both that copyright notice and this permission notice appear
|
|
||||||
// in supporting documentation. William E. Kempf makes no representations
|
|
||||||
// about the suitability of this software for any purpose.
|
|
||||||
// It is provided "as is" without express or implied warranty.
|
|
||||||
|
|
||||||
#include <boost/thread/thread.hpp>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
void helloworld()
|
|
||||||
{
|
|
||||||
std::cout << "Hello World!" << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
boost::thread thrd(&helloworld);
|
|
||||||
thrd.join();
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
// Copyright (C) 2001-2003
|
|
||||||
// William E. Kempf
|
|
||||||
//
|
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
|
||||||
// and its documentation for any purpose is hereby granted without fee,
|
|
||||||
// provided that the above copyright notice appear in all copies and
|
|
||||||
// that both that copyright notice and this permission notice appear
|
|
||||||
// in supporting documentation. William E. Kempf makes no representations
|
|
||||||
// about the suitability of this software for any purpose.
|
|
||||||
// It is provided "as is" without express or implied warranty.
|
|
||||||
|
|
||||||
#include <boost/thread/thread.hpp>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
struct helloworld
|
|
||||||
{
|
|
||||||
helloworld() { }
|
|
||||||
void operator()() { std::cout << "Hello World." << std::endl; }
|
|
||||||
};
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
boost::thread thrd(helloworld());
|
|
||||||
thrd.join();
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
// Copyright (C) 2001-2003
|
|
||||||
// William E. Kempf
|
|
||||||
//
|
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
|
||||||
// and its documentation for any purpose is hereby granted without fee,
|
|
||||||
// provided that the above copyright notice appear in all copies and
|
|
||||||
// that both that copyright notice and this permission notice appear
|
|
||||||
// in supporting documentation. William E. Kempf makes no representations
|
|
||||||
// about the suitability of this software for any purpose.
|
|
||||||
// It is provided "as is" without express or implied warranty.
|
|
||||||
|
|
||||||
#include <boost/thread/thread.hpp>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
struct helloworld
|
|
||||||
{
|
|
||||||
helloworld(const char* who) : m_who(who) { }
|
|
||||||
void operator()() { std::cout << m_who << "says, \"Hello World.\"" << std::endl; }
|
|
||||||
const char* m_who;
|
|
||||||
};
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
boost::thread thrd(helloworld("Bob"));
|
|
||||||
thrd.join();
|
|
||||||
}
|
|
||||||
@@ -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