2
0
mirror of https://github.com/boostorg/thread.git synced 2026-02-03 09:42:16 +00:00

Compare commits

..

66 Commits

Author SHA1 Message Date
William E. Kempf
9b8c62d45a Merged from RC_1_29_0
[SVN r16126]
2002-11-05 22:43:42 +00:00
nobody
7d438e9f25 This commit was manufactured by cvs2svn to create branch
'thread_development'.

[SVN r16006]
2002-10-28 14:10:15 +00:00
William E. Kempf
3699cc97a6 Added new tutorial files
[SVN r16005]
2002-10-28 14:10:14 +00:00
Vladimir Prus
5a7377acda Made Boost.Thread compile with V2.
[SVN r15969]
2002-10-23 13:22:56 +00:00
Beman Dawes
6aaee629b5 Fix acknowledgements and copyright
[SVN r15759]
2002-10-07 00:07:46 +00:00
Björn Karlsson
b465fe569c Merged from branch to trunk
[SVN r15613]
2002-10-01 15:00:37 +00:00
Björn Karlsson
5e6f72a688 Merged from branch to trunk
[SVN r15524]
2002-09-26 09:17:19 +00:00
William E. Kempf
51f80f6c15 Removed incorrect usages of typename
[SVN r15185]
2002-09-06 19:49:10 +00:00
William E. Kempf
45c314e594 Changed tabs to spaces.
[SVN r15180]
2002-09-06 15:35:39 +00:00
William E. Kempf
cfce0892e0 Added tutorial sources. Changed tabs to spaces.
[SVN r15179]
2002-09-06 15:34:48 +00:00
William E. Kempf
05d1abf030 Added build documentation. Changed tabs to spaces.
[SVN r15178]
2002-09-06 15:33:54 +00:00
Dave Abrahams
6c24a2626b Fix stupid mistake
[SVN r15058]
2002-08-22 16:13:59 +00:00
Dave Abrahams
870c75bd12 Stop using unit-test since it has problems with JAMSHELL setting with gcc
[SVN r15033]
2002-08-21 15:29:18 +00:00
William E. Kempf
5fdd771708 Fixed some bugs and warnings produced by borland and gcc
[SVN r14944]
2002-08-17 16:34:23 +00:00
William E. Kempf
06f39ac409 Changed examples in documents to links to actual code
[SVN r14939]
2002-08-16 21:43:31 +00:00
William E. Kempf
c92b0a2fb7 An attempt to make InterlockedCompareExchange more portable
[SVN r14938]
2002-08-16 21:19:48 +00:00
William E. Kempf
8a8d0e05ca Added pre-Win64 support for InterlockedCompareExchange
[SVN r14937]
2002-08-16 20:16:03 +00:00
William E. Kempf
74bae2baac Added library-root level index.html for Boost.Threads
[SVN r14914]
2002-08-15 23:37:20 +00:00
William E. Kempf
4ba48676bd Fixed some warnings produced by Borland in the regression test
[SVN r14875]
2002-08-15 03:39:24 +00:00
William E. Kempf
78480e7951 Removed subdirectories
[SVN r14870]
2002-08-15 01:39:07 +00:00
William E. Kempf
4cb9c412e8 Added examples from documentation
[SVN r14869]
2002-08-15 01:22:29 +00:00
William E. Kempf
75c83fed96 Fixed time precision bugs. Switched to Interlocked* methods for once.
[SVN r14867]
2002-08-15 00:05:54 +00:00
William E. Kempf
391de20ae0 Added test_xtime.cpp
[SVN r14852]
2002-08-14 20:39:32 +00:00
William E. Kempf
1e2a9e8971 Fixed Jamfile issues with tests
[SVN r14818]
2002-08-13 19:19:09 +00:00
William E. Kempf
43cbd3a283 Split up tests into seperate files and switched fully to unit test framework
[SVN r14780]
2002-08-12 05:43:10 +00:00
William E. Kempf
31cf6b5e64 Initial switch to Boost.Test unit test framework
[SVN r14779]
2002-08-12 00:09:33 +00:00
John D. Moore
d525388fb2 Simple tests for shared memory objects. Need multiple process tests as well.
[SVN r14428]
2002-07-12 19:33:02 +00:00
John D. Moore
1029d0d2bb Implementations for win32 + POSIX. Win32 tested.
[SVN r14427]
2002-07-12 19:30:30 +00:00
John D. Moore
00038f78e5 Moved to lower level class
[SVN r14426]
2002-07-12 19:25:32 +00:00
William E. Kempf
2dc67ea9ad Removed lock from get/set in TSS.
[SVN r14356]
2002-07-08 21:08:51 +00:00
William E. Kempf
602faacb35 Changes to tss for proper ordering of destructors
[SVN r14354]
2002-07-08 17:37:39 +00:00
William E. Kempf
0f078f33cb POSIX bug fixes.
[SVN r14316]
2002-07-05 17:52:56 +00:00
William E. Kempf
cf77472dfe POSIX bug fixes.
[SVN r14315]
2002-07-05 17:50:20 +00:00
William E. Kempf
8cc40e5e07 POSIX bug fixes.
[SVN r14314]
2002-07-05 17:45:13 +00:00
William E. Kempf
28d675b4c9 POSIX bug fixes.
[SVN r14313]
2002-07-05 17:38:43 +00:00
William E. Kempf
27b2b14c17 Added generation tracking to tss.
[SVN r14312]
2002-07-05 17:30:36 +00:00
William E. Kempf
cc5dd8a978 Fixed order of thread exit routines.
[SVN r14294]
2002-07-03 18:06:30 +00:00
William E. Kempf
81ee94ce3c Modified TSS to use defined destruction ordering.
[SVN r14291]
2002-07-03 15:54:10 +00:00
William E. Kempf
184e604287 'Fixed' tss bug.
[SVN r14252]
2002-06-27 22:18:05 +00:00
William E. Kempf
50dccc1f66 Removed CS and most 'process_detach' stuff from threadmon
[SVN r14250]
2002-06-27 19:40:41 +00:00
John D. Moore
30b766a02e Initial version for discussion
[SVN r14236]
2002-06-25 12:35:44 +00:00
William E. Kempf
48e8588af0 First go at refactoring tss and next version of thread class.
[SVN r14221]
2002-06-21 18:33:59 +00:00
Dave Abrahams
99109ab78b respect <sysinclude>
[SVN r13995]
2002-05-21 16:24:07 +00:00
William E. Kempf
a40b3657f6 Fixed pthread_detach bug
[SVN r13989]
2002-05-20 16:33:01 +00:00
William E. Kempf
1000f77180 Refactored thread
[SVN r13988]
2002-05-20 16:26:57 +00:00
William E. Kempf
518c5c8215 Added thread_group tests
[SVN r13952]
2002-05-16 14:34:03 +00:00
William E. Kempf
d30279342a Flushed output
[SVN r13943]
2002-05-15 22:40:00 +00:00
William E. Kempf
4c9ca0edae Fixed member initialization order warnings
[SVN r13942]
2002-05-15 22:36:35 +00:00
William E. Kempf
c163f90071 Added missing typename keywords
[SVN r13941]
2002-05-15 22:34:16 +00:00
William E. Kempf
1404d8558b Removed id parameters from thread_pool tests
[SVN r13940]
2002-05-15 22:32:38 +00:00
William E. Kempf
c8762d5c91 Removed id parameters from thread_pool tests
[SVN r13939]
2002-05-15 22:27:48 +00:00
William E. Kempf
11d3f9feb4 Changed <limits> to <boost/limits.hpp>
[SVN r13938]
2002-05-15 22:16:30 +00:00
William E. Kempf
3130149dfd Fixed bugs in rw_mutex.cpp caused by missing typename keywords
[SVN r13937]
2002-05-15 22:13:20 +00:00
William E. Kempf
4808ccb316 Refactoring tests
[SVN r13936]
2002-05-15 22:01:36 +00:00
William E. Kempf
7ae3687ed8 Bug fixes for rw_mutex and refactoring of tests
[SVN r13925]
2002-05-15 17:46:53 +00:00
William E. Kempf
bb5f17bf04 Bug fixes for rw_mutex and refactoring of tests
[SVN r13924]
2002-05-15 17:43:01 +00:00
William E. Kempf
a32df1aad9 Merged trunk changes
[SVN r13911]
2002-05-15 15:27:18 +00:00
William E. Kempf
da86b991e5 Updated thread_pool.html
[SVN r13907]
2002-05-15 14:54:18 +00:00
William E. Kempf
a80d5f159d Merged from RC_1_28_0 branch
[SVN r13905]
2002-05-15 14:35:39 +00:00
William E. Kempf
d12508b97f Refactored thread_pool implementation
[SVN r13627]
2002-05-02 21:42:22 +00:00
William E. Kempf
98af8c50c4 Updated documentation for barrier
[SVN r13598]
2002-04-30 21:46:53 +00:00
William E. Kempf
7bb5c1b4e2 Modified barrier implementation
[SVN r13597]
2002-04-30 21:27:21 +00:00
William E. Kempf
07ecf15f4c Added rw_mutex
[SVN r13593]
2002-04-30 19:10:14 +00:00
William E. Kempf
d5006255fd Added barrier.
[SVN r13581]
2002-04-29 16:19:27 +00:00
William E. Kempf
d7d8b4cedd Added thread_pool.
[SVN r13580]
2002-04-29 12:53:02 +00:00
nobody
c9f3478a21 This commit was manufactured by cvs2svn to create branch
'thread_development'.

[SVN r13571]
2002-04-26 21:15:41 +00:00
87 changed files with 8214 additions and 2408 deletions

View File

@@ -31,17 +31,21 @@ subproject libs/thread/build ;
SEARCH on <module@>threads.jam = $(SUBDIR) ;
include <module@>threads.jam ;
template thread_libs
## sources ##
: <template>thread_base
## requirements ##
:
## default build ##
: debug release <runtime-link>static/dynamic
;
#######################
# Conditionally declare the Boost.Threads dynamic link library boost_threadmon.
if $(NT) && ! $(PTW32)
{
dll boost_threadmon
: ../src/threadmon.cpp
: <include>$(BOOST_ROOT)
<threading>multi
: debug release <runtime-link>static/dynamic
;
dll boost_threadmon : <template>thread_libs ../src/threadmon.cpp ;
}
#######################
@@ -49,15 +53,9 @@ if $(NT) && ! $(PTW32)
# Base names of the source files for libboost_thread.
CPP_SOURCES =
condition mutex recursive_mutex thread tss xtime once exceptions ;
condition mutex recursive_mutex thread tss xtime once exceptions thread_pool barrier rw_mutex ;
lib boost_thread
: ../src/$(CPP_SOURCES).cpp
: <include>$(BOOST_ROOT)
<threading>multi
$(pthreads-win32)
: debug release <runtime-link>static/dynamic
;
lib boost_thread : <template>thread_libs ../src/$(CPP_SOURCES).cpp ;
#######################
# Stage the generated targets.

View File

@@ -9,15 +9,24 @@ if $(NT)
{
local install-path = $(PTW32[1]) ;
local lib = $(PTW32[2]) ;
pthreads-win32 =
<define>BOOST_HAS_PTHREADS
pthreads-win32 =
<define>BOOST_HAS_PTHREADS
<define>PtW32NoCatchWarn
<include>$(install-path)/pre-built/include
<library-file>$(install-path)/pre-built/lib/$(lib)
;
;
}
else
{
threadmon = <dll>../build/boost_threadmon ;
}
}
template thread_base
## sources ##
:
## requirements ##
: <sysinclude>$(BOOST_ROOT) <threading>multi $(pthreads-win32)
## default build ##
:
;

Binary file not shown.

View File

@@ -7,21 +7,25 @@
<body link="#0000ff" vlink="#800080">
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
"header">
<tr>
<td valign="top" width="300">
<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">
<td valign="top">
<h1 align="center">Boost.Threads</h1>
<h2 align="center">Acknowledgments</h2>
</td>
</tr>
</table>
<hr>
<p><a href="../../../people/william_kempf.htm">William E. Kempf</a> was the architect,
<p><a href="../../../people/william_kempf.htm">William E. Kempf</a> was the architect,
designer, and implementor of <b>Boost.Threads</b>.</p>
<p>Mac OS Carbon implementation written by <a href="../../../people/mac_murrett.htm">Mac
<p>Mac OS Carbon implementation written by <a href="../../../people/mac_murrett.htm">Mac
Murrett</a>.</p>
<p><a href="mailto:jdmoore99@comcast.net">Dave Moore</a> provided initial submissions
and further comments on the <code>barrier</code>, <code>thread_pool</code>,
<code>rw_mutex</code>, <code>rw_try_mutex</code> and <code>rw_timed_mutex</code>
classes.</p>
<p>Important contributions were also made by Jeremy Siek (lots of input on the
design and on the implementation), Alexander Terekhov (lots of input on the
Win32 implementation, especially in regards to boost::condition, as well as
@@ -29,41 +33,41 @@
Paul Mclachlan, Thomas Matelich and Iain Hanson (for help in trying to get the
build to work on other platforms), and Kevin S. Van Horn (for several updates/corrections
to the documentation).</p>
<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>
<p>Discussions on the boost.org mailing list were essential in the development
of <b>Boost.Threads</b>. As of August 1, 2001, participants included Alan Griffiths,
Albrecht Fritzsche, Aleksey Gurtovoy, Alexander Terekhov, Andrew Green, Andy
Sawyer, Asger Alstrup Nielsen, Beman Dawes, Bill Klein, Bill Rutiser, Bill Wade,
Branko &Egrave;ibej, Brent Verner, Craig Henderson, Csaba Szepesvari, Dale Peakall,
Damian Dixon, Dan Nuffer, Darryl Green, Daryle Walker, David Abrahams, David
Allan Finch, Dejan Jelovic, Dietmar Kuehl, Doug Gregor, Douglas Gregor, Duncan
Harris, Ed Brey, Eric Swanson, Eugene Karpachov, Fabrice Truillot, Frank Gerlach,
Gary Powell, Gernot Neppert, Geurt Vos, Ghazi Ramadan, Greg Colvin, Gregory
Seidman, HYS, Iain Hanson, Ian Bruntlett, J Panzer, Jeff Garland, Jeff Paquette,
Jens Maurer, Jeremy Siek, Jesse Jones, Joe Gottman, John (EBo) David, John Bandela,
John Maddock, John Max Skaller, John Panzer, Jon Jagger , Karl Nelson, Kevlin
Henney, KG Chandrasekhar, Levente Farkas, Lie-Quan Lee, Lois Goldthwaite, Luis
Pedro Coelho, Marc Girod, Mark A. Borgerding, Mark Rodgers, Marshall Clow, Matthew
Austern, Matthew Hurd, Michael D. Crawford, Michael H. Cox , Mike Haller, Miki
Jovanovic, Nathan Myers, Paul Moore, Pavel Cisler, Peter Dimov, Petr Kocmid,
Philip Nash, Rainer Deyke, Reid Sweatman, Ross Smith, Scott McCaskill, Shalom
Reich , Steve Cleary, Steven Kirk, Thomas Holenstein, Thomas Matelich, Trevor
<p>Discussions on the boost.org mailing list were essential in the development
of <b>Boost.Threads</b>. As of August 1, 2001, participants included Alan Griffiths,
Albrecht Fritzsche, Aleksey Gurtovoy, Alexander Terekhov, Andrew Green, Andy
Sawyer, Asger Alstrup Nielsen, Beman Dawes, Bill Klein, Bill Rutiser, Bill Wade,
Branko &Egrave;ibej, Brent Verner, Craig Henderson, Csaba Szepesvari, Dale Peakall,
Damian Dixon, Dan Nuffer, Darryl Green, Daryle Walker, David Abrahams, David
Allan Finch, Dejan Jelovic, Dietmar Kuehl, Doug Gregor, Douglas Gregor, Duncan
Harris, Ed Brey, Eric Swanson, Eugene Karpachov, Fabrice Truillot, Frank Gerlach,
Gary Powell, Gernot Neppert, Geurt Vos, Ghazi Ramadan, Greg Colvin, Gregory
Seidman, HYS, Iain Hanson, Ian Bruntlett, J Panzer, Jeff Garland, Jeff Paquette,
Jens Maurer, Jeremy Siek, Jesse Jones, Joe Gottman, John (EBo) David, John Bandela,
John Maddock, John Max Skaller, John Panzer, Jon Jagger , Karl Nelson, Kevlin
Henney, KG Chandrasekhar, Levente Farkas, Lie-Quan Lee, Lois Goldthwaite, Luis
Pedro Coelho, Marc Girod, Mark A. Borgerding, Mark Rodgers, Marshall Clow, Matthew
Austern, Matthew Hurd, Michael D. Crawford, Michael H. Cox , Mike Haller, Miki
Jovanovic, Nathan Myers, Paul Moore, Pavel Cisler, Peter Dimov, Petr Kocmid,
Philip Nash, Rainer Deyke, Reid Sweatman, Ross Smith, Scott McCaskill, Shalom
Reich , Steve Cleary, Steven Kirk, Thomas Holenstein, Thomas Matelich, Trevor
Perrin, Valentin Bonnard, Vesa Karvonen, Wayne Miller, and William Kempf.</p>
<p>Apologies for anyone inadvertently missed.</p>
<hr>
<p>Revised
<p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
05 November, 2001
05 November, 2001
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p>
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
All Rights Reserved.</i></p>
<p>Permission to use, copy, modify, distribute and sell this software and its
documentation for any purpose is hereby granted without fee, provided that the
above copyright notice appear in all copies and that both that copyright notice
and this permission notice appear in supporting documentation. William E. Kempf
makes no representations about the suitability of this software for any purpose.
<p>Permission to use, copy, modify, distribute and sell this software and its
documentation for any purpose is hereby granted without fee, provided that the
above copyright notice appear in all copies and that both that copyright notice
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 &quot;as is&quot; without express or implied warranty.</p>
</body>
</html>

168
doc/barrier.html Normal file
View File

@@ -0,0 +1,168 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<link rel="stylesheet" type="text/css" href="../../../boost.css">
<title>Boost.Threads - Header &lt;boost/thread/barrier.hpp&gt;</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">Header &lt;<a href="../../../boost/thread/barrier.hpp">boost/thread/barrier.hpp</a>&gt;</h2>
</td>
</tr>
</table>
<hr>
<h2>Contents</h2>
<dl class="page-index">
<dt><a href="#introduction">Introduction</a></dt>
<dt><a href="#classes">Classes</a></dt>
<dl class="page-index">
<dt><a href="#class-barrier">Class <code>barrier</code></a></dt>
<dl class="page-index">
<dt><a href="#class-barrier-synopsis">Class <code>barrier</code> synopsis</a></dt>
<dt><a href="#class-barrier-ctors">Class <code>barrier</code> constructors
and destructor</a></dt>
<dt><a href="#class-barrier-modifiers">Class <code>barrier</code> modifier
functions</a></dt>
</dl>
</dl>
<dt><a href="#examples">Example(s)</a></dt>
</dl>
<hr>
<h2><a name="introduction"></a>Introduction</h2>
<p>Include the header &lt;<a href="../../../boost/thread/barrier.hpp">boost/thread/barrier.hpp</a>&gt;
to define the class <code>boost::barrier</code>.</p>
<h2><a name="classes"></a>Classes</h2>
<h3><a name="class-barrier"></a>Class <code>barrier</code></h3>
<p>An object of class <code>barrier</code> is a synchronization primitive used
to cause a set of threads to wait until they each perform a certain function
or each reach a particular point in their execution. When a barrier is created,
it is initialized with a thread count "N". The first N-1 calls to wait() will
all cause their threads to be blocked. The Nth call to wait() will allow all
of the waiting threads, including the Nth thread, to be placed in a ready state.
Should an additional thread make an N+1th call to wait() on the barrier, it
will be as though this was the first call to wait(), and the process will be
repeated until another N threads call wait(). This functionality allows the
same set of N threads to re-use a barrier object to synchronize their execution
at multiple points during their execution.</p>
<p>See <A href="definitions.html">Formal Definitions</A> for definitions of thread
states <A href="definitions.html#state">blocked</A> and <A href="definitions.html#state">
ready</A>. Note that "waiting" is a synonym for blocked.</p>
<h4><a name="class-barrier-synopsis"></a>Class <code>barrier</code> synopsis</h4>
<pre>
namespace boost
{
class barrier : private <A href="../../utility/utility.htm#Class noncopyable">boost::noncopyable</A> // Exposition only.
// Class barrier meets the <A href="overview.html#NonCopyable" .. utility.htm#Class? utility>NonCopyable</A> requirement.
{
public:
barrier(size_t count);
~barrier();
bool wait();
};
};
</pre>
<h4><a name="class-barrier-ctors"></a>Class <code>barrier</code> constructors
and destructor</h4>
<pre>
barrier(size_t count);
</pre>
<dl class="function-semantics">
<dt><b>Effects:</b> Constructs a <code>barrier</code> object that will cause
count threads to block on a call to <code>wait()</code>.</dt>
</dl>
<pre>
~barrier();
</pre>
<dl class="function-semantics">
<dt><b>Effects:</b> Destroys <code>*this</code>. If threads are still executing
their <code>wait()</code> operations, the behavior for these threads is undefined.</dt>
</dl>
<h4><a name="class-barrier-modifiers"></a>Class <code>barrier</code> modifier
functions</h4>
<pre>
bool wait();
</pre>
<dl class="function-semantics">
<dt><b>Effects:</b> Wait until N threads call wait(), where N equals the count
provided to the constructor for the barrier object.</dt>
<dt><b>Returns:</b> Exactly one of the N threads will receive a return value
of <code>true</code>, the others will receive a value of <code>false</code>.
Precisely which thread receives the return value of <code>true</code> will
be implementation defined. Applications can use this value to designate one
thread as a leader that will take a certain action, and the other threads
emerging from the barrier can wait for that action to take place.</dt>
<dt><b>Danger:</b> If the barrier is destroyed before <code>wait()</code> can
return, the behavior is undefined.</dt>
</dl>
<h2><a name="examples"></a>Example(s)</h2>
<pre>
#include <a href="../../../boost/thread/condition.hpp">&lt;boost/thread/barrier.hpp&gt;</a>
#include <a href="../../../boost/thread/thread.hpp">&lt;boost/thread/thread.hpp&gt;</a>
#include <a href="../../../boost/thread/mutex.hpp">&lt;boost/thread/mutex.hpp&gt;</a>
#include &lt;iostream&gt;
const int N_THREADS = 10;
boost::barrier gen_barrier(N_THREADS);
int global_parameter = 0;
boost::mutex mutex;
static void worker()
{
for (int i = 0; i &lt; 5; ++i)
{
// Simulate 5 cycles of computation...
if (gen_barrier.wait())
{
boost::mutex::scoped_lock lock(mutex);
global_parameter++;
}
}
// Let one worker "report" the results
if (gen_barrier.wait())
{
boost::mutex::scoped_lock lock(lock);
std::cout &lt;&lt; "Global Parameter=" &lt;&lt; global_parameter &lt;&lt; "\n";
}
}
int main(int, char*[])
{
boost::thread_group g;
global_parameter = 0;
for (int i = 0; i &lt; N_THREADS; ++i)
g.create_thread(&amp;worker);
g.join_all();
}
</pre>
<p>The output is:</p>
<pre>
Global Parameter=5
</pre>
<hr>
<p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
05 November, 2001
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p>
<p><i>&copy; Copyright <a href="mailto:jdmoore99@comcast.net">Dave Moore</a> and <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
All Rights Reserved.</i></p>
<p>Permission to use, copy, modify, distribute and sell this software and its
documentation for any purpose is hereby granted without fee, provided that the
above copyright notice appear in all copies and that both that copyright notice
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 &quot;as is&quot; without express or implied warranty.</p>
</body>
</html>

View File

@@ -7,11 +7,11 @@
<body link="#0000ff" vlink="#800080">
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
"header">
<tr>
<td valign="top" width="300">
<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">
<td valign="top">
<h1 align="center">Boost.Threads</h1>
<h2 align="center">Bibliography</h2>
</td>
@@ -19,147 +19,147 @@
</table>
<hr>
<table summary="Bibliography" border="0" cellpadding="5" width="777">
<tr>
<tr>
<td width="102" valign="top" align="left"><b>[<a name=
"Andrews-83">Andrews 83</a>]</b></td>
<td width="645"> Gregory R. Andrews, Fred B. Schneider, <cite>Concepts and
Notations for Concurrent Programming</cite>, ACM Computing Surveys, Vol.
<td width="645"> Gregory R. Andrews, Fred B. Schneider, <cite>Concepts and
Notations for Concurrent Programming</cite>, ACM Computing Surveys, Vol.
15, No. 1, March, 1983. <a href=
"http://www.acm.org/pubs/citations/journals/surveys/1983-15-1/p3-andrews/">
http://www.acm.org/pubs/citations/journals/surveys/1983-15-1/p3-andrews/</a>
<p>Good general background reading. Includes descriptions of Path Expressions,
"http://www.acm.org/pubs/citations/journals/surveys/1983-15-1/p3-andrews/">
http://www.acm.org/pubs/citations/journals/surveys/1983-15-1/p3-andrews/</a>
<p>Good general background reading. Includes descriptions of Path Expressions,
Message Passing, and Remote Procedure Call in addition to the basics.</p>
</td>
</tr>
<tr>
<tr>
<td width="102" valign="top" align="left"><b>[<a name=
"Boost">Boost</a>]</b></td>
<td width="645"> The <cite>Boost</cite> worldwide web site. <a href=
"http://www.boost.org">http://www.boost.org</a>
<p>Boost.Threads is one of many Boost libraries. The Boost web site includes
a great deal of documentation and general information which applies to
all Boost libraries. Current copies of the libraries including documentation
"http://www.boost.org">http://www.boost.org</a>
<p>Boost.Threads is one of many Boost libraries. The Boost web site includes
a great deal of documentation and general information which applies to
all Boost libraries. Current copies of the libraries including documentation
and test programs may be downloaded from the web site.</p>
</td>
</tr>
<tr>
<tr>
<td width="102" valign="top" align="left"><b>[<a name=
"Brinch-Hansen-73">Brinch Hansen 73</a>]</b></td>
<td width="645"> Per Brinch Hansen, <cite>Concurrent Programming Concepts</cite>,
<td width="645"> Per Brinch Hansen, <cite>Concurrent Programming Concepts</cite>,
ACM Computing Surveys, Vol. 5, No. 4, December, 1973. <a href=
"http://www.acm.org/pubs/articles/journals/surveys/1973-5-4/p223-hansen/p223-hansen.pdf">
http://www.acm.org/pubs/articles/journals/surveys/1973-5-4/p223-hansen/</a>
<p>&quot;This paper describes the evolution of language features for multiprogramming
from event queues and semaphores to critical regions and monitors.&quot;
Includes analysis of why <i>events</i> are considered error-prone. Also
noteworthy because of an introductory quotation from Christopher Alexander;
Brinch Hansen was years ahead of others in recognizing pattern concepts
"http://www.acm.org/pubs/articles/journals/surveys/1973-5-4/p223-hansen/p223-hansen.pdf">
http://www.acm.org/pubs/articles/journals/surveys/1973-5-4/p223-hansen/</a>
<p>&quot;This paper describes the evolution of language features for multiprogramming
from event queues and semaphores to critical regions and monitors.&quot;
Includes analysis of why <i>events</i> are considered error-prone. Also
noteworthy because of an introductory quotation from Christopher Alexander;
Brinch Hansen was years ahead of others in recognizing pattern concepts
applied to software too.</p>
</td>
</tr>
<tr>
<tr>
<td width="102" valign="top" align="left"><b>]<a name=
"Butenhof-97">Butenhof 97</a>]</b></td>
<td width="645">
<p>David R. Butenhof, <cite>Programming with POSIX Threads</cite>, Addison-Wesley
<td width="645">
<p>David R. Butenhof, <cite>Programming with POSIX Threads</cite>, Addison-Wesley
1997, ISBN 0-201-63392-2 <a
href="http://cseng.aw.com/book/0,3828,0201633922,00.html">
href="http://cseng.aw.com/book/0,3828,0201633922,00.html">
http://cseng.aw.com/book/0,3828,0201633922,00.html</a></p>
<p>This is a very readable explanation of threads and how to use them. Many
of the insights given apply to all multithreaded programming, not just
<p>This is a very readable explanation of threads and how to use them. Many
of the insights given apply to all multithreaded programming, not just
POSIX Threads.</p>
</td>
</tr>
<tr>
<tr>
<td width="102" valign="top" align="left"><b>[<a name=
"Hoare-74">Hoare 74</a>]</b></td>
<td width="645">
<p>C.A.R Hoare, <cite>Monitors: An Operating System Structuring Concept</cite>,
Communications of the ACM, Vol. 17, No. 10. October 1974, pp. 549-557
<td width="645">
<p>C.A.R Hoare, <cite>Monitors: An Operating System Structuring Concept</cite>,
Communications of the ACM, Vol. 17, No. 10. October 1974, pp. 549-557
<a href=
"http://www.acm.org/classics/feb96/"> http://www.acm.org/classics/feb96/</a></p>
<p>Hoare and Brinch Hansen&#39;s work on Monitors is the basis for reliable
multithreading patterns. This is one of the most often referenced papers
<p>Hoare and Brinch Hansen&#39;s work on Monitors is the basis for reliable
multithreading patterns. This is one of the most often referenced papers
in all of computer science, and with good reason.</p>
</td>
</tr>
<tr>
<tr>
<td width="102" valign="top" align="left"><b>[<a name=
"ISO-98">ISO 98</a>]</b></td>
<td width="645">
<p>ISO/IEC 14882:1998(E) <cite>Programming Language C++</cite> <a href="http://www.ansi.org">
<td width="645">
<p>ISO/IEC 14882:1998(E) <cite>Programming Language C++</cite> <a href="http://www.ansi.org">
http://www.ansi.org</a></p>
<p>This is the official C++ Standards document. Available from the ANSI
<p>This is the official C++ Standards document. Available from the ANSI
(American National Standards Institute) Electronic Standards Store.</p>
</td>
</tr>
<tr>
<tr>
<td width="102" valign="top" align="left"><b>[<a name=
"McDowell-89">McDowell 89</a>]</b></td>
<td width="645"> Charles E McDowell, David P. Helmbold, <cite>Debugging Concurrent
Programs</cite>, ACM Computing Surveys, Vol. 21, No. 2, December, 1989.
<td width="645"> Charles E McDowell, David P. Helmbold, <cite>Debugging Concurrent
Programs</cite>, ACM Computing Surveys, Vol. 21, No. 2, December, 1989.
<a href=
"http://www.acm.org/pubs/citations/journals/surveys/1989-21-4/p593-mcdowell/">
http://www.acm.org/pubs/citations/journals/surveys/1989-21-4/p593-mcdowell/</a>
<p>Identifies many of the unique failure modes and debugging difficulties
"http://www.acm.org/pubs/citations/journals/surveys/1989-21-4/p593-mcdowell/">
http://www.acm.org/pubs/citations/journals/surveys/1989-21-4/p593-mcdowell/</a>
<p>Identifies many of the unique failure modes and debugging difficulties
associated with concurrent programs.</p>
</td>
</tr>
<tr>
<tr>
<td width="102" valign="top" align="left"><b>[<a name=
"Schmidt">Schmidt</a>]</b> </td>
<td width="645">
<p>Douglas C. Schmidt and Irfan Pyarali, <cite>Strategies for Implementing
POSIX Condition Variables on Win32</cite>, Department of Computer Science,
<td width="645">
<p>Douglas C. Schmidt and Irfan Pyarali, <cite>Strategies for Implementing
POSIX Condition Variables on Win32</cite>, Department of Computer Science,
Washington University, St. Louis, Missouri. <a href=
"http://www.cs.wustl.edu/~schmidt/win32-cv-1.html"> http://www.cs.wustl.edu/~schmidt/win32-cv-1.html</a></p>
<p>Rationale for understanding Boost.Threads condition variables. Note that
Alexander Terekhov found some bugs in the implementation given in this
article, so pthreads-win32 and Boost.Threads are even more complicated
<p>Rationale for understanding Boost.Threads condition variables. Note that
Alexander Terekhov found some bugs in the implementation given in this
article, so pthreads-win32 and Boost.Threads are even more complicated
yet.</p>
</td>
</tr>
<tr>
<tr>
<td width="102" valign="top" align="left"><b>[<a name=
"Schmidt-00">Schmidt 00</a>]</b> </td>
<td width="645">
<p>Douglas C. Schmidt, Michael Stal, Hans Rohnert and Frank Buschmann, <cite>Pattern-Oriented
Software Architecture Volume 2 - Patterns for Concurrent and Networked
<td width="645">
<p>Douglas C. Schmidt, Michael Stal, Hans Rohnert and Frank Buschmann, <cite>Pattern-Oriented
Software Architecture Volume 2 - Patterns for Concurrent and Networked
Objects</cite>, Wiley 2000, ISBN 0-471-60695-2 <a href=
"http://www.wiley.com/Corporate/Website/Objects/Products/0,9049,104671,00.html">
"http://www.wiley.com/Corporate/Website/Objects/Products/0,9049,104671,00.html">
http://www.wiley.com/Corporate/Website/Objects/Products/0,9049,104671,00.html</a></p>
<p>This is a very good explanation of how to apply several patterns useful
for concurrent programming. Among the patterns documented is the Monitor
<p>This is a very good explanation of how to apply several patterns useful
for concurrent programming. Among the patterns documented is the Monitor
Pattern mentioned frequently in the <b>Boost.Threads</b> documentation.</p>
</td>
</tr>
<tr>
<tr>
<td width="102" valign="top" align="left"><b>[<a name=
"Stroustrup-00">Stroustrup 00</a>]</b></td>
<td width="645"> Bjarne Stroustrup, <cite>The C++ Programming Language</cite>,
<td width="645"> Bjarne Stroustrup, <cite>The C++ Programming Language</cite>,
Special Edition, Addison-Wesley 2000, ISBN 0-201-70073-5 <a href=
"http://cseng.aw.com/book/0,3828,0201700735,00.html"> http://cseng.aw.com/book/0,3828,0201700735,00.html</a>
<p>The first book a C++ programmer should own. Note that the 3rd edition
(and subsequent editions like the Special Edition) has been rewritten
"http://cseng.aw.com/book/0,3828,0201700735,00.html"> http://cseng.aw.com/book/0,3828,0201700735,00.html</a>
<p>The first book a C++ programmer should own. Note that the 3rd edition
(and subsequent editions like the Special Edition) has been rewritten
to cover the ISO standard language and library.</p>
</td>
</tr>
</table>
<p>Note: The URL&#39;s above are provided in plain text form so that they will
<p>Note: The URL&#39;s above are provided in plain text form so that they will
be visible on printed copies of this document.</p>
<hr>
<p>Revised
<p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
05 November, 2001
05 November, 2001
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p>
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> and
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> and
Beman Dawes 2001-2002. All Rights Reserved.</i></p>
<p>Permission to use, copy, modify, distribute and sell this software and its
documentation for any purpose is hereby granted without fee, provided that the
above copyright notice appear in all copies and that both that copyright notice
and this permission notice appear in supporting documentation. William E. Kempf
makes no representations about the suitability of this software for any purpose.
<p>Permission to use, copy, modify, distribute and sell this software and its
documentation for any purpose is hereby granted without fee, provided that the
above copyright notice appear in all copies and that both that copyright notice
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 &quot;as is&quot; without express or implied warranty.</p>
</body>
</html>

77
doc/build.html Normal file
View File

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

View File

@@ -7,11 +7,11 @@
<body link="#0000ff" vlink="#800080">
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
"header">
<tr>
<td valign="top" width="300">
<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">
<td valign="top">
<h1 align="center">Boost.Threads</h1>
<h2 align="center">Header &lt;<a href="../../../boost/thread/condition.hpp">boost/thread/condition.hpp</a>&gt;</h2>
</td>
@@ -19,16 +19,16 @@
</table>
<hr>
<h2>Contents</h2>
<dl class="page-index">
<dl class="page-index">
<dt><a href="#introduction">Introduction</a></dt>
<dt><a href="#classes">Classes</a></dt>
<dl class="page-index">
<dl class="page-index">
<dt><a href="#class-condition">Class <code>condition</code></a></dt>
<dl class="page-index">
<dl class="page-index">
<dt><a href="#class-condition-synopsis">Class <code>condition</code> synopsis</a></dt>
<dt><a href="#class-condition-ctors">Class <code>condition</code> constructors
<dt><a href="#class-condition-ctors">Class <code>condition</code> constructors
and destructor</a></dt>
<dt><a href="#class-condition-modifiers">Class <code>condition</code> modifier
<dt><a href="#class-condition-modifiers">Class <code>condition</code> modifier
functions</a></dt>
</dl>
</dl>
@@ -40,25 +40,25 @@
to define the class condition.</p>
<h2><a name="classes"></a>Classes</h2>
<h3><a name="class-condition"></a>Class <code>condition</code></h3>
<p>An object of class <code>condition</code> is a synchronization primitive used
to cause a thread to wait until a particular shared-data condition (or time)
is met. A <code>condition</code> object is always used in conjunction with a
mutex object (an object whose type is a model of <a href="mutex_concept.html">Mutex</a>
or one of its refinements). The mutex object must be locked prior to waiting
on the <code>condition</code>, which is verified by passing a lock object (an
object whose type is a model of <a href="lock_concept.html">Lock</a> or one
of its refinements) to the <code>condition</code> object&#39;s <code>wait</code>
functions. Upon blocking on the condition object, the thread unlocks the mutex
object. When the thread returns from a call to one of the condition object's
wait functions the mutex object is again locked. The tricky unlock/lock sequence
is performed automatically by the <code> condition</code> object&#39;s <code>wait</code>
<p>An object of class <code>condition</code> is a synchronization primitive used
to cause a thread to wait until a particular shared-data condition (or time)
is met. A <code>condition</code> object is always used in conjunction with a
mutex object (an object whose type is a model of <a href="mutex_concept.html">Mutex</a>
or one of its refinements). The mutex object must be locked prior to waiting
on the <code>condition</code>, which is verified by passing a lock object (an
object whose type is a model of <a href="lock_concept.html">Lock</a> or one
of its refinements) to the <code>condition</code> object&#39;s <code>wait</code>
functions. Upon blocking on the condition object, the thread unlocks the mutex
object. When the thread returns from a call to one of the condition object's
wait functions the mutex object is again locked. The tricky unlock/lock sequence
is performed automatically by the <code> condition</code> object&#39;s <code>wait</code>
functions.</p>
<p>The <code>condition</code> type is often used to implement the <i> Monitor
Object</i> and other important patterns (see <a href="bibliography.html#Schmidt-00">[Schmidt
00]</a> and <a href="bibliography.html#Hoare-74">[Hoare 74]</a>). Monitors are
<p>The <code>condition</code> type is often used to implement the <i> Monitor
Object</i> and other important patterns (see <a href="bibliography.html#Schmidt-00">[Schmidt
00]</a> and <a href="bibliography.html#Hoare-74">[Hoare 74]</a>). Monitors are
one of the most important patterns for creating reliable multithreaded programs.</p>
<p>See <a href="definitions.html">Formal Definitions</a> for definitions of thread
states <a href="definitions.html#state"> blocked</a> and <a href="definitions.html#state">ready</a>.
<p>See <a href="definitions.html">Formal Definitions</a> for definitions of thread
states <a href="definitions.html#state"> blocked</a> and <a href="definitions.html#state">ready</a>.
Note that &quot;waiting&quot; is a synonym for blocked.</p>
<h4><a name="class-condition-synopsis"></a>Class <code>condition</code> synopsis</h4>
<pre>
@@ -84,99 +84,99 @@ namespace boost
};
};
</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>
<pre>
condition();
</pre>
<dl class="function-semantics">
<dl class="function-semantics">
<dt><b>Effects:</b> Constructs a <code>condition</code> object.</dt>
</dl>
<pre>
~condition();
</pre>
<dl class="function-semantics">
<dl class="function-semantics">
<dt><b>Effects:</b> Destroys <code>*this</code>.</dt>
</dl>
<h4><a name="class-condition-modifiers"></a>Class <code>condition</code> modifier
<h4><a name="class-condition-modifiers"></a>Class <code>condition</code> modifier
functions</h4>
<pre>
void notify_one();
</pre>
<dl class="function-semantics">
<dt><b>Effects:</b> If there is a thread waiting on <code>*this</code>, change
<dl class="function-semantics">
<dt><b>Effects:</b> If there is a thread waiting on <code>*this</code>, change
that thread&#39;s state to ready. Otherwise there is no effect.</dt>
<dt><b>Note:</b> If more than one thread is waiting on the condition, it is
unspecified which is made ready. After returning to a ready state the notified
thread must still acquire the mutex again (which occurs within the call to
<dt><b>Note:</b> If more than one thread is waiting on the condition, it is
unspecified which is made ready. After returning to a ready state the notified
thread must still acquire the mutex again (which occurs within the call to
one of the <code>condition</code> object's wait functions).</dt>
</dl>
<pre>
void notify_all();
</pre>
<dl class="function-semantics">
<dt><b>Effects:</b> Change the state of all threads waiting on <code> *this</code>
to ready. If there are no waiting threads, <code> notify_all()</code> has
<dl class="function-semantics">
<dt><b>Effects:</b> Change the state of all threads waiting on <code> *this</code>
to ready. If there are no waiting threads, <code> notify_all()</code> has
no effect.</dt>
</dl>
<pre>
template &lt;typename ScopedLock&gt;
void wait(ScopedLock&amp; lock);
</pre>
<dl class="function-semantics">
<dt><b>Requires:</b> <code>ScopedLock</code> meets the <a href="lock_concept.html#ScopedLock">ScopedLock</a>
<dl class="function-semantics">
<dt><b>Requires:</b> <code>ScopedLock</code> meets the <a href="lock_concept.html#ScopedLock">ScopedLock</a>
requirements.</dt>
<dt><b>Effects:</b> Releases the lock on the <a href="mutex_concept.html">mutex
model</a> associated with <code>lock</code>, blocks the current thread of
execution until readied by a call to <code>this-&gt;notify_one()</code> or
<dt><b>Effects:</b> Releases the lock on the <a href="mutex_concept.html">mutex
model</a> associated with <code>lock</code>, blocks the current thread of
execution until readied by a call to <code>this-&gt;notify_one()</code> or
<code> this-&gt;notify_all()</code>, and then reacquires the lock.</dt>
<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>
<dt><b>Danger:</b> This version should always be used within a loop checking
that the state logically associated with the <code>condition</code> has become
true. Without the loop, race conditions can ensue due to possible &quot;spurious
wake ups&quot;. The second version encapsulates this loop idiom internally
<dt><b>Danger:</b> This version should always be used within a loop checking
that the state logically associated with the <code>condition</code> has become
true. Without the loop, race conditions can ensue due to possible &quot;spurious
wake ups&quot;. The second version encapsulates this loop idiom internally
and is generally the preferred method.</dt>
</dl>
<pre>
Template&lt;typename ScopedLock, typename Pr&gt;
void wait(ScopedLock&amp; lock, Pr pred);
</pre>
<dl class="function-semantics">
<dt><b>Requires:</b> <code>ScopedLock</code> meets the <a href="lock_concept.html#ScopedLock">ScopedLock</a>
<dl class="function-semantics">
<dt><b>Requires:</b> <code>ScopedLock</code> meets the <a href="lock_concept.html#ScopedLock">ScopedLock</a>
requirements, return from <code>pred()</code> convertible to bool.</dt>
<dt><b>Effects:</b> As if: <code>while (!pred()) wait(lock)</code></dt>
<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>
</dl>
<pre>
template &lt;typename ScopedLock&gt;
bool timed_wait(ScopedLock&amp; lock, const <a href="xtime.html">xtime</a>&amp; XT);
</pre>
<dl class="function-semantics">
<dt><b>Requires:</b> <code>ScopedLock</code> meets the <a href="lock_concept.html#ScopedLock">ScopedLock</a>
<dl class="function-semantics">
<dt><b>Requires:</b> <code>ScopedLock</code> meets the <a href="lock_concept.html#ScopedLock">ScopedLock</a>
requirements.</dt>
<dt><b>Effects:</b> Releases the lock on the <a href="mutex_concept.html">mutex
model</a> associated with the <code> lock</code>, blocks the current thread
of execution until readied by a call to <code>this-&gt;notify_one()</code>
or <code> this-&gt;notify_all()</code>, or until <code>XT</code>, and then
<dt><b>Effects:</b> Releases the lock on the <a href="mutex_concept.html">mutex
model</a> associated with the <code> lock</code>, blocks the current thread
of execution until readied by a call to <code>this-&gt;notify_one()</code>
or <code> this-&gt;notify_all()</code>, or until <code>XT</code>, and then
reacquires the lock.</dt>
<dt><b>Returns:</b> <code>false</code> if <code>XT</code> is reached, otherwise
<dt><b>Returns:</b> <code>false</code> if <code>XT</code> is reached, otherwise
<code>true</code>.</dt>
<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>
<dt><b>Danger:</b> This version should always be used within a loop checking
that the state logically associated with the <code>condition</code> has become
true. Without the loop, race conditions can ensue due to &quot;spurious wake
ups&quot;. The second version encapsulates this loop idiom internally and
<dt><b>Danger:</b> This version should always be used within a loop checking
that the state logically associated with the <code>condition</code> has become
true. Without the loop, race conditions can ensue due to &quot;spurious wake
ups&quot;. The second version encapsulates this loop idiom internally and
is generally the preferred method.</dt>
</dl>
<pre>
Template&lt;typename ScopedLock, typename Pr&gt;
bool timed_wait(ScopedLock&amp; lock, const <a href="xtime.html">xtime</a>&amp; XT, Pr pred);
</pre>
<dl class="function-semantics">
<dt><b>Requires:</b> <code>ScopedLock</code> meets the <a href="lock_concept.html#ScopedLock">ScopedLock</a>
<dl class="function-semantics">
<dt><b>Requires:</b> <code>ScopedLock</code> meets the <a href="lock_concept.html#ScopedLock">ScopedLock</a>
requirements, return from <code>pred()</code> convertible to bool.</dt>
<dt><b>Effects:</b> As if:<br>
<pre>
@@ -188,82 +188,13 @@ while (!pred())
return true;
</pre>
</dt>
<dt><b>Returns:</b> <code>false</code> if <code>XT</code> is reached, otherwise
<dt><b>Returns:</b> <code>false</code> if <code>XT</code> is reached, otherwise
<code>true</code>.</dt>
<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>
</dl>
<h2><a name="examples"></a>Example(s)</h2>
<pre>
#include &lt;iostream&gt;
#include &lt;vector&gt;
#include <a href="../../../boost/utility.hpp">&lt;boost/utility.hpp&gt;</a>
#include <a href="../../../boost/thread/condition.hpp">&lt;boost/thread/condition.hpp&gt;</a>
#include <a href="../../../boost/thread/thread.hpp">&lt;boost/thread/thread.hpp&gt;</a>
class bounded_buffer : private boost::noncopyable
{
public:
typedef boost::mutex::scoped_lock lock;
bounded_buffer(int n) : begin(0), end(0), buffered(0), circular_buf(n) { }
void send (int m) {
lock lk(monitor);
while (buffered == circular_buf.size())
buffer_not_full.wait(lk);
circular_buf[end] = m;
end = (end+1) % circular_buf.size();
++buffered;
buffer_not_empty.notify_one();
}
int receive() {
lock lk(monitor);
while (buffered == 0)
buffer_not_empty.wait(lk);
int i = circular_buf[begin];
begin = (begin+1) % circular_buf.size();
--buffered;
buffer_not_full.notify_one();
return i;
}
private:
int begin, end, buffered;
std::vector&lt;int&gt; circular_buf;
boost::condition buffer_not_full, buffer_not_empty;
boost::mutex monitor;
};
bounded_buffer buf(2);
void sender() {
int n = 0;
while (n &lt; 100) {
buf.send(n);
std::cout &lt;&lt; &quot;sent: &quot; &lt;&lt; n &lt;&lt; std::endl;
++n;
}
buf.send(-1);
}
void receiver() {
int n;
do {
n = buf.receive();
std::cout &lt;&lt; &quot;received: &quot; &lt;&lt; n &lt;&lt; std::endl;
} while (n != -1); // -1 indicates end of buffer
}
int main(int, char*[])
{
boost::thread thrd1(&amp;sender);
boost::thread thrd2(&amp;receiver);
thrd1.join();
thrd2.join();
return 0;
}
</pre>
<p><a href="../example/condition.cpp">libs/thread/example/condition.cpp</a></p>
<p>Typical output (dependent on scheduling policies) is:</p>
<pre>
sent: 0
@@ -277,18 +208,18 @@ received: 3
sent: 4
received: 4
</pre>
<p>Revised
<p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
05 November, 2001
05 November, 2001
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p>
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
All Rights Reserved.</i></p>
<p>Permission to use, copy, modify, distribute and sell this software and its
documentation for any purpose is hereby granted without fee, provided that the
above copyright notice appear in all copies and that both that copyright notice
and this permission notice appear in supporting documentation. William E. Kempf
makes no representations about the suitability of this software for any purpose.
<p>Permission to use, copy, modify, distribute and sell this software and its
documentation for any purpose is hereby granted without fee, provided that the
above copyright notice appear in all copies and that both that copyright notice
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 &quot;as is&quot; without express or implied warranty.</p>
</body>
</html>

View File

@@ -7,88 +7,88 @@
<body link="#0000ff" vlink="#800080">
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
"header">
<tr>
<td valign="top" width="300">
<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">
<td valign="top">
<h1 align="center">Boost.Threads</h1>
<h2 align="center">Configuration</h2>
</td>
</tr>
</table>
<hr>
<dl class="page-index">
<dl class="page-index">
<dt><a href="#introduction">Introduction</a></dt>
<dt><a href="#lib-defined-public">Public Library Defined Macros</a></dt>
<dt><a href="#lib-defined-impl">Library Defined Implementation Macros</a></dt>
</dl>
<h2><a name="introduction"></a>Introduction</h2>
<p><b>Boost.Threads</b> uses several configuration macros in <a href="../../config/config.htm">&lt;boost/config.hpp&gt;</a>,
as well as configuration macros meant to be supplied by the application. These
<p><b>Boost.Threads</b> uses several configuration macros in <a href="../../config/config.htm">&lt;boost/config.hpp&gt;</a>,
as well as configuration macros meant to be supplied by the application. These
macros are documented here.</p>
<h2><a name="lib-defined-public"></a>Public Library Defined Macros</h2>
<p>These macros are defined by <b>Boost.Threads</b> but are expected to be used
<p>These macros are defined by <b>Boost.Threads</b> but are expected to be used
by application code.</p>
<table summary="public library defined macros" cellspacing="10" width="100%">
<tr>
<tr>
<td><b>Macro</b></td>
<td><b>Meaning</b></td>
</tr>
<tr>
<tr>
<td>BOOST_HAS_THREADS</td>
<td>Indicates that threading support is available. This means both that there
is a platform specific implementation for <b>Boost.Threads</b> and that
threading support has been enabled in a platform specific manner. For instance,
on the Win32 platform there&#39;s an implementation for <b>Boost.Threads</b>
but unless the program is compiled against one of the multithreading runtimes
(often determined by the compiler predefining the macro _MT) the BOOST_HAS_THREADS
<td>Indicates that threading support is available. This means both that there
is a platform specific implementation for <b>Boost.Threads</b> and that
threading support has been enabled in a platform specific manner. For instance,
on the Win32 platform there&#39;s an implementation for <b>Boost.Threads</b>
but unless the program is compiled against one of the multithreading runtimes
(often determined by the compiler predefining the macro _MT) the BOOST_HAS_THREADS
macro remains undefined.</td>
</tr>
</table>
<h2><a name="lib-defined-impl"></a>Library Defined Implementation Macros</h2>
<p>These macros are defined by <b>Boost.Threads</b> and are implementation details
<p>These macros are defined by <b>Boost.Threads</b> and are implementation details
of interest only to implementors.</p>
<table summary="library defined implementation macros" cellspacing="10" width="100%">
<tr>
<tr>
<td><b>Macro</b></td>
<td><b>Meaning</b></td>
</tr>
<tr>
<tr>
<td>BOOST_HAS_WINTHREADS</td>
<td>Indicates that the platform has the Microsoft Win32 threading libraries,
<td>Indicates that the platform has the Microsoft Win32 threading libraries,
and that they should be used to implement <b>Boost.Threads</b>.</td>
</tr>
<tr>
<tr>
<td>BOOST_HAS_PTHREADS</td>
<td>Indicates that the platform has the POSIX pthreads libraries, and that
<td>Indicates that the platform has the POSIX pthreads libraries, and that
they should be used to implement <b>Boost.Threads</b>.</td>
</tr>
<tr>
<tr>
<td>BOOST_HAS_FTIME</td>
<td>Indicates that the implementation should use GetSystemTimeAsFileTime()
and the FILETIME type to calculate the current time. This is an implementation
<td>Indicates that the implementation should use GetSystemTimeAsFileTime()
and the FILETIME type to calculate the current time. This is an implementation
detail used by boost::detail::getcurtime().</td>
</tr>
<tr>
<tr>
<td>BOOST_HAS_GETTTIMEOFDAY</td>
<td>Indicates that the implementation should use gettimeofday() to calculate
<td>Indicates that the implementation should use gettimeofday() to calculate
the current time. This is an implementation detail used by boost::detail::getcurtime().</td>
</tr>
</table>
<hr>
<p>Revised
<p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
05 November, 2001
05 November, 2001
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p>
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
All Rights Reserved.</i></p>
<p>Permission to use, copy, modify, distribute and sell this software and its
documentation for any purpose is hereby granted without fee, provided that the
above copyright notice appear in all copies and that both that copyright notice
and this permission notice appear in supporting documentation. William E. Kempf
makes no representations about the suitability of this software for any purpose.
<p>Permission to use, copy, modify, distribute and sell this software and its
documentation for any purpose is hereby granted without fee, provided that the
above copyright notice appear in all copies and that both that copyright notice
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 &quot;as is&quot; without express or implied warranty.</p>
</body>
</html>

View File

@@ -7,11 +7,11 @@
<body link="#0000ff" vlink="#800080">
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
"header">
<tr>
<td valign="top" width="300">
<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">
<td valign="top">
<h1 align="center">Boost.Threads</h1>
<h2 align="center">Definitions</h2>
</td>
@@ -19,10 +19,10 @@
</table>
<hr>
<h2>Contents</h2>
<dl class="page-index">
<dl class="page-index">
<dt><a href="#introduction">Introduction</a></dt>
<dt><a href="#definitions">Definitions</a></dt>
<dl class="page-index">
<dl class="page-index">
<dt><a href="#definition-thread">Thread</a></dt>
<dt><a href="#definition-thread-safe">Thread-safe</a></dt>
<dt><a href="#definition-thread-state">Thread State</a></dt>
@@ -37,40 +37,40 @@
<hr>
<h2><a name="introduction"></a>Introduction</h2>
<p>The definitions are given in terms of the <a href=
"bibliography.html#ISO-98">C++ Standard</a>. References to the standard
are in the form [1.2.3/4], which represents the section number, with the paragraph
"bibliography.html#ISO-98">C++ Standard</a>. References to the standard
are in the form [1.2.3/4], which represents the section number, with the paragraph
number following the &quot;/&quot;.</p>
<p>Because the definitions are written in something akin to &quot;standardese&quot;,
they can be difficult to understand. The intent isn&#39;t to confuse, but rather
to clarify the additional requirements Boost.Threads places on a C++ implementation
<p>Because the definitions are written in something akin to &quot;standardese&quot;,
they can be difficult to understand. The intent isn&#39;t to confuse, but rather
to clarify the additional requirements Boost.Threads places on a C++ implementation
as defined by the C++ Standard.</p>
<h2><a name="definitions"></a>Definitions</h2>
<h3><a name="definition-thread"></a>Thread</h3>
<p>Thread is short for &quot;thread of execution&quot;. A thread of execution
is an execution environment [1.9/7] within the execution environment of a C++
program [1.9]. The main() function [3.6.1] of the program is the initial function
of the initial thread. A program in a multithreading environment always has
<p>Thread is short for &quot;thread of execution&quot;. A thread of execution
is an execution environment [1.9/7] within the execution environment of a C++
program [1.9]. The main() function [3.6.1] of the program is the initial function
of the initial thread. A program in a multithreading environment always has
an initial thread even if the program explicitly creates no additional threads.</p>
<p>Unless otherwise specified, each thread shares all aspects of its execution
environment with other threads in the program. Shared aspects of the execution
<p>Unless otherwise specified, each thread shares all aspects of its execution
environment with other threads in the program. Shared aspects of the execution
environment include, but are not limited to, the following:</p>
<ul>
<li>Static storage duration (static, extern) objects [3.7.1].</li>
</ul>
<ul>
<li>Dynamic storage duration (heap) objects [3.7.3]. Thus each memory allocation
will return a unique addresses, regardless of the thread making the allocation
<li>Dynamic storage duration (heap) objects [3.7.3]. Thus each memory allocation
will return a unique addresses, regardless of the thread making the allocation
request.</li>
</ul>
<ul>
<li>Automatic storage duration (stack) objects [3.7.2] accessed via pointer
<li>Automatic storage duration (stack) objects [3.7.2] accessed via pointer
or reference from another thread.</li>
</ul>
<ul>
<li>Resources provided by the operating system. For example, files.</li>
</ul>
<ul>
<li>The program itself. In other words, each thread is executing some function
<li>The program itself. In other words, each thread is executing some function
of the same program, not a totally different program.</li>
</ul>
<p>Each thread has its own:</p>
@@ -81,183 +81,183 @@
<li>Automatic storage duration (stack) objects [3.7.2].</li>
</ul>
<h3><a name="definition-thread-safe"></a>Thread-safe</h3>
<p>A program is thread-safe if it has no <a href="#Race condition">race conditions</a>,
does not <a href="#Deadlock">deadlock</a>, and has no <a href="#Priority failure">priority
<p>A program is thread-safe if it has no <a href="#Race condition">race conditions</a>,
does not <a href="#Deadlock">deadlock</a>, and has no <a href="#Priority failure">priority
failures</a>.</p>
<p>Note that thread-safety does not necessarily imply efficiency, and than while
some thread-safety violations can be determined statically at compile time,
<p>Note that thread-safety does not necessarily imply efficiency, and than while
some thread-safety violations can be determined statically at compile time,
many thread-safety errors can only only be detected at runtime.</p>
<h3><a name="definition-thread-state"></a>Thread State</h3>
<p>During the lifetime of a thread, it shall be in one of the following states:</p>
<table summary="thread states" border="1" cellpadding="5">
<tr>
<tr>
<td><b>State</b></td>
<td><b>Description</b></td>
</tr>
<tr>
<tr>
<td>Ready</td>
<td>Ready to run, but waiting for a processor.</td>
</tr>
<tr>
<tr>
<td>Running</td>
<td>Currently executing on a processor. Zero or more threads may be running
<td>Currently executing on a processor. Zero or more threads may be running
at any time, with a maximum equal to the number of processors.</td>
</tr>
<tr>
<tr>
<td>Blocked</td>
<td>Waiting for some resource other than a processor which is not currently
available, or for the completion of calls to library functions [1.9/6].
<td>Waiting for some resource other than a processor which is not currently
available, or for the completion of calls to library functions [1.9/6].
The term &quot;waiting&quot; is synonymous for &quot;blocked&quot;</td>
</tr>
<tr>
<tr>
<td>Terminated</td>
<td>Finished execution but not yet detached or joined.</td>
</tr>
</table>
<p>Thread state transitions shall occur only as specified:</p>
<table summary="state transitions" border="1" cellpadding="5">
<tr>
<tr>
<td><b>From</b></td>
<td><b>To</b></td>
<td><b>Cause</b></td>
</tr>
<tr>
<td>
<tr>
<td>
<p align="left">[none]</p>
</td>
<td>Ready</td>
<td>Thread is created by a call to a library function. In the case of the
initial thread, creation is implicit and occurs during the startup of the
<td>Thread is created by a call to a library function. In the case of the
initial thread, creation is implicit and occurs during the startup of the
main() function [3.6.1].</td>
</tr>
<tr>
<tr>
<td>Ready</td>
<td>Running</td>
<td>Processor becomes available.</td>
</tr>
<tr>
<tr>
<td>Running</td>
<td>Ready</td>
<td>Thread preempted.</td>
</tr>
<tr>
<tr>
<td>Running</td>
<td>Blocked</td>
<td>Thread calls a library function which waits for a resource or for the
<td>Thread calls a library function which waits for a resource or for the
completion of I/O.</td>
</tr>
<tr>
<tr>
<td>Running</td>
<td>Terminated</td>
<td>Thread returns from its initial function, calls a thread termination library
function, or is canceled by some other thread calling a thread termination
<td>Thread returns from its initial function, calls a thread termination library
function, or is canceled by some other thread calling a thread termination
library function.</td>
</tr>
<tr>
<tr>
<td>Blocked</td>
<td>Ready</td>
<td>The resource being waited for becomes available, or the blocking library
<td>The resource being waited for becomes available, or the blocking library
function completes.</td>
</tr>
<tr>
<tr>
<td>Terminated</td>
<td>[none]</td>
<td>Thread is detached or joined by some other thread calling the appropriate
<td>Thread is detached or joined by some other thread calling the appropriate
library function, or by program termination [3.6.3].</td>
</tr>
</table>
<p>[Note: if a suspend() function is added to the threading library, additional
<p>[Note: if a suspend() function is added to the threading library, additional
transitions to the blocked state will have to be added to the above table.]</p>
<h3><a name="definition-race-condition"></a>Race Condition</h3>
<p>A race condition is what occurs when multiple threads read and write to the
same memory without proper synchronization, resulting in an incorrect value
being read or written. The result of a race condition may be a bit pattern which
isn&#39;t even a valid value for the data type. A race condition results in
<p>A race condition is what occurs when multiple threads read and write to the
same memory without proper synchronization, resulting in an incorrect value
being read or written. The result of a race condition may be a bit pattern which
isn&#39;t even a valid value for the data type. A race condition results in
undefined behavior [1.3.12].</p>
<p>Race conditions can be prevented by serializing memory access using the tools
<p>Race conditions can be prevented by serializing memory access using the tools
provided by Boost.Threads.</p>
<h3><a name="definition-deadlock"></a>Deadlock</h3>
<p>Deadlock is an execution state where for some set of threads, each thread in
the set is blocked waiting for some action by one of the other threads in the
<p>Deadlock is an execution state where for some set of threads, each thread in
the set is blocked waiting for some action by one of the other threads in the
set. Since each is waiting on the others, none will ever become ready again.</p>
<h3><a name="definition-starvation"></a>Starvation</h3>
<p>The condition in which a thread is not making sufficient progress in its work
<p>The condition in which a thread is not making sufficient progress in its work
during a given time interval.</p>
<h3><a name="definition-priority-failure"></a>Priority Failure</h3>
<p>A priority failure (such as priority inversion or infinite overtaking) occurs
when threads executed in such a sequence that required work is not performed
<p>A priority failure (such as priority inversion or infinite overtaking) occurs
when threads executed in such a sequence that required work is not performed
in time to be useful.</p>
<h3><a name="definition-visibility"></a>Memory Visibility</h3>
<p>An address [1.7] shall always point to the same memory byte, regardless of
<p>An address [1.7] shall always point to the same memory byte, regardless of
the thread or processor dereferencing the address.</p>
<p>An object [1.8, 1.9] is accessible from multiple threads if it is of static
storage duration (static, extern) [3.7.1], or if a pointer or reference to it
<p>An object [1.8, 1.9] is accessible from multiple threads if it is of static
storage duration (static, extern) [3.7.1], or if a pointer or reference to it
is explicitly or implicitly dereferenced in multiple threads.</p>
<p>For an object accessible from multiple threads, the value of the object accessed
from one thread may be indeterminate or different than the value accessed from
another thread, except under the conditions specified in the following table.
For the same row of the table, the value of an object accessible at the indicated
sequence point in thread A will be determinate and the same if accessed at or
after the indicated sequence point in thread B, provided the object is not otherwise
modified. In the table, the &quot;sequence point at a call&quot; is the sequence
point after the evaluation of all function arguments [1.9/17], while the &quot;sequence
point after a call&quot; is the sequence point after the copying of the returned
<p>For an object accessible from multiple threads, the value of the object accessed
from one thread may be indeterminate or different than the value accessed from
another thread, except under the conditions specified in the following table.
For the same row of the table, the value of an object accessible at the indicated
sequence point in thread A will be determinate and the same if accessed at or
after the indicated sequence point in thread B, provided the object is not otherwise
modified. In the table, the &quot;sequence point at a call&quot; is the sequence
point after the evaluation of all function arguments [1.9/17], while the &quot;sequence
point after a call&quot; is the sequence point after the copying of the returned
value...&quot; [1.9/17].</p>
<table summary="memory visibility" border="1" cellpadding="5">
<tr>
<tr>
<td align="center"><b>Thread A</b></td>
<td align="center"><b>Thread B</b></td>
</tr>
<tr>
<tr>
<td>The sequence point at a call to a library thread-creation function.</td>
<td>The first sequence point of the initial function in the new thread created
<td>The first sequence point of the initial function in the new thread created
by the Thread A call.</td>
</tr>
<tr>
<td>The sequence point at a call to a library function which locks a mutex,
<tr>
<td>The sequence point at a call to a library function which locks a mutex,
directly or by waiting for a condition variable.</td>
<td>The sequence point after a call to a library function which unlocks the
<td>The sequence point after a call to a library function which unlocks the
same mutex.</td>
</tr>
<tr>
<tr>
<td>The last sequence point before thread termination.</td>
<td>The sequence point after a call to a library function which joins the
<td>The sequence point after a call to a library function which joins the
terminated thread.</td>
</tr>
<tr>
<td>The sequence point at a call to a library function which signals or broadcasts
<tr>
<td>The sequence point at a call to a library function which signals or broadcasts
a condition variable.</td>
<td>The sequence point after the call to the library function which was waiting
<td>The sequence point after the call to the library function which was waiting
on that same condition variable or signal.</td>
</tr>
</table>
<p>The architecture of the execution environment and the observable behavior of
<p>The architecture of the execution environment and the observable behavior of
the abstract machine [1.9] shall be the same on all processors.</p>
<p>The latitude granted by the C++ standard for an implementation to alter the
definition of observable behavior of the abstract machine to include additional
<p>The latitude granted by the C++ standard for an implementation to alter the
definition of observable behavior of the abstract machine to include additional
library I/O functions [1.9/6] is extended to include threading library functions.</p>
<p>When an exception is thrown and there is no matching exception handler in the
same thread, behavior is undefined. The preferred behavior is the same as when
there is no matching exception handler in a program [15.3/9]. That is, terminate()
<p>When an exception is thrown and there is no matching exception handler in the
same thread, behavior is undefined. The preferred behavior is the same as when
there is no matching exception handler in a program [15.3/9]. That is, terminate()
is called, and it is implementation defined whether or not the stack is unwound.</p>
<h2><a name="acknowledgements"></a>Acknowledgments</h2>
<p>This document has been much improved by the incorporation of comments from
<p>This document has been much improved by the incorporation of comments from
William Kempf.</p>
<p>The visibility rules are based on <a href=
"bibliography.html#Butenhof-97">[Butenhof 97]</a>.</p>
<hr>
<p>Revised
<p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
05 November, 2001
05 November, 2001
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p>
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
All Rights Reserved.</i></p>
<p>Permission to use, copy, modify, distribute and sell this software and its
documentation for any purpose is hereby granted without fee, provided that the
above copyright notice appear in all copies and that both that copyright notice
and this permission notice appear in supporting documentation. William E. Kempf
makes no representations about the suitability of this software for any purpose.
<p>Permission to use, copy, modify, distribute and sell this software and its
documentation for any purpose is hereby granted without fee, provided that the
above copyright notice appear in all copies and that both that copyright notice
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 &quot;as is&quot; without express or implied warranty.</p>
</body>
</html>

View File

@@ -7,11 +7,11 @@
<body link="#0000ff" vlink="#800080">
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
"header">
<tr>
<td valign="top" width="300">
<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">
<td valign="top">
<h1 align="center">Boost.Threads</h1>
<h2 align="center">Header &lt;<a href="../../../boost/thread/exceptions.hpp">boost/thread/exceptions.hpp</a>&gt;</h2>
</td>
@@ -19,21 +19,21 @@
</table>
<hr>
<h2>Contents</h2>
<dl class="page-index">
<dl class="page-index">
<dt><a href="#introduction">Introduction</a></dt>
<dt><a href="#classes">Classes</a></dt>
<dl class="page-index">
<dl class="page-index">
<dt><a href="#class-lock_error">Class <code>lock_error</code></a></dt>
<dl class="page-index">
<dl class="page-index">
<dt><a href="#class-lock_error-synopsis">Class <code>lock_error</code> synopsis</a></dt>
<dt><a href="#class-lock_error-ctors">Class <code>lock_error</code> constructors
<dt><a href="#class-lock_error-ctors">Class <code>lock_error</code> constructors
and destructor</a></dt>
</dl>
<dt><a href="#class-thread_resource_error">Class <code>thread_resource_error</code></a></dt>
<dl class="page-index">
<dt><a href="#class-thread_resource_error-synopsis">Class <code>thread_resource_error</code>
<dl class="page-index">
<dt><a href="#class-thread_resource_error-synopsis">Class <code>thread_resource_error</code>
synopsis</a></dt>
<dt><a href="#class-thread_resource_error-ctors">Class <code>thread_resource_error</code>
<dt><a href="#class-thread_resource_error-ctors">Class <code>thread_resource_error</code>
constructors and destructor</a></dt>
</dl>
</dl>
@@ -44,67 +44,67 @@
to define the exception types that may be thrown by <b>Boost.Threads</b> classes.</p>
<h2><a name="classes"></a>Classes</h2>
<h3><a name="class-lock_error"></a>Class <code>lock_error</code></h3>
<p>The lock_error class defines an exception type thrown to indicate a locking
related error has been detected. Examples of such errors include a lock operation
which can be determined to result in a deadlock, or unlock operations attempted
<p>The lock_error class defines an exception type thrown to indicate a locking
related error has been detected. Examples of such errors include a lock operation
which can be determined to result in a deadlock, or unlock operations attempted
by a thread that does not own the lock. </p>
<h4><a name="class-lock_error-synopsis"></a>Class <code>lock_error</code> synopsis</h4>
<pre>
namespace boost
{
class lock_error : public std::logical_error
{
public:
lock_error();
};
{
public:
lock_error();
};
};
</pre>
<h4><a name="class-lock_error-ctors"></a>Class <code>lock_error</code> constructors
<h4><a name="class-lock_error-ctors"></a>Class <code>lock_error</code> constructors
and destructor</h4>
<pre>
lock_error();
</pre>
<dl class="function-semantics">
<dl class="function-semantics">
<dt><b>Effects:</b> Constructs a <code>lock_error</code> object.</dt>
</dl>
<h3><a name="class-thread_resource_error"></a>Class <code>thread_resource_error</code></h3>
<p>The thread_resource_error class defines an exception type that is thrown by
constructors in the Boost.Threads library when thread related resources can
not be acquired. This does not include memory allocation failures which instead
<p>The thread_resource_error class defines an exception type that is thrown by
constructors in the Boost.Threads library when thread related resources can
not be acquired. This does not include memory allocation failures which instead
throw std::bad_alloc. </p>
<h4><a name="class-thread_resource_error-synopsis"></a>Class <code>thread_resource_error</code>
<h4><a name="class-thread_resource_error-synopsis"></a>Class <code>thread_resource_error</code>
synopsis</h4>
<pre>
namespace boost
{
class thread_resource_error : public std::runtime_error
{
public:
thread_resource_error();
};
{
public:
thread_resource_error();
};
};
</pre>
<h4><a name="class-thread_resource_error-ctors"></a>Class <code>thread_resource_error</code>
<h4><a name="class-thread_resource_error-ctors"></a>Class <code>thread_resource_error</code>
constructors and destructor</h4>
<pre>
thread_resource_error();
</pre>
<dl class="function-semantics">
<dl class="function-semantics">
<dt><b>Effects:</b> Constructs a <code>thread_resource_error</code> object.</dt>
</dl>
<hr>
<p>Revised
<p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
05 November, 2001
05 November, 2001
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p>
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
All Rights Reserved.</i></p>
<p>Permission to use, copy, modify, distribute and sell this software and its
documentation for any purpose is hereby granted without fee, provided that the
above copyright notice appear in all copies and that both that copyright notice
and this permission notice appear in supporting documentation. William E. Kempf
makes no representations about the suitability of this software for any purpose.
<p>Permission to use, copy, modify, distribute and sell this software and its
documentation for any purpose is hereby granted without fee, provided that the
above copyright notice appear in all copies and that both that copyright notice
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 &quot;as is&quot; without express or implied warranty.</p>
</body>
</html>

View File

@@ -7,84 +7,84 @@
<body link="#0000ff" vlink="#800080">
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
"header">
<tr>
<td valign="top" width="300">
<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">
<td valign="top">
<h1 align="center">Boost.Threads</h1>
<h2 align="center">Frequently Asked Questions (FAQs)</h2>
</td>
</tr>
</table>
<hr>
<dl class="page-index">
<dl class="page-index">
<dt><a href="#question1">1. Are lock objects thread safe?</a></dt>
<dt><a href="#question2a">2a. Why was <b>Boost.Threads</b> modeled after (specific
<dt><a href="#question2a">2a. Why was <b>Boost.Threads</b> modeled after (specific
library name)?</a></dt>
<dt><a href="#question2b">2b. Why wasn't <b>Boost.Threads</b> modeled after
<dt><a href="#question2b">2b. Why wasn't <b>Boost.Threads</b> modeled after
(specific library name)?</a></dt>
<dt><a href="#question3">3. Why do mutexes have noncopyable semantics?</a></dt>
<dt><a href="#question4">4. How can you prevent deadlock from occurring when
<dt><a href="#question4">4. How can you prevent deadlock from occurring when
a thread must lock multiple mutexes?</a></dt>
<dt><a href="#question5">5. Don't noncopyable mutex semantics mean that a class
<dt><a href="#question5">5. Don't noncopyable mutex semantics mean that a class
with a mutex member will be noncopyable as well?</a></dt>
<dt><a href="#question6">6. How can you lock a mutex member in a const member
<dt><a href="#question6">6. How can you lock a mutex member in a const member
function (in order to implement the monitor pattern)?</a></dt>
<dt><a href="#question7">7. Why supply condition variables rather than event
<dt><a href="#question7">7. Why supply condition variables rather than event
variables?</a></dt>
<dt><a href="#question8">8. Why isn't thread cancellation or termination provided?</a></dt>
<dt><a href="#question9">9. Is it safe for threads to share automatic storage
<dt><a href="#question9">9. Is it safe for threads to share automatic storage
duration (stack) objects via pointers or references?</a></dt>
<dt><a href="#question10">10. Why has class semaphore disappeared?</a></dt>
</dl>
<h2><a name="question1"></a>1. Are lock objects <a href="definitions.html#definition-thread-safe">
<h2><a name="question1"></a>1. Are lock objects <a href="definitions.html#definition-thread-safe">
thread safe</a>?</h2>
<p><b>No!</b> Lock objects are not meant to be shared between threads. They are
meant to be short-lived objects created on automatic storage within a code block.
Any other usage is just likely to lead to errors and won&#39;t really be of
<p><b>No!</b> Lock objects are not meant to be shared between threads. They are
meant to be short-lived objects created on automatic storage within a code block.
Any other usage is just likely to lead to errors and won&#39;t really be of
actual benefit any way. Share <a href=
"mutex_concept.html">mutexes</a>, not locks. For more information see
the <a href="rationale.html#lock_objects">rationale</a> behind the design for
"mutex_concept.html">mutexes</a>, not locks. For more information see
the <a href="rationale.html#lock_objects">rationale</a> behind the design for
lock objects.</p>
<h2><a name="question2a"></a>2a. Why was <b>Boost.Threads</b> modeled after (specific
<h2><a name="question2a"></a>2a. Why was <b>Boost.Threads</b> modeled after (specific
library name)?</h2>
<p>It wasn&#39;t. Boost.Threads was designed from scratch. Extensive design discussions
involved numerous people representing a wide range of experience across many
platforms. To ensure portability, the initial implements were done in parallel
using POSIX Threads and the Win32 threading API. But the Boost.Threads design
<p>It wasn&#39;t. Boost.Threads was designed from scratch. Extensive design discussions
involved numerous people representing a wide range of experience across many
platforms. To ensure portability, the initial implements were done in parallel
using POSIX Threads and the Win32 threading API. But the Boost.Threads design
is very much in the spirit of C++, and thus doesn&#39;t model such C based APIs.</p>
<h2><a name="question2b"></a>2b. Why wasn&#39;t Boost.Threads modeled after (specific
<h2><a name="question2b"></a>2b. Why wasn&#39;t Boost.Threads modeled after (specific
library name)?</h2>
<p>Existing C++ libraries either seemed dangerous (often failing to take advantage
of prior art to reduce errors) or had excessive dependencies on library components
unrelated to threading. Existing C libraries couldn&#39;t meet our C++ requirements,
and were also missing certain features. For instance, the WIN32 thread API lacks
condition variables, even though these are critical for the important Monitor
<p>Existing C++ libraries either seemed dangerous (often failing to take advantage
of prior art to reduce errors) or had excessive dependencies on library components
unrelated to threading. Existing C libraries couldn&#39;t meet our C++ requirements,
and were also missing certain features. For instance, the WIN32 thread API lacks
condition variables, even though these are critical for the important Monitor
pattern <a href="bibliography.html#Schmidt-00">[Schmidt 00]</a>.</p>
<h2><a name="question3"></a>3. Why do <a href="mutex_concept.html">Mutexes</a>
<h2><a name="question3"></a>3. Why do <a href="mutex_concept.html">Mutexes</a>
have noncopyable semantics?</h2>
<p>To ensure that <a href="definitions.html#Deadlock">deadlocks</a> don&#39;t
occur. The only logical form of copy would be to use some sort of shallow copy
semantics in which multiple mutex objects could refer to the same mutex state.
This means that if ObjA has a mutex object as part of its state and ObjB is
copy constructed from it, then when ObjB::foo() locks the mutex it has effectively
locked ObjA as well. This behavior can result in deadlock. Other copy semantics
result in similar problems (if you think you can prove this to be wrong then
<p>To ensure that <a href="definitions.html#Deadlock">deadlocks</a> don&#39;t
occur. The only logical form of copy would be to use some sort of shallow copy
semantics in which multiple mutex objects could refer to the same mutex state.
This means that if ObjA has a mutex object as part of its state and ObjB is
copy constructed from it, then when ObjB::foo() locks the mutex it has effectively
locked ObjA as well. This behavior can result in deadlock. Other copy semantics
result in similar problems (if you think you can prove this to be wrong then
supply us with an alternative and we&#39;ll reconsider).</p>
<h2><a name="question4"></a>4. How can you prevent <a href="definitions.html#Deadlock">
<h2><a name="question4"></a>4. How can you prevent <a href="definitions.html#Deadlock">
deadlock</a> from occurring when a thread must lock multiple mutexes?</h2>
<p>Always lock them in the same order. One easy way of doing this is to use each
mutex&#39;s address to determine the order in which they are locked. A future
<p>Always lock them in the same order. One easy way of doing this is to use each
mutex&#39;s address to determine the order in which they are locked. A future
Boost.Threads concept may wrap this pattern up in a reusable class.</p>
<h2><a name="question5"></a>5. Don&#39;t noncopyable <a href="mutex_concept.html">mutex</a>
<h2><a name="question5"></a>5. Don&#39;t noncopyable <a href="mutex_concept.html">mutex</a>
semantics mean that a class with a mutex member will be noncopyable as well?</h2>
<p>No, but what it does mean is that the compiler can&#39;t generate a copy constructor
and assignment operator, so they will have to be coded explicitly. This is a
<b>good thing</b>, however, since the compiler generated operations would not
<p>No, but what it does mean is that the compiler can&#39;t generate a copy constructor
and assignment operator, so they will have to be coded explicitly. This is a
<b>good thing</b>, however, since the compiler generated operations would not
be <a href=
"definitions.html#Thread-safe">thread-safe</a>. The following is a simple
example of a class with copyable semantics and internal synchronization through
"definitions.html#Thread-safe">thread-safe</a>. The following is a simple
example of a class with copyable semantics and internal synchronization through
a mutex member.</p>
<pre>
class counter
@@ -96,7 +96,7 @@ public:
: m_value(initial_value)
{
}
// We only need to synchronize other for the same reason we don't have to
// synchronize on construction!
counter(const counter&amp; other)
@@ -104,20 +104,20 @@ public:
boost::mutex::scoped_lock scoped_lock(other.m_mutex);
m_value = other.m_value;
}
// For assignment we need to synchronize both objects!
const counter&amp; operator=(const counter&amp; other)
{
if (this == &amp;other)
return *this;
boost::mutex::scoped_lock lock1(&amp;m_mutex &lt; &amp;other.m_mutex ? m_mutex : other.m_mutex);
boost::mutex::scoped_lock lock2(&amp;m_mutex &gt; &amp;other.m_mutex ? m_mutex : other.m_mutex);
m_value = other.m_value;
return *this;
}
int value() const
{
boost::mutex::scoped_lock scoped_lock(m_mutex);
@@ -128,56 +128,56 @@ public:
boost::mutex::scoped_lock scoped_lock(m_mutex);
return ++m_value;
}
private:
mutable boost::mutex m_mutex;
int m_value;
};
</pre>
<h2><a name="question6"></a>6. How can you lock a <a href="mutex_concept.html">mutex</a>
<h2><a name="question6"></a>6. How can you lock a <a href="mutex_concept.html">mutex</a>
member in a const member function, in order to implement the Monitor Pattern?</h2>
<p>The Monitor Pattern mutex <a href="bibliography.html#Schmidt-00"> [Schmidt
00]</a> should simply be declared as mutable. See the example code above. The
internal state of mutex types could have been made mutable, with all lock calls
made via const functions, but this does a poor job of documenting the actual
semantics (and in fact would be incorrect since the logical state of a locked
mutex clearly differs from the logical state of an unlocked mutex). Declaring
<p>The Monitor Pattern mutex <a href="bibliography.html#Schmidt-00"> [Schmidt
00]</a> should simply be declared as mutable. See the example code above. The
internal state of mutex types could have been made mutable, with all lock calls
made via const functions, but this does a poor job of documenting the actual
semantics (and in fact would be incorrect since the logical state of a locked
mutex clearly differs from the logical state of an unlocked mutex). Declaring
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>
<p>Condition variables result in user code much less prone to <a href=
"definitions.html#Race condition">race conditions</a> than event variables.
See <a href="rationale.html#Events">Rationale</a> for analysis. Also see <a href="bibliography.html#Hoare-74">[Hoare
"definitions.html#Race condition">race conditions</a> than event variables.
See <a href="rationale.html#Events">Rationale</a> for analysis. Also see <a href="bibliography.html#Hoare-74">[Hoare
74]</a> and <a href="bibliography.html#Schmidt-00">[Schmidt 00]</a>.</p>
<h2><a name="question8"></a>8. Why isn&#39;t thread cancellation or termination
<h2><a name="question8"></a>8. Why isn&#39;t thread cancellation or termination
provided?</h2>
<p>There&#39;s a valid need for thread termination, so at some point Boost.Threads
probably will include it, but only after we can find a truly safe (and portable)
<p>There&#39;s a valid need for thread termination, so at some point Boost.Threads
probably will include it, but only after we can find a truly safe (and portable)
mechanism for this concept.</p>
<h2><a name="question9"></a>9. Is it safe for threads to share automatic storage
<h2><a name="question9"></a>9. Is it safe for threads to share automatic storage
duration (stack) objects via pointers or references?</h2>
<p>Only if you can guarantee that the lifetime of the stack object will not end
while other threads might still access the object. Thus the safest practice
is to avoid sharing stack objects, particularly in designs where threads are
created and destroyed dynamically. Restrict sharing of stack objects to simple
designs with very clear and unchanging function and thread lifetimes. (Suggested
<p>Only if you can guarantee that the lifetime of the stack object will not end
while other threads might still access the object. Thus the safest practice
is to avoid sharing stack objects, particularly in designs where threads are
created and destroyed dynamically. Restrict sharing of stack objects to simple
designs with very clear and unchanging function and thread lifetimes. (Suggested
by Darryl Green).</p>
<h2><a name="question10"></a>10. Why has class semaphore disappeared?</h2>
<p>Semaphore was removed as too error prone. The same effect can be achieved with
<p>Semaphore was removed as too error prone. The same effect can be achieved with
greater safety by the combination of a mutex and a condition variable.</p>
<hr>
<p>Revised
<p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
05 November, 2001
05 November, 2001
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p>
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
All Rights Reserved.</i></p>
<p>Permission to use, copy, modify, distribute and sell this software and its
documentation for any purpose is hereby granted without fee, provided that the
above copyright notice appear in all copies and that both that copyright notice
and this permission notice appear in supporting documentation. William E. Kempf
makes no representations about the suitability of this software for any purpose.
<p>Permission to use, copy, modify, distribute and sell this software and its
documentation for any purpose is hereby granted without fee, provided that the
above copyright notice appear in all copies and that both that copyright notice
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 &quot;as is&quot; without express or implied warranty.</p>
</body>
</html>

View File

@@ -7,11 +7,11 @@
<body link="#0000ff" vlink="#800080">
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
"header">
<tr>
<td valign="top" width="300">
<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">
<td valign="top">
<h1 align="center">Boost.Threads</h1>
<h2 align="center">Index</h2>
</td>
@@ -19,117 +19,125 @@
</table>
<hr>
<h2>Contents</h2>
<dl class="index">
<dl class="index">
<dt><a href="overview.html">Overview</a></dt>
<dt><a href="mutex_concept.html">Mutex Concepts</a></dt>
<dl class="index">
<dl class="index">
<dt><a href="mutex_concept.html#Mutex">Mutex</a></dt>
<dt><a href="mutex_concept.html#TryMutex">TryMutex</a></dt>
<dt><a href="mutex_concept.html#TimedMutex">TimedMutex</a></dt>
</dl>
<dt><a href="lock_concept.html">Lock Concepts</a></dt>
<dl class="index">
<dl class="index">
<dt><a href="lock_concept.html#Lock">Lock</a></dt>
<dt><a href="lock_concept.html#ScopedLock">ScopedLock</a></dt>
<dt><a href="lock_concept.html#ScopedTryLock">ScopedTryLock</a></dt>
<dt><a href="lock_concept.html#ScopedTimedLock">ScopedTimedLock</a></dt>
</dl>
<dt>Reference</dt>
<dl class="index">
<dl class="index">
<dt><a href="barrier.html"><code>&lt;boost/thread/barrier.hpp&gt;</code></a></dt>
<dl class="index">
<dt><a href="barrier.html#classes">Classes</a></dt>
<dl class="index">
<dt><a href="barrier.html#class-barrier"><code>barrier</code></a></dt>
</dl>
</dl>
<dt><a href="condition.html"><code>&lt;boost/thread/condition.hpp&gt;</code></a></dt>
<dl class="index">
<dl class="index">
<dt><a href="condition.html#classes">Classes</a></dt>
<dl class="index">
<dl class="index">
<dt><a href="condition.html#class-condition"><code>condition</code></a></dt>
</dl>
</dl>
</dl>
<dl class="index">
<dl class="index">
<dt><a href="exceptions.html"><code>&lt;boost/thread/exceptions.hpp&gt;</code></a></dt>
<dl class="index">
<dl class="index">
<dt><a href="exceptions.html#classes">Classes</a></dt>
<dl class="index">
<dl class="index">
<dt><a href="exceptions.html#class-lock_error"><code>lock_error</code></a></dt>
<dt><a href="exceptions.html#class-thread_resource_error"><code>thread_resource_error</code></a></dt>
</dl>
</dl>
</dl>
<dl class="index">
<dl class="index">
<dt><a href="mutex.html"><code>&lt;boost/thread/mutex.hpp&gt;</code></a></dt>
<dl class="index">
<dl class="index">
<dt><a href="mutex.html#classes">Classes</a></dt>
<dl class="index">
<dl class="index">
<dt><a href="mutex.html#class-mutex"><code>mutex</code></a></dt>
<dt><a href="mutex.html#class-try_mutex"><code>try_mutex</code></a></dt>
<dt><a href="mutex.html#class-timed_mutex"><code>timed_mutex</code></a></dt>
</dl>
</dl>
</dl>
<dl class="index">
<dl class="index">
<dt><a href="once.html"><code>&lt;boost/thread/once.hpp&gt;</code></a></dt>
<dl class="index">
<dl class="index">
<dt><a href="once.html#macros">Macros</a></dt>
<dl class="index">
<dl class="index">
<dt><a href="once.html#macro-BOOST_ONCE_INIT"><code>BOOST_ONCE_INIT</code></a></dt>
</dl>
<dt><a href="once.html#types">Types</a></dt>
<dl class="index">
<dl class="index">
<dt><a href="once.html#type-once_flag"><code>once_flag</code></a></dt>
</dl>
<dt><a href="once.html#functions">Functions</a></dt>
<dl class="index">
<dl class="index">
<dt><a href="once.html#function-call_once"><code>call_once</code></a></dt>
</dl>
</dl>
</dl>
<dl class="index">
<dl class="index">
<dt><a href="recursive_mutex.html"><code>&lt;boost/thread/recursive_mutex.hpp&gt;</code></a></dt>
<dl class="index">
<dl class="index">
<dt><a href="recursive_mutex.html#classes">Classes</a></dt>
<dl class="index">
<dl class="index">
<dt><a href="recursive_mutex.html#class-recursive_mutex"><code>recursive_mutex</code></a></dt>
<dt><a href="recursive_mutex.html#class-recursive_try_mutex"><code>recursive_try_mutex</code></a></dt>
<dt><a href="recursive_mutex.html#class-recursive_timed_mutex"><code>recursive_timed_mutex</code></a></dt>
</dl>
</dl>
</dl>
<dl class="index">
<dl class="index">
<dt><a href="thread.html"><code>&lt;boost/thread/thread.hpp&gt;</code></a></dt>
<dl class="index">
<dl class="index">
<dt><a href="thread.html#classes">Classes</a></dt>
<dl class="index">
<dl class="index">
<dt><a href="thread.html#class-thread"><code>thread</code></a></dt>
<dt><a href="thread.html#class-thread_group"><code>thread_group</code></a></dt>
</dl>
</dl>
</dl>
<dl class="index">
<dl class="index">
<dt><a href="tss.html"><code>&lt;boost/thread/tss.hpp&gt;</code></a></dt>
<dl class="index">
<dl class="index">
<dt><a href="tss.html#classes">Classes</a></dt>
<dl class="index">
<dl class="index">
<dt><a href="tss.html#class-thread_specific_ptr"><code>thread_specific_ptr</code></a></dt>
</dl>
</dl>
</dl>
<dl class="index">
<dl class="index">
<dt><a href="xtime.html"><code>&lt;boost/thread/xtime.hpp&gt;</code></a></dt>
<dl class="index">
<dl class="index">
<dt><a href="xtime.html#values">Values</a></dt>
<dl class="page-index">
<dl class="page-index">
<dt><a href="xtime.html#value-spec"><code>TIME_UTC</code></a></dt>
</dl>
<dt><a href="xtime.html#classes">Classes</a></dt>
<dl class="page-index">
<dl class="page-index">
<dt><a href="xtime.html#class-xtime"><code>xtime</code></a></dt>
</dl>
<dt><a href="xtime.html#functions">Functions</a></dt>
<dl class="page-index">
<dl class="page-index">
<dt><a href="xtime.html#function-xtime_get"><code>xtime_get</code></a></dt>
</dl>
</dl>
</dl>
<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="rationale.html">Rationale</a></dt>
<dt><a href="definitions.html">Definitions</a></dt>
@@ -138,18 +146,18 @@
<dt><a href="acknowledgments.html">Acknowledgments</a></dt>
</dl>
<hr>
<p>Revised
<p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
05 November, 2001
05 November, 2001
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p>
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
All Rights Reserved.</i></p>
<p>Permission to use, copy, modify, distribute and sell this software and its
documentation for any purpose is hereby granted without fee, provided that the
above copyright notice appear in all copies and that both that copyright notice
and this permission notice appear in supporting documentation. William E. Kempf
makes no representations about the suitability of this software for any purpose.
<p>Permission to use, copy, modify, distribute and sell this software and its
documentation for any purpose is hereby granted without fee, provided that the
above copyright notice appear in all copies and that both that copyright notice
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 &quot;as is&quot; without express or implied warranty.</p>
</body>
</html>

View File

@@ -7,153 +7,153 @@
<body link="#0000ff" vlink="#800080">
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
"header">
<tr>
<td valign="top" width="300">
<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">
<td valign="top">
<h1 align="center">Boost.Threads</h1>
<h2 align="center">Introduction to Design</h2>
</td>
</tr>
</table>
<hr>
<dl class="page-index">
<dl class="page-index">
<dt><a href="#motivation">Motivation</a></dt>
<dt><a href="#goals">Goals</a></dt>
<dt><a href="#phases">Iterative Phases</a></dt>
<dl class="page-index">
<dl class="page-index">
<dt><a href="#phase1">Phase 1, Synchronization Primitives</a></dt>
<dt><a href="#phase2">Phase 2, Thread Management and Thread Specific Storage</a></dt>
<dt><a href="#next-phase">The Next Phase</a></dt>
</dl>
</dl>
<h2><a name="motivation"></a>Motivation</h2>
<p>With client/server and three-tier architectures becoming common place in today&#39;s
world, it&#39;s becoming increasingly important for programs to be able to handle
parallel processing. Modern day operating systems usually provide some support
for this through native thread APIs. Unfortunately, writing portable code that
makes use of parallel processing in C++ is made very difficult by a lack of
a standard interface for these native APIs. Further, these APIs are almost universally
C APIs and fail to take advantage of C++&#39;s strengths, or to address C++&#39;s
<p>With client/server and three-tier architectures becoming common place in today&#39;s
world, it&#39;s becoming increasingly important for programs to be able to handle
parallel processing. Modern day operating systems usually provide some support
for this through native thread APIs. Unfortunately, writing portable code that
makes use of parallel processing in C++ is made very difficult by a lack of
a standard interface for these native APIs. Further, these APIs are almost universally
C APIs and fail to take advantage of C++&#39;s strengths, or to address C++&#39;s
issues.</p>
<p>The <b>Boost.Threads</b> library is an attempt to define a portable interface
<p>The <b>Boost.Threads</b> library is an attempt to define a portable interface
for writing parallel processes in C++.</p>
<h2><a name="goals"></a>Goals</h2>
<p>The <b>Boost.Threads</b> library has several goals that should help to set
it apart from other solutions. These goals are listed in order of precedence
<p>The <b>Boost.Threads</b> library has several goals that should help to set
it apart from other solutions. These goals are listed in order of precedence
with full descriptions below.</p>
<ul>
<li> <b>Portability</b>
<p><b>Boost.Threads</b> was designed to be highly portable. The goal is for
the interface to be easily implemented on any platform that supports threads,
<li> <b>Portability</b>
<p><b>Boost.Threads</b> was designed to be highly portable. The goal is for
the interface to be easily implemented on any platform that supports threads,
and possibly even on platforms without native thread support.</p>
</li>
<li> <b>Safety</b>
<p><b>Boost.Threads</b> was designed to be as safe as possible. Writing <a href="definitions.html#Thread-safe">thread-safe</a>
code is very difficult and successful libraries must strive to insulate
the programmer from dangerous constructs as much as possible. This is accomplished
<li> <b>Safety</b>
<p><b>Boost.Threads</b> was designed to be as safe as possible. Writing <a href="definitions.html#Thread-safe">thread-safe</a>
code is very difficult and successful libraries must strive to insulate
the programmer from dangerous constructs as much as possible. This is accomplished
in several ways:</p>
<ul>
<li>
<p align="left">C++ language features are used make correct usage easy
(if possible, the default) and error-prone impossible or at least more
difficult. For example, see the <a href="mutex_concept.html">Mutex</a>
and <a href="lock_concept.html">Lock</a> designs, and how note how they
<li>
<p align="left">C++ language features are used make correct usage easy
(if possible, the default) and error-prone impossible or at least more
difficult. For example, see the <a href="mutex_concept.html">Mutex</a>
and <a href="lock_concept.html">Lock</a> designs, and how note how they
interact.</p>
</li>
<li>
<p align="left">Certain traditional concurrent programming features are
considered so error-prone that they are not provided at all. For example,
<li>
<p align="left">Certain traditional concurrent programming features are
considered so error-prone that they are not provided at all. For example,
see the <a
href="rationale.html#Events">Events Not Provided</a> rationale.</p>
</li>
<li>
<p align="left">Dangerous features, or features which may be misused,
are identified as such in the documentation to make users aware of potential
<li>
<p align="left">Dangerous features, or features which may be misused,
are identified as such in the documentation to make users aware of potential
pitfalls.</p>
</li>
</ul>
</li>
<li> <b>Flexibility</b>
<p><b>Boost.Threads</b> was designed to be flexible. This goal is often at
odds with <i>safety</i>. When functionality might be compromised by the
desire to keep the interface safe, <b> Boost.Threads</b> has been designed
to provide the functionality, but to make it&#39;s use prohibitive for general
use. In other words, the interfaces have been designed such that it's usually
obvious when something is unsafe, and the documentation is written to explain
<li> <b>Flexibility</b>
<p><b>Boost.Threads</b> was designed to be flexible. This goal is often at
odds with <i>safety</i>. When functionality might be compromised by the
desire to keep the interface safe, <b> Boost.Threads</b> has been designed
to provide the functionality, but to make it&#39;s use prohibitive for general
use. In other words, the interfaces have been designed such that it's usually
obvious when something is unsafe, and the documentation is written to explain
why.</p>
</li>
<li> <b>Efficiency</b>
<p><b>Boost.Threads</b> was designed to be as efficient as possible. When
building a library on top of another library there is always a danger that
the result will be so much slower than the &quot;native&quot; API that programmers
are inclined to ignore the higher level API. <b>Boost.Threads</b> was designed
to minimize the chances of this occurring. The interfaces have been crafted
to allow an implementation the greatest chance of being as efficient as
possible. This goal is often at odds with the goal for <i>safety</i>. Every
effort was made to ensure efficient implementations, but when in conflict
<li> <b>Efficiency</b>
<p><b>Boost.Threads</b> was designed to be as efficient as possible. When
building a library on top of another library there is always a danger that
the result will be so much slower than the &quot;native&quot; API that programmers
are inclined to ignore the higher level API. <b>Boost.Threads</b> was designed
to minimize the chances of this occurring. The interfaces have been crafted
to allow an implementation the greatest chance of being as efficient as
possible. This goal is often at odds with the goal for <i>safety</i>. Every
effort was made to ensure efficient implementations, but when in conflict
<i>safety</i> has always taken precedence.</p>
</li>
</ul>
<h2><a name="phases"></a>Iterative Phases</h2>
<p>Another goal of <b>Boost.Threads</b> was to take a dynamic, iterative approach
in its development. The computing industry is still exploring the concepts of
parallel programming. Most thread libraries supply only simple primitive concepts
for thread synchronization. These concepts are very simple, but they are very
difficult to use safely or to provide formal proofs for constructs built on
top of them. There has been a lot of research in other concepts, such as in
&quot;Communicating Sequential Processes.&quot; <b>Boost.Threads</b> was designed
in iterative steps, providing the building blocks necessary for the next step,
and giving the researcher the tools necessary to explore new concepts in a portable
<p>Another goal of <b>Boost.Threads</b> was to take a dynamic, iterative approach
in its development. The computing industry is still exploring the concepts of
parallel programming. Most thread libraries supply only simple primitive concepts
for thread synchronization. These concepts are very simple, but they are very
difficult to use safely or to provide formal proofs for constructs built on
top of them. There has been a lot of research in other concepts, such as in
&quot;Communicating Sequential Processes.&quot; <b>Boost.Threads</b> was designed
in iterative steps, providing the building blocks necessary for the next step,
and giving the researcher the tools necessary to explore new concepts in a portable
manner.</p>
<p>Given the goal of following a dynamic, iterative approach <b> Boost.Threads</b>
shall go through several growth cycles. Each phase in its development shall
<p>Given the goal of following a dynamic, iterative approach <b> Boost.Threads</b>
shall go through several growth cycles. Each phase in its development shall
be roughly documented here.</p>
<h3><a name="phase1"></a>Phase 1, Synchronization Primitives</h3>
<p>Boost is all about providing high quality libraries with implementations for
many platforms. Unfortunately, there&#39;s a big problem faced by developers
wishing to supply such high quality libraries, namely thread-safety. The C++
standard doesn&#39;t address threads at all, but real world programs often make
use of native threading support. A portable library that doesn&#39;t address
the issue of thread-safety is there for not much help to a programmer who wants
to use the library in his multithreaded application. So there&#39;s a very great
need for portable primitives that will allow the library developer to create
<a href="definitions.html#Thread-safe"> thread-safe</a> implementations. This
<p>Boost is all about providing high quality libraries with implementations for
many platforms. Unfortunately, there&#39;s a big problem faced by developers
wishing to supply such high quality libraries, namely thread-safety. The C++
standard doesn&#39;t address threads at all, but real world programs often make
use of native threading support. A portable library that doesn&#39;t address
the issue of thread-safety is there for not much help to a programmer who wants
to use the library in his multithreaded application. So there&#39;s a very great
need for portable primitives that will allow the library developer to create
<a href="definitions.html#Thread-safe"> thread-safe</a> implementations. This
need far out weighs the need for portable methods to create and manage threads.</p>
<p>Because of this need, the first phase of <b>Boost.Threads</b> focuses solely
on providing portable primitive concepts for thread synchronization. Types provided
in this phase include the <a href="mutex.html"> mutex/try_mutex/timed_mutex</a>,
<a href="recursive_mutex.html"> recursive_mutex/recursive_try_mutex/recursive_timed_mutex</a>
and <a href="exceptions.html#class-lock_error">lock_error</a>. These are considered
the &quot;core&quot; synchronization primitives, though there are others that
<p>Because of this need, the first phase of <b>Boost.Threads</b> focuses solely
on providing portable primitive concepts for thread synchronization. Types provided
in this phase include the <a href="mutex.html"> mutex/try_mutex/timed_mutex</a>,
<a href="recursive_mutex.html"> recursive_mutex/recursive_try_mutex/recursive_timed_mutex</a>
and <a href="exceptions.html#class-lock_error">lock_error</a>. These are considered
the &quot;core&quot; synchronization primitives, though there are others that
will be added in later phases.</p>
<h3><a name="phase2"></a>Phase 2, Thread Management and Thread Specific Storage</h3>
<p>This phase addresses the creation and management of threads and provides a
mechanism for thread specific storage (data associated with a thread instance).
Thread management is a tricky issue in C++, so this phase addresses only the
basic needs of multithreaded program. Later phases are likely to add additional
functionality in this area. This phase of <b>Boost.Threads</b> adds the <a href="thread.html">thread</a>
and <a href="tss.html#class-thread_specific_ptr">thread_specific_ptr</a> types.
With these additions the <b>Boost.Threads</b> library can be considered minimal
<p>This phase addresses the creation and management of threads and provides a
mechanism for thread specific storage (data associated with a thread instance).
Thread management is a tricky issue in C++, so this phase addresses only the
basic needs of multithreaded program. Later phases are likely to add additional
functionality in this area. This phase of <b>Boost.Threads</b> adds the <a href="thread.html">thread</a>
and <a href="tss.html#class-thread_specific_ptr">thread_specific_ptr</a> types.
With these additions the <b>Boost.Threads</b> library can be considered minimal
but complete.</p>
<h3><a name="next-phase"></a>The Next Phase</h3>
<p>The next phase will address more advanced synchronization concepts, such as
<p>The next phase will address more advanced synchronization concepts, such as
read/write mutexes and barriers.</p>
<hr>
<hr>
<p>Revised
<p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
05 November, 2001
05 November, 2001
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p>
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
All Rights Reserved.</i></p>
<p>Permission to use, copy, modify, distribute and sell this software and its
documentation for any purpose is hereby granted without fee, provided that the
above copyright notice appear in all copies and that both that copyright notice
and this permission notice appear in supporting documentation. William E. Kempf
makes no representations about the suitability of this software for any purpose.
<p>Permission to use, copy, modify, distribute and sell this software and its
documentation for any purpose is hereby granted without fee, provided that the
above copyright notice appear in all copies and that both that copyright notice
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 &quot;as is&quot; without express or implied warranty.</p>
</body>
</html>

View File

@@ -7,21 +7,21 @@
<body link="#0000ff" vlink="#800080">
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
"header">
<tr>
<td valign="top" width="300">
<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">
<td valign="top">
<h1 align="center">Boost.Threads</h1>
<h2 align="center">ScopedLock Concept</h2>
</td>
</tr>
</table>
<hr>
<dl class="page-index">
<dl class="page-index">
<dt><a href="#introduction">Introduction</a></dt>
<dt><a href="#concept-requirements">Concept Requirements</a></dt>
<dl class="page-index">
<dl class="page-index">
<dt><a href="#Lock-concept">Lock Concept</a></dt>
<dt><a href="#ScopedLock-concept">ScopedLock Concept</a></dt>
<dt><a href="#ScopedTryLock-concept">ScopedTryLock Concept</a></dt>
@@ -29,166 +29,166 @@
</dl>
</dl>
<h2><a name="introduction"></a>Introduction</h2>
<p>A lock object provides a safe means for locking and unlocking a mutex object
(an object whose type is a model of <a href="mutex_concept.html">Mutex</a> or
one of its refinements). In other words they are an implementation of the <i>Scoped
Locking</i> <a href="bibliography.html#Schmidt-00">[Schmidt 00]</a> pattern.
The <a href="#ScopedLock-concept">ScopedLock</a> concept, with <a href="#ScopedTryLock-concept">ScopedTryLock</a>
and <a href="#ScopedTimedLock-concept">ScopedTimedLock</a> refinements, formalize
<p>A lock object provides a safe means for locking and unlocking a mutex object
(an object whose type is a model of <a href="mutex_concept.html">Mutex</a> or
one of its refinements). In other words they are an implementation of the <i>Scoped
Locking</i> <a href="bibliography.html#Schmidt-00">[Schmidt 00]</a> pattern.
The <a href="#ScopedLock-concept">ScopedLock</a> concept, with <a href="#ScopedTryLock-concept">ScopedTryLock</a>
and <a href="#ScopedTimedLock-concept">ScopedTimedLock</a> refinements, formalize
the requirements.</p>
<p>Lock objects are constructed with a reference to a mutex object and typically
acquire ownership of the mutex object by setting its state to locked. They also
ensure ownership is relinquished in the destructor. Lock objects also expose
functions to query the lock status and to manually lock and unlock the mutex
<p>Lock objects are constructed with a reference to a mutex object and typically
acquire ownership of the mutex object by setting its state to locked. They also
ensure ownership is relinquished in the destructor. Lock objects also expose
functions to query the lock status and to manually lock and unlock the mutex
object.</p>
<p>Lock objects are meant to be short lived, expected to be used at block scope
only. The lock objects are not <a href="definitions.html#definition-thread-safe">thread-safe</a>.
Lock objects must maintain state to indicate whether or not they&#39;ve been
locked and this state is not protected by any synchronization concepts. For
<p>Lock objects are meant to be short lived, expected to be used at block scope
only. The lock objects are not <a href="definitions.html#definition-thread-safe">thread-safe</a>.
Lock objects must maintain state to indicate whether or not they&#39;ve been
locked and this state is not protected by any synchronization concepts. For
this reason a lock object should never be shared between multiple threads.</p>
<h2><a name="concept-requirements"></a>Concept Requirements</h2>
<h3><a name="Lock-concept"></a>Lock Concept</h3>
<p>For a Lock type <code>L</code> and an object <code>lk</code> and const object
<code>clk</code> of that type, the following expressions must be well-formed
<p>For a Lock type <code>L</code> and an object <code>lk</code> and const object
<code>clk</code> of that type, the following expressions must be well-formed
and have the indicated effects.</p>
<table summary="Lock expressions" border="1" cellpadding="5">
<tr>
<tr>
<td><b>Expression</b></td>
<td><b>Effects</b></td>
</tr>
<tr>
<tr>
<td valign="top"><code>(&amp;lk)-&gt;~L();</code></td>
<td><code>if (locked()) unlock();</code></td>
</tr>
<tr>
<tr>
<td valign="top"><code>(&amp;clk)-&gt;operator const void*()</code></td>
<td>Returns type void*, non-zero if if the associated mutex object has been
<td>Returns type void*, non-zero if if the associated mutex object has been
locked by <code>clk</code>, otherwise 0.</td>
</tr>
<tr>
<tr>
<td valign="top"><code>clk.locked()</code></td>
<td>Returns a <code>bool</code>, <code>(&amp;clk)-&gt;operator const void*()
<td>Returns a <code>bool</code>, <code>(&amp;clk)-&gt;operator const void*()
!= 0</code></td>
</tr>
<tr>
<tr>
<td valign="top"><code>lk.lock()</code></td>
<td>Throws <code>lock_error</code> if <code>locked()</code>. If the associated
mutex object is already locked by some other thread, places the current
thread in the <a href="definitions.html#State">Blocked</a> state until the
associated mutex is unlocked, after which the current thread is placed in
the <a href="definitions.html#State"> Ready</a> state, eventually to be
returned to the <a href="definitions.html#State">Running</a> state. If the
associated mutex object is already locked by the same thread the behavior
is dependent on the <a href="mutex_concept.html#locking-strategies">locking
<td>Throws <code>lock_error</code> if <code>locked()</code>. If the associated
mutex object is already locked by some other thread, places the current
thread in the <a href="definitions.html#State">Blocked</a> state until the
associated mutex is unlocked, after which the current thread is placed in
the <a href="definitions.html#State"> Ready</a> state, eventually to be
returned to the <a href="definitions.html#State">Running</a> state. If the
associated mutex object is already locked by the same thread the behavior
is dependent on the <a href="mutex_concept.html#locking-strategies">locking
strategy</a> of the associated mutex object.<br>
Postcondition: <code>locked() == true</code></td>
</tr>
<tr>
<tr>
<td valign="top"><code>lk.unlock()</code></td>
<td>If <code>!locked()</code>, throws <code>lock_error</code>, otherwise unlocks
<td>If <code>!locked()</code>, throws <code>lock_error</code>, otherwise unlocks
the associated mutex.<br>
Postcondition: <code>!locked()</code></td>
</tr>
</table>
<h3><a name="ScopedLock-concept"></a>ScopedLock Concept</h3>
<p>A ScopedLock is a refinement of <a href="#Lock">Lock</a>. For a ScopedLock
type <code>L</code> and an object <code>lk</code> of that type, and an object
<code>m</code> of a type meeting the <a href="mutex_concept.html#Mutex-concept">Mutex</a>
requirements, and an object <code>b</code> of type <code>bool</code>, the following
<p>A ScopedLock is a refinement of <a href="#Lock">Lock</a>. For a ScopedLock
type <code>L</code> and an object <code>lk</code> of that type, and an object
<code>m</code> of a type meeting the <a href="mutex_concept.html#Mutex-concept">Mutex</a>
requirements, and an object <code>b</code> of type <code>bool</code>, the following
expressions must be well-formed and have the indicated effects.</p>
<table summary="ScopedLock expressions" border="1" cellpadding="5">
<tr>
<tr>
<td><b>Expression</b></td>
<td><b>Effects</b></td>
</tr>
<tr>
<tr>
<td valign="top"><code>L lk(m);</code></td>
<td>Constructs an object <code>lk</code>, and associates mutex object <code>m</code>
<td>Constructs an object <code>lk</code>, and associates mutex object <code>m</code>
with it, then calls <code>lock()</code></td>
</tr>
<tr>
<tr>
<td valign="top"><code>L lk(m,b);</code></td>
<td>Constructs an object <code>lk</code>, and associates mutex object <code>m</code>
<td>Constructs an object <code>lk</code>, and associates mutex object <code>m</code>
with it, then if <code>b</code>, calls <code>lock()</code></td>
</tr>
</table>
<h3><a name="ScopedTryLock-concept"></a>ScopedTryLock Concept</h3>
<p>A ScopedTryLock is a refinement of <a href="#Lock-concept">Lock</a>. For a
ScopedTryLock type <code>L</code> and an object <code>lk</code> of that type,
and an object <code>m</code> of a type meeting the <a href="mutex_concept.html#TryMutex-concept">TryMutex</a>
requirements, and an object <code>b</code> of type <code>bool</code>, the following
<p>A ScopedTryLock is a refinement of <a href="#Lock-concept">Lock</a>. For a
ScopedTryLock type <code>L</code> and an object <code>lk</code> of that type,
and an object <code>m</code> of a type meeting the <a href="mutex_concept.html#TryMutex-concept">TryMutex</a>
requirements, and an object <code>b</code> of type <code>bool</code>, the following
expressions must be well-formed and have the indicated effects.</p>
<table summary="ScopedTryLock expressions" border="1" cellpadding="5">
<tr>
<tr>
<td><b>Expression</b></td>
<td><b>Effects</b></td>
</tr>
<tr>
<tr>
<td valign="top"><code>L lk(m);</code></td>
<td>Constructs an object <code>lk</code>, and associates mutex object <code>m</code>
<td>Constructs an object <code>lk</code>, and associates mutex object <code>m</code>
with it, then calls <code>try_lock()</code></td>
</tr>
<tr>
<tr>
<td valign="top"><code>L lk(m,b);</code></td>
<td>Constructs an object <code>lk</code>, and associates mutex object <code>m</code>
<td>Constructs an object <code>lk</code>, and associates mutex object <code>m</code>
with it, then if <code>b</code>, calls <code> lock()</code></td>
</tr>
<tr>
<tr>
<td valign="top"><code>lk.try_lock()</code></td>
<td>If locked(), throws <code>lock_error</code>. Makes a non-blocking attempt
to lock the associated mutex object, returning <code>true</code> if the
lock attempt is successful, otherwise <code>false</code>. If the associated
mutex object is already locked by the same thread the behavior is dependent
on the <a href="mutex_concept.html#locking-strategies">locking strategy</a>
<td>If locked(), throws <code>lock_error</code>. Makes a non-blocking attempt
to lock the associated mutex object, returning <code>true</code> if the
lock attempt is successful, otherwise <code>false</code>. If the associated
mutex object is already locked by the same thread the behavior is dependent
on the <a href="mutex_concept.html#locking-strategies">locking strategy</a>
of the associated mutex object.</td>
</tr>
</table>
<h3><a name="ScopedTimedLock-concept"></a>ScopedTimedLock Concept</h3>
<p>A ScopedTimedLock is a refinement of <a href="#Lock">Lock</a>. For a ScopedTimedLock
type <code>L</code> and an object <code>lk</code> of that type, and an object
<code>m</code> of a type meeting the <a href="mutex_concept.html#TimedMutex">TimedMutex</a>
requirements, and an object <code>b</code> of type <code>bool</code>, and an
object <code>t</code> of type <code><a href="xtime.html"> xtime</a></code>,
<p>A ScopedTimedLock is a refinement of <a href="#Lock">Lock</a>. For a ScopedTimedLock
type <code>L</code> and an object <code>lk</code> of that type, and an object
<code>m</code> of a type meeting the <a href="mutex_concept.html#TimedMutex">TimedMutex</a>
requirements, and an object <code>b</code> of type <code>bool</code>, and an
object <code>t</code> of type <code><a href="xtime.html"> xtime</a></code>,
the following expressions must be well-formed and have the indicated effects.</p>
<table summary="ScopedTimedLock expressions" border="1" cellpadding=
"5">
<tr>
<tr>
<td><b>Expression</b></td>
<td><b>Effects</b></td>
</tr>
<tr>
<tr>
<td valign="top"><code>L lk(m,t);</code></td>
<td>Constructs an object <code>lk</code>, and associates mutex object <code>m</code>
<td>Constructs an object <code>lk</code>, and associates mutex object <code>m</code>
with it, then calls <code> timed_lock(t)</code></td>
</tr>
<tr>
<tr>
<td valign="top"><code>L lk(m,b);</code></td>
<td>Constructs an object <code>lk</code>, and associates mutex object <code>m</code>
<td>Constructs an object <code>lk</code>, and associates mutex object <code>m</code>
with it, then if <code>b</code>, calls <code> lock()</code></td>
</tr>
<tr>
<tr>
<td valign="top"><code>lk.timed_lock(t)</code></td>
<td>If locked(), throws lock_error. Makes a blocking attempt to lock the associated
mutex object, and returns <code>true</code> if successful within the specified
time <code>t</code>, otherwise <code>false</code>. If the associated mutex
object is already locked by the same thread the behavior is dependent on
the <a href="mutex_concept.html#locking-strategies">locking strategy</a>
<td>If locked(), throws lock_error. Makes a blocking attempt to lock the associated
mutex object, and returns <code>true</code> if successful within the specified
time <code>t</code>, otherwise <code>false</code>. If the associated mutex
object is already locked by the same thread the behavior is dependent on
the <a href="mutex_concept.html#locking-strategies">locking strategy</a>
of the associated mutex object.</td>
</tr>
</table>
<hr>
<p>Revised
<p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
05 November, 2001
05 November, 2001
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p>
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
All Rights Reserved.</i></p>
<p>Permission to use, copy, modify, distribute and sell this software and its
documentation for any purpose is hereby granted without fee, provided that the
above copyright notice appear in all copies and that both that copyright notice
and this permission notice appear in supporting documentation. William E. Kempf
makes no representations about the suitability of this software for any purpose.
<p>Permission to use, copy, modify, distribute and sell this software and its
documentation for any purpose is hereby granted without fee, provided that the
above copyright notice appear in all copies and that both that copyright notice
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 &quot;as is&quot; without express or implied warranty.</p>
</body>
</html>

View File

@@ -7,11 +7,11 @@
<body link="#0000ff" vlink="#800080">
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
"header">
<tr>
<td valign="top" width="300">
<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">
<td valign="top">
<h1 align="center">Boost.Threads</h1>
<h2 align="center">Header &lt;<a href="../../../boost/thread/mutex.hpp">boost/thread/mutex.hpp</a>&gt;</h2>
</td>
@@ -19,31 +19,31 @@
</table>
<hr>
<h2>Contents</h2>
<dl class="page-index">
<dl class="page-index">
<dt><a href="#introduction">Introduction</a></dt>
<dt><a href="#classes">Classes</a></dt>
<dl class="page-index">
<dl class="page-index">
<dt><a href="#class-mutex">Class <code>mutex</code></a></dt>
<dl class="page-index">
<dl class="page-index">
<dt><a href="#class-mutex-synopsis">Class <code>mutex</code> synopsis</a></dt>
<dt><a href="#class-mutex-ctors">Class <code>mutex</code> constructors and
<dt><a href="#class-mutex-ctors">Class <code>mutex</code> constructors and
destructor</a></dt>
</dl>
</dl>
<dl class="page-index">
<dl class="page-index">
<dt><a href="#class-try_mutex">Class <code>try_mutex</code></a></dt>
<dl class="page-index">
<dl class="page-index">
<dt><a href="#class-try_mutex-synopsis">Class <code>try_mutex</code> synopsis</a></dt>
<dt><a href="#class-try_mutex-ctors">Class <code>try_mutex</code> constructors
<dt><a href="#class-try_mutex-ctors">Class <code>try_mutex</code> constructors
and destructor</a></dt>
</dl>
</dl>
<dl class="page-index">
<dl class="page-index">
<dt><a href="#class-timed_mutex">Class <code>timed_mutex</code></a></dt>
<dl class="page-index">
<dt><a href="#class-timed_mutex-synopsis">Class <code>timed_mutex</code>
<dl class="page-index">
<dt><a href="#class-timed_mutex-synopsis">Class <code>timed_mutex</code>
synopsis</a></dt>
<dt><a href="#class-timed_mutex-ctors">Class <code>timed_mutex</code> constructors
<dt><a href="#class-timed_mutex-ctors">Class <code>timed_mutex</code> constructors
and destructor</a></dt>
</dl>
</dl>
@@ -57,35 +57,35 @@
"#timed_mutex Synopsis">timed_mutex</a></code> classes.</p>
<p>The <code><a href="#mutex Synopsis">mutex</a></code>, <code><a href=
"#try_mutex Synopsis">try_mutex</a></code> and <code><a href=
"#timed_mutex Synopsis">timed_mutex</a></code> classes are models of <a href="mutex_concept.html#Mutex-concept">Mutex</a>,
<a href="mutex_concept.html#TryMutex-concept">TryMutex</a>, and <a href="mutex_concept.html#TimedMutex-concept">TimedMutex</a>
respectively. These types should be used to non-recursively synchronize access
to shared resources. For recursive locking mechanics, see the <a href="recursive_mutex.html">recursive
"#timed_mutex Synopsis">timed_mutex</a></code> classes are models of <a href="mutex_concept.html#Mutex-concept">Mutex</a>,
<a href="mutex_concept.html#TryMutex-concept">TryMutex</a>, and <a href="mutex_concept.html#TimedMutex-concept">TimedMutex</a>
respectively. These types should be used to non-recursively synchronize access
to shared resources. For recursive locking mechanics, see the <a href="recursive_mutex.html">recursive
mutexes</a> supplied by <b>Boost.Threads</b>.</p>
<p>Each class supplies one or more typedefs for lock types which model matching
lock concepts. For the best possible performance you should use the mutex class
<p>Each class supplies one or more typedefs for lock types which model matching
lock concepts. For the best possible performance you should use the mutex class
that supports the minimum set of lock types that you need.</p>
<table summary="lock types" border="1" cellpadding="5">
<tr>
<tr>
<td><b>Mutex Class</b></td>
<td><b>Lock name</b></td>
<td><b>Lock Concept</b></td>
</tr>
<tr>
<tr>
<td valign="top"><a href="#mutex Synopsis"><code> mutex</code></a></td>
<td valign="middle"><code>scoped_lock</code></td>
<td valign="middle"><a href="lock_concept.html#ScopedLock"> ScopedLock</a></td>
</tr>
<tr>
<td valign="top"><code><a href="#try_mutex Synopsis"> try_mutex</a></code>
<tr>
<td valign="top"><code><a href="#try_mutex Synopsis"> try_mutex</a></code>
</td>
<td valign="middle"><code>scoped_lock<br>
scoped_try_lock</code></td>
<td valign="middle"><a href="lock_concept.html#ScopedLock"> ScopedLock</a><br>
<a href="lock_concept.html#ScopedTryLock"> ScopedTryLock</a></td>
</tr>
<tr>
<td valign="top"><code><a href="#timed_mutex Synopsis"> timed_mutex</a></code>
<tr>
<td valign="top"><code><a href="#timed_mutex Synopsis"> timed_mutex</a></code>
</td>
<td valign="middle"><code>scoped_lock<br>
scoped_try_lock<br>
@@ -95,22 +95,22 @@
<a href="lock_concept.html#ScopedTimedLock"> ScopedTimedLock</a></td>
</tr>
</table>
<p>The <code>mutex</code>, <code>try_mutex</code> and <code>timed_mutex</code>
classes use an <code>Unspecified</code> <a href="mutex_concept.html#LockingStrategies">locking
strategy</a>, so attempts to recursively lock them or attempts to unlock them
by threads that don&#39;t own a lock on them result in <b>undefined behavior</b>.
This strategy allows implementations to be as efficient as possible on any given
platform. It is, however, recommended that implementations include debugging
<p>The <code>mutex</code>, <code>try_mutex</code> and <code>timed_mutex</code>
classes use an <code>Unspecified</code> <a href="mutex_concept.html#LockingStrategies">locking
strategy</a>, so attempts to recursively lock them or attempts to unlock them
by threads that don&#39;t own a lock on them result in <b>undefined behavior</b>.
This strategy allows implementations to be as efficient as possible on any given
platform. It is, however, recommended that implementations include debugging
support to detect misuse when <code>NDEBUG</code> is not defined.</p>
<p>Like all the <b>Boost.Threads</b> <a href="mutex_concept.html">mutex models</a>,
the <code>mutex</code>, <code>try_mutex</code> and <code> timed_mutex</code>
leave the <a href="mutex_concept.html#SchedulingPolicies">scheduling policy</a>
as <code> Unspecified</code>. Programmers should make no assumptions about the
<p>Like all the <b>Boost.Threads</b> <a href="mutex_concept.html">mutex models</a>,
the <code>mutex</code>, <code>try_mutex</code> and <code> timed_mutex</code>
leave the <a href="mutex_concept.html#SchedulingPolicies">scheduling policy</a>
as <code> Unspecified</code>. Programmers should make no assumptions about the
order in which waiting threads acquire a lock.</p>
<h2><a name="classes"></a>Classes</h2>
<h3><a name="class-mutex"></a>Class <code>mutex</code></h3>
<p>The <code>mutex</code> class is a model of <a href="mutex_concept.html#Mutex-concept">Mutex</a>
and <a href="overview.html#non-copyable">NonCopyable</a>, and provides no additional
<p>The <code>mutex</code> class is a model of <a href="mutex_concept.html#Mutex-concept">Mutex</a>
and <a href="overview.html#non-copyable">NonCopyable</a>, and provides no additional
facilities beyond the requirements of these concepts.</p>
<h4><a name="class-mutex-synopsis"></a>Class <code>mutex</code> synopsis</h4>
<pre>
@@ -121,31 +121,31 @@ namespace boost
{
public:
typedef <i>[implementation defined; see <a href="#Introduction">Introduction</a>]</i> scoped_lock;
mutex();
~mutex();
};
};
</pre>
<h4><a name="class-mutex-ctors"></a>Class <code>mutex</code> constructors and
<h4><a name="class-mutex-ctors"></a>Class <code>mutex</code> constructors and
destructor</h4>
<pre>
mutex();
</pre>
<dl class="function-semantics">
<dl class="function-semantics">
<dt><b>Postconditions:</b> <code>*this</code> is in an unlocked state.</dt>
</dl>
<pre>
~mutex();
</pre>
<dl class="function-semantics">
<dl class="function-semantics">
<dt><b>Requires:</b> <code>*this</code> is in an unlocked sate.</dt>
<dt><b>Danger:</b> Destruction of a locked mutex is a serious programming error
<dt><b>Danger:</b> Destruction of a locked mutex is a serious programming error
resulting in undefined behavior such as a program crash.</dt>
</dl>
<h3><a name="class-try_mutex"></a>Class <code>try_mutex</code></h3>
<p>The <code>try_mutex</code> class is a model of <a href="mutex_concept.html#TryMutex-concept">TryMutex</a>
and <a href="overview.html#non-copyable">NonCopyable</a>, and provides no additional
<p>The <code>try_mutex</code> class is a model of <a href="mutex_concept.html#TryMutex-concept">TryMutex</a>
and <a href="overview.html#non-copyable">NonCopyable</a>, and provides no additional
facilities beyond the requirements of these concepts.</p>
<h4><a name="class-try_mutex-synopsis"></a>Class <code>try_mutex</code> synopsis</h4>
<pre>
@@ -157,31 +157,31 @@ namespace boost
Public:
typedef <i>[implementation defined; see <a href="#Introduction">Introduction</a>]</i> scoped_lock;
typedef <i>[implementation defined; see <a href="#Introduction">Introduction</a>]</i> scoped_try_lock;
try_mutex();
~try_mutex();
};
};
</pre>
<h4><a name="class-try_mutex-ctors"></a>Class <code>try_mutex</code> constructors
<h4><a name="class-try_mutex-ctors"></a>Class <code>try_mutex</code> constructors
and destructor</h4>
<pre>
try_mutex();
</pre>
<dl class="function-semantics">
<dl class="function-semantics">
<dt><b>Postconditions:</b> <code>*this</code> is in an unlocked state.</dt>
</dl>
<pre>
~try_mutex();
</pre>
<dl class="function-semantics">
<dl class="function-semantics">
<dt><b>Requires:</b> <code>*this</code> is in an unlocked sate.</dt>
<dt><b>Danger:</b> Destruction of a locked mutex is a serious programming error
<dt><b>Danger:</b> Destruction of a locked mutex is a serious programming error
resulting in undefined behavior such as a program crash.</dt>
</dl>
<h3><a name="class-timed_mutex"></a>Class <code>timed_mutex</code></h3>
<p>The <code>timed_mutex</code> class is a model of <a href="mutex_concept.html#TimedMutex-concept">TimedMutex</a>
and <a href="overview.html#non-copyable">NonCopyable</a>, and provides no additional
<p>The <code>timed_mutex</code> class is a model of <a href="mutex_concept.html#TimedMutex-concept">TimedMutex</a>
and <a href="overview.html#non-copyable">NonCopyable</a>, and provides no additional
facilities beyond the requirements of these concepts.</p>
<h4><a name="class-timed_mutex-synopsis"></a>Class <code>timed_mutex</code> synopsis</h4>
<pre>
@@ -194,75 +194,30 @@ namespace boost
typedef <i>[implementation defined; see <a href="#Introduction">Introduction</a>]</i> scoped_lock;
typedef <i>[implementation defined; see <a href="#Introduction">Introduction</a>]</i> scoped_try_lock;
typedef <i>[implementation defined; see <a href="#Introduction">Introduction</a>]</i> scoped_timed_lock;
timed_mutex();
~timed_mutex();
};
};
</pre>
<h4><a name="class-timed_mutex-ctors"></a>Class <code>timed_mutex</code> constructors
<h4><a name="class-timed_mutex-ctors"></a>Class <code>timed_mutex</code> constructors
and destructor</h4>
<pre>
timed_mutex();
</pre>
<dl class="function-semantics">
<dl class="function-semantics">
<dt><b>Postconditions:</b> <code>*this</code> is in an unlocked state.</dt>
</dl>
<pre>
~timed_mutex();
</pre>
<dl class="function-semantics">
<dl class="function-semantics">
<dt><b>Requires:</b> <code>*this</code> is in an unlocked sate.</dt>
<dt><b>Danger:</b> Destruction of a locked mutex is a serious programming error
<dt><b>Danger:</b> Destruction of a locked mutex is a serious programming error
resulting in undefined behavior such as a program crash.</dt>
</dl>
<h2><a name="examples"></a>Example(s)</h2>
<pre>
#include <a href=
"../../../boost/thread/mutex.hpp">&lt;boost/thread/mutex.hpp&gt;</a>
#include <a href=
"../../../boost/thread/thread.hpp">&lt;boost/thread/thread.hpp&gt;</a>
#include &lt;iostream&gt;
boost::mutex io_mutex; // The iostreams are not guaranteed to be <a href=
"definitions.html#Thread-safe">thread-safe</a>!
class counter
{
public:
counter() : count(0) { }
int increment() {
boost::mutex::scoped_lock scoped_lock(mutex);
return ++count;
}
private:
boost::mutex mutex;
int count;
};
counter c;
void change_count()
{
int i = c.increment();
boost::mutex::scoped_lock scoped_lock(io_mutex);
std::cout &lt;&lt; &quot;count == &quot; &lt;&lt; i &lt;&lt; std::endl;
}
int main(int, char*[])
{
const int num_threads = 4;
boost::thread_group thrds;
for (int i=0; i &lt; num_threads; ++i)
thrds.create_thread(&amp;change_count);
thrds.join_all();
return 0;
}
</pre>
<p><a href="../example/mutex.cpp">libs/thread/example/mutex.cpp</a></p>
<p>The output is:</p>
<pre>
count == 1
@@ -271,18 +226,18 @@ count == 3
count == 4
</pre>
<hr>
<p>Revised
<p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
05 November, 2001
05 November, 2001
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p>
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
All Rights Reserved.</i></p>
<p>Permission to use, copy, modify, distribute and sell this software and its
documentation for any purpose is hereby granted without fee, provided that the
above copyright notice appear in all copies and that both that copyright notice
and this permission notice appear in supporting documentation. William E. Kempf
makes no representations about the suitability of this software for any purpose.
<p>Permission to use, copy, modify, distribute and sell this software and its
documentation for any purpose is hereby granted without fee, provided that the
above copyright notice appear in all copies and that both that copyright notice
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 &quot;as is&quot; without express or implied warranty.</p>
</body>
</html>

View File

@@ -7,33 +7,33 @@
<body link="#0000ff" vlink="#800080">
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
"header">
<tr>
<td valign="top" width="300"> <a href="../../../index.htm"><img height="86" width="277" alt="C++ Boost" src="../../../c++boost.gif" border="0"></a>
<tr>
<td valign="top" width="300"> <a href="../../../index.htm"><img height="86" width="277" alt="C++ Boost" src="../../../c++boost.gif" border="0"></a>
</td>
<td valign="top">
<td valign="top">
<h1 align="center">Boost.Threads</h1>
<h2 align="center">Mutex Concept</h2>
</td>
</tr>
</table>
<hr>
<dl class="page-index">
<dl class="page-index">
<dt><a href="#introduction">Introduction</a></dt>
<dt><a href="#locking-strategies">Locking Strategies</a></dt>
<dl class="page-index">
<dl class="page-index">
<dt><a href="#locking-strategy-recursive">Recursive</a></dt>
<dt><a href="#locking-strategy-checked">Checked</a></dt>
<dt><a href="#locking-strategy-unchecked">Unchecked</a></dt>
<dt><a href="#locking-strategy-unspecified">Unspecified</a></dt>
</dl>
<dt><a href="#scheduling-policies">Scheduling Policies</a></dt>
<dl class="page-index">
<dl class="page-index">
<dt><a href="#scheduling-policy-FIFO">FIFO</a></dt>
<dt><a href="#scheduling-policy-priority-driven">Priority Driven</a></dt>
<dt><a href="#scheduling-policy-unspecified">Unspecified</a></dt>
</dl>
<dt><a href="#concept-requirements">Concept Requirements</a></dt>
<dl class="page-index">
<dl class="page-index">
<dt><a href="#Mutex-concept">Mutex Concept</a></dt>
<dt><a href="#TryMutex-concept">TryMutex Concept</a></dt>
<dt><a href="#TimedMutex-concept">TimedMutex Concept</a></dt>
@@ -41,155 +41,155 @@
<dt><a href="#models">Models</a></dt>
</dl>
<h2><a name="introduction"></a>Introduction</h2>
<p>A mutex (short for mutual-exclusion) object is used to serializes access to
a resource shared between multiple threads. The <a href="#Mutex">Mutex</a> concept,
with <a href="#TryMutex">TryMutex</a> and <a href="#TimedMutex">TimedMutex</a>
refinements, formalize the requirements. A model that implements Mutex and its
refinements has two states: <b>locked</b> and <b>unlocked</b>. Before using
a shared resource, a thread locks a <b>Boost.Threads</b> mutex object (an object
whose type is a model of <a href="#Mutex-concept">Mutex</a> or one of it's
refinements), insuring <a href="definitions.html#thread-safe">thread-safe</a>
access to the shared resource. When use of the shared resource is complete,
the thread unlocks the mutex object, allowing another thread to acquire the
<p>A mutex (short for mutual-exclusion) object is used to serializes access to
a resource shared between multiple threads. The <a href="#Mutex">Mutex</a> concept,
with <a href="#TryMutex">TryMutex</a> and <a href="#TimedMutex">TimedMutex</a>
refinements, formalize the requirements. A model that implements Mutex and its
refinements has two states: <b>locked</b> and <b>unlocked</b>. Before using
a shared resource, a thread locks a <b>Boost.Threads</b> mutex object (an object
whose type is a model of <a href="#Mutex-concept">Mutex</a> or one of it's
refinements), insuring <a href="definitions.html#thread-safe">thread-safe</a>
access to the shared resource. When use of the shared resource is complete,
the thread unlocks the mutex object, allowing another thread to acquire the
lock and use the shared resource.</p>
<p>Traditional C thread APIs, like POSIX threads or the Windows thread APIs, expose
functions to lock and unlock a mutex object. This is dangerous since it&#39;s
easy to forget to unlock a locked mutex. When the flow of control is complex,
with multiple return points, the likelihood of forgetting to unlock a mutex
object would become even greater. When exceptions are thrown, it becomes nearly
impossible to ensure that the mutex object is unlocked properly when using these
<p>Traditional C thread APIs, like POSIX threads or the Windows thread APIs, expose
functions to lock and unlock a mutex object. This is dangerous since it&#39;s
easy to forget to unlock a locked mutex. When the flow of control is complex,
with multiple return points, the likelihood of forgetting to unlock a mutex
object would become even greater. When exceptions are thrown, it becomes nearly
impossible to ensure that the mutex object is unlocked properly when using these
traditional API&#39;s. The result is <a href="definitions.html#deadlock">deadlock</a>.</p>
<p>Many C++ threading libraries use a pattern known as <i>Scoped Locking</i> <a href="bibliography.html#Schmidt-00">[Schmidt
00]</a> to free the programmer from the need to explicitly lock and unlock mutex
objects. With this pattern, a <a href="lock_concept.html">Lock</a> concept is
employed where the lock object&#39;s constructor locks the associated mutex
object and the destructor automatically does the unlocking. The <b>Boost.Threads</b>
library takes this pattern to the extreme in that Lock concepts are the only
way to lock and unlock a mutex object: lock and unlock functions are not exposed
by any <b>Boost.Threads</b> mutex objects. This helps to ensure safe usage patterns,
<p>Many C++ threading libraries use a pattern known as <i>Scoped Locking</i> <a href="bibliography.html#Schmidt-00">[Schmidt
00]</a> to free the programmer from the need to explicitly lock and unlock mutex
objects. With this pattern, a <a href="lock_concept.html">Lock</a> concept is
employed where the lock object&#39;s constructor locks the associated mutex
object and the destructor automatically does the unlocking. The <b>Boost.Threads</b>
library takes this pattern to the extreme in that Lock concepts are the only
way to lock and unlock a mutex object: lock and unlock functions are not exposed
by any <b>Boost.Threads</b> mutex objects. This helps to ensure safe usage patterns,
especially when code throws exceptions.</p>
<h2><a name="locking-strategies"></a>Locking Strategies</h2>
<p>Every mutex object follows one of several locking strategies. These strategies
define the semantics for the locking operation when the calling thread already
<p>Every mutex object follows one of several locking strategies. These strategies
define the semantics for the locking operation when the calling thread already
owns a lock on the mutex object.</p>
<h3><a name="locking-strategy-recursive"></a>Recursive</h3>
<p>With a recursive locking strategy when a thread attempts to acquire a lock
on the mutex object for which it already owns a lock, the operation is successful.
Note the distinction between a thread, which may have multiple locks outstanding
on a recursive mutex object, and a lock object, which even for a recursive mutex
object cannot have any of its lock functions called multiple times without first
<p>With a recursive locking strategy when a thread attempts to acquire a lock
on the mutex object for which it already owns a lock, the operation is successful.
Note the distinction between a thread, which may have multiple locks outstanding
on a recursive mutex object, and a lock object, which even for a recursive mutex
object cannot have any of its lock functions called multiple times without first
calling unlock.</p>
<p>Internally a lock count is maintained and the owning thread must unlock the
mutex model the same number of times that it&#39;s locked it before the mutex
object&#39;s state returns to unlocked. Since mutex objects in <b>Boost.Threads</b>
expose locking functionality only through lock concepts, a thread will always
unlock a mutex object the same number of times that it locked it. This helps
to eliminate a whole set of errors typically found in traditional C style thread
<p>Internally a lock count is maintained and the owning thread must unlock the
mutex model the same number of times that it&#39;s locked it before the mutex
object&#39;s state returns to unlocked. Since mutex objects in <b>Boost.Threads</b>
expose locking functionality only through lock concepts, a thread will always
unlock a mutex object the same number of times that it locked it. This helps
to eliminate a whole set of errors typically found in traditional C style thread
APIs.</p>
<p>Classes <a href="recursive_mutex.html#class-recursive_mutex">recursive_mutex</a>,
<a href="recursive_mutex.html#class-recursive_try_mutex">recursive_try_mutex</a>
and <a href="recursive_mutex.html#class-recursive_timed_mutex">recursive_timed_mutex</a>
<p>Classes <a href="recursive_mutex.html#class-recursive_mutex">recursive_mutex</a>,
<a href="recursive_mutex.html#class-recursive_try_mutex">recursive_try_mutex</a>
and <a href="recursive_mutex.html#class-recursive_timed_mutex">recursive_timed_mutex</a>
use this locking strategy.</p>
<h3><a name="locking-strategy-checked"></a>Checked</h3>
<p>With a checked locking strategy when a thread attempts to acquire a lock on
the mutex object for which the thread already owns a lock, the operation will
fail with some sort of error indication. Further, attempts by a thread to unlock
a mutex object that was not locked by the thread will also return some sort
of error indication. In <b>Boost.Threads</b>, an exception of type <a href="exceptions.html#class-lock_error">
<p>With a checked locking strategy when a thread attempts to acquire a lock on
the mutex object for which the thread already owns a lock, the operation will
fail with some sort of error indication. Further, attempts by a thread to unlock
a mutex object that was not locked by the thread will also return some sort
of error indication. In <b>Boost.Threads</b>, an exception of type <a href="exceptions.html#class-lock_error">
lock_error</a> would be thrown in these cases.</p>
<p><b>Boost.Threads</b> does not currently provide any mutex objects that use
<p><b>Boost.Threads</b> does not currently provide any mutex objects that use
this strategy.</p>
<h3><a name="locking-strategy-unchecked"></a>Unchecked</h3>
<p>With an unchecked locking strategy when a thread attempts to acquire a lock
on a mutex object for which the thread already owns a lock the operation will
<a href="definitions.html#definition-deadlock">deadlock</a>. In general this
locking strategy is less safe than a checked or recursive strategy, but it&#39;s
<p>With an unchecked locking strategy when a thread attempts to acquire a lock
on a mutex object for which the thread already owns a lock the operation will
<a href="definitions.html#definition-deadlock">deadlock</a>. In general this
locking strategy is less safe than a checked or recursive strategy, but it&#39;s
also a faster strategy and so is employed by many libraries.</p>
<p><b>Boost.Threads</b> does not currently provide any mutex objects that use
<p><b>Boost.Threads</b> does not currently provide any mutex objects that use
this strategy.</p>
<h3><a name="locking-strategy-unspecified"></a>Unspecified</h3>
<p>With an unspecified locking strategy, when a thread attempts to acquire a lock
on a mutex object for which the thread already owns a lock the operation results
<p>With an unspecified locking strategy, when a thread attempts to acquire a lock
on a mutex object for which the thread already owns a lock the operation results
in <b>undefined behavior</b>.</p>
<p>In general a mutex object with an unspecified locking strategy is unsafe, and
it requires programmer discipline to use the mutex object properly. However,
this strategy allows an implementation to be as fast as possible with no restrictions
on its implementation. This is especially true for portable implementations
that wrap the native threading support of a platform. For this reason, the classes
<a href="mutex.html#class-mutex">mutex</a>, <a href="mutex.html#class-try_mutex">try_mutex</a>
and <a href="mutex.html#class-timed_mutex">timed_mutex</a> use this locking
<p>In general a mutex object with an unspecified locking strategy is unsafe, and
it requires programmer discipline to use the mutex object properly. However,
this strategy allows an implementation to be as fast as possible with no restrictions
on its implementation. This is especially true for portable implementations
that wrap the native threading support of a platform. For this reason, the classes
<a href="mutex.html#class-mutex">mutex</a>, <a href="mutex.html#class-try_mutex">try_mutex</a>
and <a href="mutex.html#class-timed_mutex">timed_mutex</a> use this locking
strategy despite the lack of safety.</p>
<h2><a name="scheduling-policies"></a>Scheduling Policies</h2>
<p>Every mutex object follows one of several scheduling policies. These policies
define the semantics when the mutex object is unlocked and there is more than
one thread waiting to acquire a lock. In other words, the policy defines which
<p>Every mutex object follows one of several scheduling policies. These policies
define the semantics when the mutex object is unlocked and there is more than
one thread waiting to acquire a lock. In other words, the policy defines which
waiting thread shall acquire the lock.</p>
<h3><a name="scheduling-policy-FIFO"></a>FIFO</h3>
<p>With a FIFO scheduling policy, threads waiting for the lock will acquire it
in a first come first serve order (or First In First Out). This can help prevent
a high priority thread from starving lower priority threads that are also waiting
<p>With a FIFO scheduling policy, threads waiting for the lock will acquire it
in a first come first serve order (or First In First Out). This can help prevent
a high priority thread from starving lower priority threads that are also waiting
on the mutex object's lock.</p>
<h3><a name="scheduling-policy-priority-driven"></a>Priority Driven</h3>
<p>With a Priority Driven scheduling policy, the thread with the highest priority
acquires the lock. Note that this means that low-priority threads may never
acquire the lock if the mutex object has high contention and there is always
at least one high-priority thread waiting. This is known as thread starvation.
When multiple threads of the same priority are waiting on the mutex object's
lock one of the other scheduling priorities will determine which thread shall
<p>With a Priority Driven scheduling policy, the thread with the highest priority
acquires the lock. Note that this means that low-priority threads may never
acquire the lock if the mutex object has high contention and there is always
at least one high-priority thread waiting. This is known as thread starvation.
When multiple threads of the same priority are waiting on the mutex object's
lock one of the other scheduling priorities will determine which thread shall
acquire the lock.</p>
<h3><a name="scheduling-policy-unspecified"></a>Unspecified</h3>
<p>The mutex object does not specify a scheduling policy. In order to ensure portability,
<p>The mutex object does not specify a scheduling policy. In order to ensure portability,
all <b>Boost.Threads</b> mutex models use an unspecified scheduling policy.</p>
<h2><a name="concept-requirements"></a>Concept Requirements</h2>
<h3><a name="Mutex-concept"></a>Mutex Concept</h3>
<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>
<p>A Mutex object has two states: locked and unlocked. Mutex object state can
only be determined by an object meeting the <a href="lock_concept.html#ScopedLock">ScopedLock</a>
requirements and constructed for the Mutex object.</p>
<p>A Mutex is <a href="../../utility/utility.htm#Class noncopyable">NonCopyable</a>.</p>
<p>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>
<table summary="Mutex expressions" border="1" cellpadding="5">
<tr>
<tr>
<td><b>Expression</b></td>
<td><b>Effects</b></td>
</tr>
<tr>
<tr>
<td><code>M m;</code></td>
<td>Constructs a mutex object m. Post-condition: m is unlocked.</td>
</tr>
<tr>
<tr>
<td><code>(&amp;m)-&gt;~M();</code></td>
<td>Precondition: m is unlocked. Destroys a mutex object m.</td>
</tr>
<tr>
<tr>
<td><code>M::scoped_lock</code></td>
<td>A model of <a href="lock_concept.html#ScopedLock">ScopedLock</a>.</td>
</tr>
</table>
<h3><a name="TryMutex-concept"></a>TryMutex Concept</h3>
<p>A TryMutex is a refinement of <a href="#Mutex-concept">Mutex</a>. For a TryMutex
type M and an object m of that type, the following expressions must be well-formed
<p>A TryMutex is a refinement of <a href="#Mutex-concept">Mutex</a>. For a TryMutex
type M and an object m of that type, the following expressions must be well-formed
and have the indicated effects.</p>
<table summary="TryMutex expressions" border="1" cellpadding="5">
<tr>
<tr>
<td><b>Expression</b></td>
<td><b>Effects</b></td>
</tr>
<tr>
<tr>
<td><code>M::scoped_try_lock</code></td>
<td>A model of <a href="lock_concept.html#ScopedTryLock">ScopedTryLock</a>.</td>
</tr>
</table>
<h3><a name="TimedMutex-concept"></a>TimedMutex Concept</h3>
<p>A TimedMutex is a refinement of <a href="#TryMutex-concept">TryMutex</a>. For
a TimedMutex type M and an object m of that type, the following expressions
<p>A TimedMutex is a refinement of <a href="#TryMutex-concept">TryMutex</a>. For
a TimedMutex type M and an object m of that type, the following expressions
must be well-formed and have the indicated effects.</p>
<table summary="TimedMutex expressions" border="1" cellpadding="5">
<tr>
<tr>
<td><b>Expression</b></td>
<td><b>Effects</b></td>
</tr>
<tr>
<tr>
<td><code>M::scoped_timed_lock</code></td>
<td>A model of <a href="lock_concept.html#ScopedTimedLock">ScopedTimedLock</a>.</td>
</tr>
@@ -197,24 +197,24 @@
<h2><a name="models"></a>Models</h2>
<p><b>Boost.Threads</b> currently supplies six models of Mutex.</p>
<table summary="Mutex concept classes" border="1" cellpadding="5">
<tr>
<tr>
<td><b>Concept</b></td>
<td><b>Refines</b></td>
<td><b>Models</b></td>
</tr>
<tr>
<tr>
<td valign="top"><a href="#Mutex-concept">Mutex</a></td>
<td valign="top">&nbsp;</td>
<td><a href="mutex.html">mutex</a><br>
<a href="recursive_mutex.html">recursive_mutex</a></td>
</tr>
<tr>
<tr>
<td valign="top"><a href="#TryMutex-concept">TryMutex</a></td>
<td valign="top"><a href="#Mutex-concept">Mutex</a></td>
<td><a href="mutex.html">try_mutex<br>
</a> <a href="recursive_mutex.html">recursive_try_mutex</a> </td>
</tr>
<tr>
<tr>
<td valign="top"><a href="#TimedMutex-concept">TimedMutex</a></td>
<td valign="top"><a href="#TryMutex-concept">TryMutex</a></td>
<td><a href="mutex.html">timed_mutex<br>
@@ -222,18 +222,18 @@
</tr>
</table>
<hr>
<p>Revised
<p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
05 November, 2001
05 November, 2001
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p>
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
All Rights Reserved.</i></p>
<p>Permission to use, copy, modify, distribute and sell this software and its
documentation for any purpose is hereby granted without fee, provided that the
above copyright notice appear in all copies and that both that copyright notice
and this permission notice appear in supporting documentation. William E. Kempf
makes no representations about the suitability of this software for any purpose.
<p>Permission to use, copy, modify, distribute and sell this software and its
documentation for any purpose is hereby granted without fee, provided that the
above copyright notice appear in all copies and that both that copyright notice
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 &quot;as is&quot; without express or implied warranty.</p>
</body>
</html>

View File

@@ -7,11 +7,11 @@
<body link="#0000ff" vlink="#800080">
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
"header">
<tr>
<td valign="top" width="300">
<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">
<td valign="top">
<h1 align="center">Boost.Threads</h1>
<h2 align="center">Header &lt;<a href="../../../boost/thread/once.hpp">boost/thread/once.hpp</a>&gt;</h2>
</td>
@@ -19,18 +19,18 @@
</table>
<hr>
<h2>Contents</h2>
<dl class="page-index">
<dl class="page-index">
<dt><a href="#introduction">Introduction</a></dt>
<dt><a href="#macros">Macros</a></dt>
<dl class="page-index">
<dl class="page-index">
<dt><a href="#macro-BOOST_ONCE_INIT">BOOST_ONCE_INIT</a></dt>
</dl>
<dt><a href="#types">Types</a></dt>
<dl class="page-index">
<dl class="page-index">
<dt><a href="#type-once_flag">once_flag</a></dt>
</dl>
<dt><a href="#functions">Functions</a></dt>
<dl class="page-index">
<dl class="page-index">
<dt><a href="#function-call_once">call_once</a></dt>
</dl>
<dt><a href="#examples">Example(s)</a></dt>
@@ -48,21 +48,21 @@
<pre>
<a name="macro-BOOST_ONCE_INIT"></a>#define BOOST_ONCE_INIT <i>implementation defined</i>
</pre>
<p>This is a constant value used to initialize <code>once_flag</code> instances
<p>This is a constant value used to initialize <code>once_flag</code> instances
to indicate that the logically associated routine has not been run yet.</p>
<h2><a name="types"></a>Types</h2>
<pre>
<a name="type-once_flag"></a>typedef <i>implementation defined</i> once_flag;
</pre>
<p>This implementation defined type is used as a flag to insure a routine is called
<p>This implementation defined type is used as a flag to insure a routine is called
only once. Instances of this type should be statically initialized to <code>BOOST_ONCE_INIT</code>.</p>
<h2><a name="functions"></a>Functions</h2>
<pre>
<a name="function-call_once"></a>void call_once(void (*func)(), once_flag& flag);
</pre>
<dl class="function-semantics">
<dl class="function-semantics">
<dt><b>Requires:</b> The function <code>func</code> shall not throw exceptions.</dt>
<dt><b>Effects:</b> As if (in an atomic fashion):
<dt><b>Effects:</b> As if (in an atomic fashion):
<pre>
if (flag == BOOST_ONCE_INIT)
func();
@@ -71,46 +71,20 @@ if (flag == BOOST_ONCE_INIT)
<dt><b>Postconditions:</b> <code>flag != BOOST_ONCE_INIT</code></dt>
</dl>
<h2><a name="examples"></a>Example(s)</h2>
<pre>
#include <a href="../../../boost/thread/thread.hpp">&lt;boost/thread/thread.hpp&gt;</a>
#include <a href="../../../boost/thread/tss.hpp">&lt;boost/thread/once.hpp&gt;</a>
#include &lt;cassert&gt;
int value=0;
boost::once_flag once = BOOST_ONCE_INIT;
void init()
{
++value;
}
void thread_proc()
{
boost::call_once(&amp;init, once);
}
int main(int argc, char* argv[])
{
boost::thread_group threads;
for (int i=0; i&lt;5; ++i)
threads.create_thread(&amp;thread_proc);
threads.join_all();
assert(value == 1);
}
</pre>
<p><a href="../example/once.cpp">libs/thread/example/once.cpp</a></p>
<hr>
<p>Revised
<p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
05 November, 2001
05 November, 2001
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p>
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
All Rights Reserved.</i></p>
<p>Permission to use, copy, modify, distribute and sell this software and its
documentation for any purpose is hereby granted without fee, provided that the
above copyright notice appear in all copies and that both that copyright notice
and this permission notice appear in supporting documentation. William E. Kempf
makes no representations about the suitability of this software for any purpose.
<p>Permission to use, copy, modify, distribute and sell this software and its
documentation for any purpose is hereby granted without fee, provided that the
above copyright notice appear in all copies and that both that copyright notice
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 &quot;as is&quot; without express or implied warranty.</p>
</body>
</html>

View File

@@ -7,115 +7,115 @@
<body link="#0000ff" vlink="#800080">
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
"header">
<tr>
<td valign="top" width="300">
<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">
<td valign="top">
<h1 align="center">Boost.Threads</h1>
<h2 align="center">Overview</h2>
</td>
</tr>
</table>
<hr>
<dl class="index">
<dl class="index">
<dt><a href="#introduction">Introduction</a></dt>
<dt><a href="#dangers">Dangers</a></dt>
<dl class="index">
<dl class="index">
<dt><a href="#testing-debugging">Testing and debugging considerations</a></dt>
<dt><a href="#head-start">Getting a head start</a></dt>
</dl>
<dt><a href="#library">C++ Standard Library usage in multithreaded programs</a></dt>
<dl class="index">
<dl class="index">
<dt><a href="#runtime-libraries">Runtime libraries</a></dt>
<dt><a href="#non-thread-safe-functions">Potentially non-thread-safe functions</a></dt>
</dl>
<dt><a href="#common-requirements">Common requirements for all Boost.Threads
<dt><a href="#common-requirements">Common requirements for all Boost.Threads
components</a></dt>
<dl class="index">
<dl class="index">
<dt><a href="#exceptions">Exceptions</a></dt>
<dt><a href="#non-copyable">NonCopyable requirement</a></dt>
</dl>
</dl>
<h2><a name="introduction"></a>Introduction</h2>
<p>Boost.Threads allows C++ programs to execute as multiple, asynchronous, independent,
threads-of-execution. Each thread has its own machine state including program
instruction counter and registers. Programs which execute as multiple threads
are called multithreaded programs to distinguish them from traditional single-threaded
programs. <a href="definitions.html">Definitions</a> gives a more complete description
<p>Boost.Threads allows C++ programs to execute as multiple, asynchronous, independent,
threads-of-execution. Each thread has its own machine state including program
instruction counter and registers. Programs which execute as multiple threads
are called multithreaded programs to distinguish them from traditional single-threaded
programs. <a href="definitions.html">Definitions</a> gives a more complete description
of the multithreading execution environment.</p>
<p>Multithreading provides several advantages:</p>
<ul>
<li>Programs which would otherwise block waiting for some external event can
continue to respond if the blocking operation is placed in a separate thread.
<li>Programs which would otherwise block waiting for some external event can
continue to respond if the blocking operation is placed in a separate thread.
Multithreading is usually an absolute requirement for these programs.</li>
</ul>
<ul>
<li>Well-designed multithreaded programs may execute faster than single-threaded
programs, particularly on multiprocessor hardware. Note, however, that poorly-designed
<li>Well-designed multithreaded programs may execute faster than single-threaded
programs, particularly on multiprocessor hardware. Note, however, that poorly-designed
multithreaded programs are often slower that single-threaded programs.</li>
</ul>
<ul>
<li>Some program designs may be easier to formulate using a multithreaded approach.
<li>Some program designs may be easier to formulate using a multithreaded approach.
After all, the real world is asynchronous!</li>
</ul>
<h2><a name="dangers"></a>Dangers</h2>
<p>Beyond the errors which can occur in single-threaded programs, multithreaded
<p>Beyond the errors which can occur in single-threaded programs, multithreaded
programs are subject to additional errors:</p>
<ul>
<li><a href="definitions.html#definition-race-condition">Race conditions</a>.</li>
<li><a href="definitions.html#definition-deadlock">Deadlock</a> (sometimes called
<li><a href="definitions.html#definition-deadlock">Deadlock</a> (sometimes called
&quot;deadly embrace&quot;)</li>
<li><a href="definitions.html#definition-priority-failure">Priority failures</a>
<li><a href="definitions.html#definition-priority-failure">Priority failures</a>
(priority inversion, infinite overtaking, starvation, etc.)</li>
</ul>
<p>Every multithreaded program must be designed carefully to avoid race conditions,
priority failures and deadlock. These aren&#39;t rare or exotic failures - they
are virtually guaranteed to occur unless multithreaded code is designed to avoid
<p>Every multithreaded program must be designed carefully to avoid race conditions,
priority failures and deadlock. These aren&#39;t rare or exotic failures - they
are virtually guaranteed to occur unless multithreaded code is designed to avoid
them. Priority failures are somewhat less common, but are nonetheless serious.</p>
<p>The <a href="introduction.html">Boost.Threads design</a> attempts to minimize
these errors, but they will still occur unless the programmer proactively designs
<p>The <a href="introduction.html">Boost.Threads design</a> attempts to minimize
these errors, but they will still occur unless the programmer proactively designs
to avoid them.</p>
<h3><a name="testing-debugging"></a>Testing and debugging considerations</h3>
<p>Multithreaded programs are non-deterministic. In other words, the same program
with the same input data may follow different execution paths each time it is
<p>Multithreaded programs are non-deterministic. In other words, the same program
with the same input data may follow different execution paths each time it is
invoked. That can make testing and debugging a nightmare:</p>
<ul>
<li>Failures are often not repeatable.</li>
<li>Probe effect causes debuggers to produce very different results from non-debug
<li>Probe effect causes debuggers to produce very different results from non-debug
uses.</li>
<li>Debuggers require special support to show thread state.</li>
<li>Tests on a single processor system may give no indication of serious errors
which would appear on multiprocessor systems, and visa versa. Thus test cases
<li>Tests on a single processor system may give no indication of serious errors
which would appear on multiprocessor systems, and visa versa. Thus test cases
should include a varying number of processors.</li>
<li>For programs which create a varying number of threads according to workload,
tests which don&#39;t span the full range of possibilities may miss serious
<li>For programs which create a varying number of threads according to workload,
tests which don&#39;t span the full range of possibilities may miss serious
errors.</li>
</ul>
<h3><a name="head-start"></a>Getting a head start</h3>
<p>Although it might appear that multithreaded programs are inherently unreliable,
many reliable multithreaded programs do exist. Multithreading techniques are
<p>Although it might appear that multithreaded programs are inherently unreliable,
many reliable multithreaded programs do exist. Multithreading techniques are
known which lead to reliable programs.</p>
<p>Design patterns for reliable multithreaded programs, including the important
<i>monitor</i> pattern, are presented in <cite> Pattern-Oriented Software Architecture
<p>Design patterns for reliable multithreaded programs, including the important
<i>monitor</i> pattern, are presented in <cite> Pattern-Oriented Software Architecture
Volume 2 - Patterns for Concurrent and Networked Objects</cite> [<a href=
"bibliography.html#Schmidt-00">Schmidt 00</a>]. Many important multithreading
programming considerations (independent of threading library) are discussed
in <cite>Programming with POSIX Threads</cite> [<a href="bibliography.html#Butenhof-97">Butenhof
"bibliography.html#Schmidt-00">Schmidt 00</a>]. Many important multithreading
programming considerations (independent of threading library) are discussed
in <cite>Programming with POSIX Threads</cite> [<a href="bibliography.html#Butenhof-97">Butenhof
97</a>].</p>
<p>Doing some reading before attempting multithreaded designs will give you a
<p>Doing some reading before attempting multithreaded designs will give you a
head start toward reliable multithreaded programs.</p>
<h2><a name="library"></a>C++ Standard Library usage in multithreaded programs</h2>
<h3><a name="runtime-libraries"></a>Runtime libraries</h3>
<p><b>Warning:</b> Multithreaded programs such as those using <b> Boost.Threads</b>
must link to <a href="definitions.html#Thread-safe"> thread-safe</a> versions
of all runtime libraries used by the program, including the runtime library
for the C++ Standard Library. Otherwise <a href="definitions.html#Race condition">race
conditions</a> will occur when multiple threads simultaneously execute runtime
library functions for <i>new</i>, <i>delete</i>, or other language features
<p><b>Warning:</b> Multithreaded programs such as those using <b> Boost.Threads</b>
must link to <a href="definitions.html#Thread-safe"> thread-safe</a> versions
of all runtime libraries used by the program, including the runtime library
for the C++ Standard Library. Otherwise <a href="definitions.html#Race condition">race
conditions</a> will occur when multiple threads simultaneously execute runtime
library functions for <i>new</i>, <i>delete</i>, or other language features
which imply shared state.</p>
<h3><a name="non-thread-safe-functions"></a>Potentially non-thread-safe functions</h3>
<p>Certain C++ Standard Library functions inherited from C are particular problems
<p>Certain C++ Standard Library functions inherited from C are particular problems
because they hold internal state between calls:</p>
<ul>
<li>rand</li>
@@ -125,49 +125,49 @@
<li>gmtime</li>
<li>localtime</li>
</ul>
<p>It is possible to write thread-safe implementations of these by using <a href="tss.html#class-thread_specific_ptr">thread-specific
storage</a>, and several C++ compiler vendors do just that. The technique is
<p>It is possible to write thread-safe implementations of these by using <a href="tss.html#class-thread_specific_ptr">thread-specific
storage</a>, and several C++ compiler vendors do just that. The technique is
well-know and is explained in [<a href=
"bibliography.html#Butenhof-97">Buttenhof 97</a>].</p>
<p>But at least one vendor (HP-UX) does not provide thread-safe implementations
of the above functions in their otherwise thread-safe runtime library. Instead
<p>But at least one vendor (HP-UX) does not provide thread-safe implementations
of the above functions in their otherwise thread-safe runtime library. Instead
they provide replacement functions with different names and arguments.</p>
<p><b>Recommendation:</b> For the most portable, yet thread-safe code, use Boost
<p><b>Recommendation:</b> For the most portable, yet thread-safe code, use Boost
replacements for the problem functions. See the <a href=
"../../random/index.html">Boost Random Number Library</a> and <a href=
"../../tokenizer/index.htm">Boost Tokenizer Library</a>.</p>
<h2><a name="common-gaurantees"></a>Common guarantees for all Boost.Threads components</h2>
<h3><a name="exceptions"></a>Exceptions</h3>
<p><b>Boost.Threads</b> destructors never throw exceptions. Unless otherwise specified,
other <b>Boost.Threads</b> functions that do not have an exception-specification
<p><b>Boost.Threads</b> destructors never throw exceptions. Unless otherwise specified,
other <b>Boost.Threads</b> functions that do not have an exception-specification
may throw implementation-defined exceptions.</p>
<p>In particular, <b>Boost.Threads</b> reports failure to allocate storage by
throwing an exception of type std::bad_alloc, or a class derived from std::bad_alloc,
failure to obtain thread resources other than memory by throwing an exception
of type <a href="exceptions.html#class-thread_resource_error">boost::thread_resource_error</a>,
<p>In particular, <b>Boost.Threads</b> reports failure to allocate storage by
throwing an exception of type std::bad_alloc, or a class derived from std::bad_alloc,
failure to obtain thread resources other than memory by throwing an exception
of type <a href="exceptions.html#class-thread_resource_error">boost::thread_resource_error</a>,
and certain lock related failures by throwing an exception of type <a href="exceptions.html#class-lock_error">boost::lock_error</a></p>
<p><b>Rationale:</b> Follows the C++ Standard Library practice of allowing all
functions except destructors or other specified functions to throw exceptions
<p><b>Rationale:</b> Follows the C++ Standard Library practice of allowing all
functions except destructors or other specified functions to throw exceptions
on errors.</p>
<h3><a name="non-copyable"></a>NonCopyable requirement</h3>
<p><b>Boost.Threads</b> classes documented as meeting the NonCopyable requirement
disallow copy construction and copy assignment. For the sake of exposition,
the synopsis of such classes show private derivation from <a href="../../utility/utility.htm">
boost::noncopyable</a>. Users should not depend on this derivation, however,
<p><b>Boost.Threads</b> classes documented as meeting the NonCopyable requirement
disallow copy construction and copy assignment. For the sake of exposition,
the synopsis of such classes show private derivation from <a href="../../utility/utility.htm">
boost::noncopyable</a>. Users should not depend on this derivation, however,
as implementations are free to meet the NonCopyable requirement in other ways.</p>
<hr>
<p>Revised
<p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
05 November, 2001
05 November, 2001
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p>
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
All Rights Reserved.</i></p>
<p>Permission to use, copy, modify, distribute and sell this software and its
documentation for any purpose is hereby granted without fee, provided that the
above copyright notice appear in all copies and that both that copyright notice
and this permission notice appear in supporting documentation. William E. Kempf
makes no representations about the suitability of this software for any purpose.
<p>Permission to use, copy, modify, distribute and sell this software and its
documentation for any purpose is hereby granted without fee, provided that the
above copyright notice appear in all copies and that both that copyright notice
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 &quot;as is&quot; without express or implied warranty.</p>
</body>
</html>

View File

@@ -7,141 +7,141 @@
<body link="#0000ff" vlink="#800080">
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
"header">
<tr>
<td valign="top" width="300">
<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">
<td valign="top">
<h1 align="center">Boost.Threads</h1>
<h2 align="center">Rationale</h2>
</td>
</tr>
</table>
<hr>
<dl class="index">
<dl class="index">
<dt><a href="#introduction">Introduction</a></dt>
<dt><a href="#library">Rationale for the Creation of <b>Boost.Threads</b></a></dt>
<dt><a href="#primitives">Rationale for the Low Level Primitives Supported in
<dt><a href="#primitives">Rationale for the Low Level Primitives Supported in
<b>Boost.Threads</b></a></dt>
<dt><a href="#lock_objects">Rationale for the Lock Design</a></dt>
<dt><a href="#non-copyable">Rationale for NonCopyable Thread Type</a></dt>
<dt><a href="#events">Rationale for not providing <i>Event Variables</i></a></dt>
</dl>
<h2><a name="introduction"></a>Introduction</h2>
<p>This page explains the rationale behind various design decisions in the <b>Boost.Threads</b>
library. Having the rationale documented here should explain how we arrived
at the current design as well as prevent future rehashing of discussions and
thought processes that have already occurred. It can also give users a lot of
<p>This page explains the rationale behind various design decisions in the <b>Boost.Threads</b>
library. Having the rationale documented here should explain how we arrived
at the current design as well as prevent future rehashing of discussions and
thought processes that have already occurred. It can also give users a lot of
insight into the design process required for this library.</p>
<h2><a name="library"></a>Rationale for the Creation of <b>Boost.Threads</b></h2>
<p>Processes often have a degree of &quot;potential parallelism&quot; and it can
often be more intuitive to design systems with this in mind. Further, these
parallel processes can result in more responsive programs. The benefits for
multithreaded programming are quite well known to most modern programmers, yet
<p>Processes often have a degree of &quot;potential parallelism&quot; and it can
often be more intuitive to design systems with this in mind. Further, these
parallel processes can result in more responsive programs. The benefits for
multithreaded programming are quite well known to most modern programmers, yet
the C++ language doesn&#39;t directly support this concept.</p>
<p>Many platforms support multithreaded programming despite the fact that the
language doesn&#39;t support it. They do this through external libraries, which
are, unfortunately, platform specific. POSIX has tried to address this problem
through the standardization of a &quot;pthread&quot; library. However, this
<p>Many platforms support multithreaded programming despite the fact that the
language doesn&#39;t support it. They do this through external libraries, which
are, unfortunately, platform specific. POSIX has tried to address this problem
through the standardization of a &quot;pthread&quot; library. However, this
is a standard only on POSIX platforms, so its portability is limited.</p>
<p>Another problem with POSIX and other platform specific thread libraries is
that they are almost universally C based libraries. This leaves several C++
specific issues unresolved, such as what happens when an exception is thrown
in a thread. Further, there are some C++ concepts, such as destructors, that
<p>Another problem with POSIX and other platform specific thread libraries is
that they are almost universally C based libraries. This leaves several C++
specific issues unresolved, such as what happens when an exception is thrown
in a thread. Further, there are some C++ concepts, such as destructors, that
can make usage much easier than what&#39;s available in a C library.</p>
<p>What&#39;s truly needed is C++ language support for threads. However, the C++
standards committee needs existing practice or a good proposal as a starting
<p>What&#39;s truly needed is C++ language support for threads. However, the C++
standards committee needs existing practice or a good proposal as a starting
point for adding this to the standard.</p>
<p>The <b>Boost.Threads</b> library was developed to provide a C++ developer with
a portable interface for writing multithreaded programs on numerous platforms.
There&#39;s a hope that the library can be the basis for a more detailed proposal
<p>The <b>Boost.Threads</b> library was developed to provide a C++ developer with
a portable interface for writing multithreaded programs on numerous platforms.
There&#39;s a hope that the library can be the basis for a more detailed proposal
for the C++ standards committee to consider for inclusion in the next C++ standard.</p>
<h2><a name="primitives"></a>Rationale for the Low Level Primitives Supported
<h2><a name="primitives"></a>Rationale for the Low Level Primitives Supported
in <b>Boost.Threads</b></h2>
<p>The <b>Boost.Threads</b> library supplies a set of low level primitives for
writing multithreaded programs, such as mutexes and condition variables. In
fact, the first release of <b>Boost.Threads</b> supports only these low level
primitives. However, computer science research has shown that use of these primitives
is difficult since it's difficult to mathematically prove that a usage pattern
is correct, meaning it doesn&#39;t result in race conditions or deadlocks. There
are several algebras (such as CSP, CCS and Join calculus) that have been developed
to help write provably correct parallel processes. In order to prove the correctness
these processes must be coded using higher level abstractions. So why does <b>Boost.Threads</b>
<p>The <b>Boost.Threads</b> library supplies a set of low level primitives for
writing multithreaded programs, such as mutexes and condition variables. In
fact, the first release of <b>Boost.Threads</b> supports only these low level
primitives. However, computer science research has shown that use of these primitives
is difficult since it's difficult to mathematically prove that a usage pattern
is correct, meaning it doesn&#39;t result in race conditions or deadlocks. There
are several algebras (such as CSP, CCS and Join calculus) that have been developed
to help write provably correct parallel processes. In order to prove the correctness
these processes must be coded using higher level abstractions. So why does <b>Boost.Threads</b>
support the lower level concepts?</p>
<p>The reason is simple: the higher level concepts need to be implemented using
at least some of the lower level concepts. So having portable lower level concepts
makes it easier to develop the higher level concepts and will allow researchers
<p>The reason is simple: the higher level concepts need to be implemented using
at least some of the lower level concepts. So having portable lower level concepts
makes it easier to develop the higher level concepts and will allow researchers
to experiment with various techniques.</p>
<p>Beyond this theoretical application of higher level concepts, however, the
fact remains that many multithreaded programs are written using only the lower
level concepts, so they are useful in and of themselves, even if it&#39;s hard
to prove that their usage is correct. Since many users will be familiar with
these lower level concepts but be unfamiliar with any of the higher level concepts
<p>Beyond this theoretical application of higher level concepts, however, the
fact remains that many multithreaded programs are written using only the lower
level concepts, so they are useful in and of themselves, even if it&#39;s hard
to prove that their usage is correct. Since many users will be familiar with
these lower level concepts but be unfamiliar with any of the higher level concepts
there&#39;s also an argument for accessibility.</p>
<h2><a name="lock_objects"></a>Rationale for the Lock Design</h2>
<p>Programmers who are used to multithreaded programming issues will quickly note
that the Boost.Thread&#39;s design for mutex lock concepts is not <a href="definitions.html#Thread-safe">thread-safe</a>
(this is clearly documented as well). At first this may seem like a serious
design flaw. Why have a multithreading primitive that&#39;s not thread-safe
<p>Programmers who are used to multithreaded programming issues will quickly note
that the Boost.Thread&#39;s design for mutex lock concepts is not <a href="definitions.html#Thread-safe">thread-safe</a>
(this is clearly documented as well). At first this may seem like a serious
design flaw. Why have a multithreading primitive that&#39;s not thread-safe
itself?</p>
<p>A lock object is not a synchronization primitive. A lock object&#39;s sole
responsibility is to ensure that a mutex is both locked and unlocked in a manner
that won&#39;t result in the common error of locking a mutex and then forgetting
to unlock it. This means that instances of a lock object are only going to be
created, at least in theory, within block scope and won&#39;t be shared between
threads. Only the mutex objects will be created outside of block scope and/or
shared between threads. Though it&#39;s possible to create a lock object outside
of block scope and to share it between threads to do so would not be a typical
usage (in fact, to do so would likely be an error). Nor are there any cases
<p>A lock object is not a synchronization primitive. A lock object&#39;s sole
responsibility is to ensure that a mutex is both locked and unlocked in a manner
that won&#39;t result in the common error of locking a mutex and then forgetting
to unlock it. This means that instances of a lock object are only going to be
created, at least in theory, within block scope and won&#39;t be shared between
threads. Only the mutex objects will be created outside of block scope and/or
shared between threads. Though it&#39;s possible to create a lock object outside
of block scope and to share it between threads to do so would not be a typical
usage (in fact, to do so would likely be an error). Nor are there any cases
when such usage would be required.</p>
<p>Lock objects must maintain some state information. In order to allow a program
to determine if a try_lock or timed_lock was successful the lock object must
retain state indicating the success or failure of the call made in its constructor.
If a lock object were to have such state and remain thread-safe it would need
to synchronize access to the state information which would result in roughly
doubling the time of most operations. Worse, since checking the state can occur
only by a call after construction we&#39;d have a race condition if the lock
<p>Lock objects must maintain some state information. In order to allow a program
to determine if a try_lock or timed_lock was successful the lock object must
retain state indicating the success or failure of the call made in its constructor.
If a lock object were to have such state and remain thread-safe it would need
to synchronize access to the state information which would result in roughly
doubling the time of most operations. Worse, since checking the state can occur
only by a call after construction we&#39;d have a race condition if the lock
object were shared between threads.</p>
<p>So, to avoid the overhead of synchronizing access to the state information
and to avoid the race condition the <b>Boost.Threads</b> library simply does
nothing to make lock objects thread-safe. Instead, sharing a lock object between
threads results in undefined behavior. Since the only proper usage of lock objects
is within block scope this isn&#39;t a problem, and so long as the lock object
<p>So, to avoid the overhead of synchronizing access to the state information
and to avoid the race condition the <b>Boost.Threads</b> library simply does
nothing to make lock objects thread-safe. Instead, sharing a lock object between
threads results in undefined behavior. Since the only proper usage of lock objects
is within block scope this isn&#39;t a problem, and so long as the lock object
is properly used there&#39;s no danger of any multithreading issues.</p>
<h2><a name="non-copyable"></a>Rationale for NonCopyable Thread Type</h2>
<p>Programmers who are used to C libraries for multithreaded programming are likely
to wonder why <b>Boost.Threads</b> uses a noncopyable design for <a href="thread.html">boost::thread</a>.
After all, the C thread types are copyable, and you often have a need for copying
them within user code. However, careful comparison of C designs to C++ designs
<p>Programmers who are used to C libraries for multithreaded programming are likely
to wonder why <b>Boost.Threads</b> uses a noncopyable design for <a href="thread.html">boost::thread</a>.
After all, the C thread types are copyable, and you often have a need for copying
them within user code. However, careful comparison of C designs to C++ designs
shows a flaw in this logic.</p>
<p>All C types are copyable. It is, in fact, not possible to make a noncopyable
type in C. For this reason types that represent system resources in C are often
designed to behave very similarly to a pointer to dynamic memory. There&#39;s
an API for acquiring the resource and an API for releasing the resources. For
memory we have pointers as the type and alloc/free for the acquisition and release
APIs. For files we have FILE* as the type and fopen/fclose for the acquisition
and release APIs. You can freely copy instances of the types but must manually
manage the lifetime of the actual resource through the acquisition and release
<p>All C types are copyable. It is, in fact, not possible to make a noncopyable
type in C. For this reason types that represent system resources in C are often
designed to behave very similarly to a pointer to dynamic memory. There&#39;s
an API for acquiring the resource and an API for releasing the resources. For
memory we have pointers as the type and alloc/free for the acquisition and release
APIs. For files we have FILE* as the type and fopen/fclose for the acquisition
and release APIs. You can freely copy instances of the types but must manually
manage the lifetime of the actual resource through the acquisition and release
APIs.</p>
<p>C++ designs recognize that the acquisition and release APIs are error prone
and try to eliminate possible errors by acquiring the resource in the constructor
and releasing it in the destructor. The best example of such a design is the
std::iostream set of classes which can represent the same resource as the FILE*
type in C. A file is opened in the std::fstream&#39;s constructor and closed
in its destructor. However, if an iostream were copyable it could lead to a
file being closed twice, an obvious error, so the std::iostream types are noncopyable
by design. This is the same design used by boost::thread, which is a simple
and easy to understand design that&#39;s consistent with other C++ standard
<p>C++ designs recognize that the acquisition and release APIs are error prone
and try to eliminate possible errors by acquiring the resource in the constructor
and releasing it in the destructor. The best example of such a design is the
std::iostream set of classes which can represent the same resource as the FILE*
type in C. A file is opened in the std::fstream&#39;s constructor and closed
in its destructor. However, if an iostream were copyable it could lead to a
file being closed twice, an obvious error, so the std::iostream types are noncopyable
by design. This is the same design used by boost::thread, which is a simple
and easy to understand design that&#39;s consistent with other C++ standard
types.</p>
<p>During the design of boost::thread it was pointed out that it would be possible
to allow it to be a copyable type if some form of &quot;reference management&quot;
were used, such as ref-counting or ref-lists, and many argued for a boost::thread_ref
design instead. The reasoning was that copying &quot;thread&quot; objects was
a typical need in the C libraries, and so presumably would be in the C++ libraries
as well. It was also thought that implementations could provide more efficient
reference management than wrappers (such as boost::shared_ptr) around a noncopyable
thread concept. Analysis of whether or not these arguments would hold true doesn&#39;t
appear to bear them out. To illustrate the analysis we&#39;ll first provide
<p>During the design of boost::thread it was pointed out that it would be possible
to allow it to be a copyable type if some form of &quot;reference management&quot;
were used, such as ref-counting or ref-lists, and many argued for a boost::thread_ref
design instead. The reasoning was that copying &quot;thread&quot; objects was
a typical need in the C libraries, and so presumably would be in the C++ libraries
as well. It was also thought that implementations could provide more efficient
reference management than wrappers (such as boost::shared_ptr) around a noncopyable
thread concept. Analysis of whether or not these arguments would hold true doesn&#39;t
appear to bear them out. To illustrate the analysis we&#39;ll first provide
pseudo-code illustrating the six typical usage patterns of a thread object.</p>
<h3>1. Simple creation of a thread.</h3>
<pre>
@@ -193,22 +193,22 @@ Void foo()
manager2.add(thread);
}
</pre>
<p>Of these usage patterns there&#39;s only one that requires reference management
(number 6). Hopefully it&#39;s fairly obvious that this usage pattern simply
won&#39;t occur as often as the other usage patterns. So there really isn&#39;t
<p>Of these usage patterns there&#39;s only one that requires reference management
(number 6). Hopefully it&#39;s fairly obvious that this usage pattern simply
won&#39;t occur as often as the other usage patterns. So there really isn&#39;t
a &quot;typical need&quot; for a thread concept, though there is some need.</p>
<p>Since the need isn&#39;t typical we must use different criteria for deciding
on either a thread_ref or thread design. Possible criteria include ease of use
<p>Since the need isn&#39;t typical we must use different criteria for deciding
on either a thread_ref or thread design. Possible criteria include ease of use
and performance. So let&#39;s analyze both of these carefully.</p>
<p>With ease of use we can look at existing experience. The standard C++ objects
that represent a system resource, such as std::iostream, are noncopyable, so
we know that C++ programmers must at least be experienced with this design.
Most C++ developers are also used to smart pointers such as boost::shared_ptr,
so we know they can at least adapt to a thread_ref concept with little effort.
<p>With ease of use we can look at existing experience. The standard C++ objects
that represent a system resource, such as std::iostream, are noncopyable, so
we know that C++ programmers must at least be experienced with this design.
Most C++ developers are also used to smart pointers such as boost::shared_ptr,
so we know they can at least adapt to a thread_ref concept with little effort.
So existing experience isn&#39;t going to lead us to a choice.</p>
<p>The other thing we can look at is how difficult it is to use both types for
the six usage patterns above. If we find it overly difficult to use a concept
for any of the usage patterns there would be a good argument for choosing the
<p>The other thing we can look at is how difficult it is to use both types for
the six usage patterns above. If we find it overly difficult to use a concept
for any of the usage patterns there would be a good argument for choosing the
other design. So we&#39;ll code all six usage patterns using both designs.</p>
<h3>1.</h3>
<pre>
@@ -232,7 +232,7 @@ void foo()
void foo()
{
thread_ref thrd =
thread_ref thrd =
create_thread(&amp;bar);thrd-&gt;join();
}
</pre>
@@ -267,7 +267,7 @@ void foo()
for (int i=0; i&lt;NUM_THREADS; ++i)
threads[i] = create_thread(&amp;bar);
for (int i= 0; i&lt;NUM_THREADS;
++i)threads[i]-&gt;join();
++i)threads[i]-&gt;join();
}
</pre>
<h3>5.</h3>
@@ -300,13 +300,13 @@ void foo()
manager2.add(thrd);
}
</pre>
<p>This shows the usage patterns being nearly identical in complexity for both
designs. The only actual added complexity occurs because of the use of operator
new in (4), (5) and (6) and the use of std::auto_ptr and boost::shared_ptr in
(4) and (6) respectively. However, that&#39;s not really much added complexity,
and C++ programmers are used to using these idioms any way. Some may dislike
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
<p>This shows the usage patterns being nearly identical in complexity for both
designs. The only actual added complexity occurs because of the use of operator
new in (4), (5) and (6) and the use of std::auto_ptr and boost::shared_ptr in
(4) and (6) respectively. However, that&#39;s not really much added complexity,
and C++ programmers are used to using these idioms any way. Some may dislike
the presence of operator new in user code, but this can be eliminated by proper
design of higher level concepts, such as the boost::thread_group class that
simplifies example (4) down to:</p>
<pre>
void foo()
@@ -318,82 +318,82 @@ void foo()
}
</pre>
<p>So ease of use is really a wash and not much help in picking a design.</p>
<p>So what about performance? If you look at the above code examples we can analyze
the theoretical impact to performance that both designs have. For (1) we can
see that platforms that don&#39;t have a ref-counted native thread type (POSIX,
for instance) will be impacted by a thread_ref design. Even if the native thread
type is ref-counted there may be an impact if more state information has to
be maintained for concepts foreign to the native API, such as clean up stacks
for Win32 implementations. For (2) the performance impact will be identical
to (1). The same for (3). For (4) things get a little more interesting and we
find that theoretically at least the thread_ref may perform faster since the
thread design requires dynamic memory allocation/deallocation. However, in practice
there may be dynamic allocation for the thread_ref design as well, it will just
be hidden from the user. As long as the implementation has to do dynamic allocations
the thread_ref loses again because of the reference management. For (5) we see
the same impact as we do for (4). For (6) we still have a possible impact to
the thread design because of dynamic allocation but thread_ref no longer suffers
because of its reference management, and in fact, theoretically at least, the
thread_ref may do a better job of managing the references. All of this indicates
that thread wins for (1), (2) and (3), with (4) and (5) the winner depends on
the implementation and the platform but the thread design probably has a better
chance, and with (6) it will again depend on the implementation and platform
but this time we favor thread_ref slightly. Given all of this it&#39;s a narrow
<p>So what about performance? If you look at the above code examples we can analyze
the theoretical impact to performance that both designs have. For (1) we can
see that platforms that don&#39;t have a ref-counted native thread type (POSIX,
for instance) will be impacted by a thread_ref design. Even if the native thread
type is ref-counted there may be an impact if more state information has to
be maintained for concepts foreign to the native API, such as clean up stacks
for Win32 implementations. For (2) the performance impact will be identical
to (1). The same for (3). For (4) things get a little more interesting and we
find that theoretically at least the thread_ref may perform faster since the
thread design requires dynamic memory allocation/deallocation. However, in practice
there may be dynamic allocation for the thread_ref design as well, it will just
be hidden from the user. As long as the implementation has to do dynamic allocations
the thread_ref loses again because of the reference management. For (5) we see
the same impact as we do for (4). For (6) we still have a possible impact to
the thread design because of dynamic allocation but thread_ref no longer suffers
because of its reference management, and in fact, theoretically at least, the
thread_ref may do a better job of managing the references. All of this indicates
that thread wins for (1), (2) and (3), with (4) and (5) the winner depends on
the implementation and the platform but the thread design probably has a better
chance, and with (6) it will again depend on the implementation and platform
but this time we favor thread_ref slightly. Given all of this it&#39;s a narrow
margin, but the thread design prevails.</p>
<p>Given this analysis, and the fact that noncopyable objects for system resources
are the normal designs that C++ programmers are used to dealing with, the <b>Boost.Threads</b>
<p>Given this analysis, and the fact that noncopyable objects for system resources
are the normal designs that C++ programmers are used to dealing with, the <b>Boost.Threads</b>
library has gone with a noncopyable design.</p>
<h2><a name="events"></a>Rationale for not providing <i>Event Variables</i></h2>
<p><i>Event variables</i> are simply far too error-prone. <a href=
"condition.html">Condition variables</a> are a much safer alternative.</p>
<p>[Note that Graphical User Interface <i>events</i> are a different concept,
<p>[Note that Graphical User Interface <i>events</i> are a different concept,
and are not what is being discussed here.]</p>
<p>Event variables were one of the first synchronization primitives. They are
<p>Event variables were one of the first synchronization primitives. They are
still used today, for example, in the native Windows multithreading API.</p>
<p>Yet both respected computer science researchers and experienced multithreading
practitioners believe event variables are so inherently error-prone that they
<p>Yet both respected computer science researchers and experienced multithreading
practitioners believe event variables are so inherently error-prone that they
should never be used, and thus should not be part of a multithreading library.</p>
<p>Per Brinch Hansen <a href="bibliography.html#Brinch-Hansen-73"> [Brinch Hansen
73]</a> analyzed event variables in some detail, pointing out [emphasis his]
that &quot;<i>event operations force the programmer to be aware of the relative
<p>Per Brinch Hansen <a href="bibliography.html#Brinch-Hansen-73"> [Brinch Hansen
73]</a> analyzed event variables in some detail, pointing out [emphasis his]
that &quot;<i>event operations force the programmer to be aware of the relative
speeds of the sending and receiving processes</i>&quot;. His summary:</p>
<blockquote>
<p>We must therefore conclude that event variables of the previous type are
impractical for system design. <i>The effect of an interaction between two
<blockquote>
<p>We must therefore conclude that event variables of the previous type are
impractical for system design. <i>The effect of an interaction between two
processes must be independent of the speed at which it is carried out.</i></p>
</blockquote>
<p>Experienced programmers using the Windows platform today report that event
variables are a continuing source of errors, even after previous bad experiences
caused them to be very careful in their use of event variables. Overt problems
can be avoided, for example, by teaming the event variable with a mutex, but
<p>Experienced programmers using the Windows platform today report that event
variables are a continuing source of errors, even after previous bad experiences
caused them to be very careful in their use of event variables. Overt problems
can be avoided, for example, by teaming the event variable with a mutex, but
that may just convert a <a href=
"definitions.html#Race condition">race condition</a> into another problem,
such as excessive resource use. One of the most distressing aspects of the experience
reports is the claim that many defects are latent. That is, the programs appear
to work correctly, but contain hidden timing dependencies which will cause them
to fail when environmental factors or usage patterns change, altering relative
"definitions.html#Race condition">race condition</a> into another problem,
such as excessive resource use. One of the most distressing aspects of the experience
reports is the claim that many defects are latent. That is, the programs appear
to work correctly, but contain hidden timing dependencies which will cause them
to fail when environmental factors or usage patterns change, altering relative
thread timings.</p>
<p>The decision to exclude event variables from <b>Boost.Threads</b> has been
surprising to some Windows programmers. They have written programs which work
using event variables, and wonder what the problem is. It seems similar to the
&quot;goto considered harmful&quot; controversy of 30 years ago. It isn&#39;t
that events, like gotos, can&#39;t be made to work, but rather that virtually
all programs using alternatives will be easier to write, debug, read, maintain,
<p>The decision to exclude event variables from <b>Boost.Threads</b> has been
surprising to some Windows programmers. They have written programs which work
using event variables, and wonder what the problem is. It seems similar to the
&quot;goto considered harmful&quot; controversy of 30 years ago. It isn&#39;t
that events, like gotos, can&#39;t be made to work, but rather that virtually
all programs using alternatives will be easier to write, debug, read, maintain,
and be less likely to contain latent defects.</p>
<p>[Rationale provided by Beman Dawes]</p>
<hr>
<p>Revised
<p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
05 November, 2001
05 November, 2001
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p>
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
All Rights Reserved.</i></p>
<p>Permission to use, copy, modify, distribute and sell this software and its
documentation for any purpose is hereby granted without fee, provided that the
above copyright notice appear in all copies and that both that copyright notice
and this permission notice appear in supporting documentation. William E. Kempf
makes no representations about the suitability of this software for any purpose.
<p>Permission to use, copy, modify, distribute and sell this software and its
documentation for any purpose is hereby granted without fee, provided that the
above copyright notice appear in all copies and that both that copyright notice
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 &quot;as is&quot; without express or implied warranty.</p>
</body>
</html>

View File

@@ -7,40 +7,40 @@
<body link="#0000ff" vlink="#800080">
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
"header">
<tr>
<td valign="top" width="300">
<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">
<td valign="top">
<h1 align="center">Boost.Threads</h1>
<h2 align="center">Header &lt;<a href="../../../boost/thread/recursive_mutex.hpp">boost/thread/recursive_mutex.hpp</a>&gt;</h2> </td>
</tr>
</table>
<hr>
<h2>Contents</h2>
<dl class="page-index">
<dl class="page-index">
<dt><a href="#introduction">Introduction</a></dt>
<dt><a href="#classes">Classes</a></dt>
<dl class="page-index">
<dl class="page-index">
<dt><a href="#class-recursive_mutex">Class <code>recursive_mutex</code></a></dt>
<dl class="page-index">
<dt><a href="#class-recursive_mutex-synopsis">Class <code>recursive_mutex</code>
<dl class="page-index">
<dt><a href="#class-recursive_mutex-synopsis">Class <code>recursive_mutex</code>
synopsis</a></dt>
<dt><a href="#class-recursive_mutex-ctors">Class <code>recursive_mutex</code>
<dt><a href="#class-recursive_mutex-ctors">Class <code>recursive_mutex</code>
constructors and destructor</a></dt>
</dl>
<dt><a href="#class-recursive_try_mutex">Class <code>recursive_try_mutex</code></a></dt>
<dl class="page-index">
<dt><a href="#class-recursive_try_mutex-synopsis">Class <code>recursive_try_mutex</code>
<dl class="page-index">
<dt><a href="#class-recursive_try_mutex-synopsis">Class <code>recursive_try_mutex</code>
synopsis</a></dt>
<dt><a href="#class-recursive_try_mutex-ctors">Class <code>recursive_try_mutex</code>
<dt><a href="#class-recursive_try_mutex-ctors">Class <code>recursive_try_mutex</code>
constructors and destructor</a></dt>
</dl>
<dt><a href="#class-recursive_timed_mutex">Class <code>recursive_timed_mutex</code></a></dt>
<dl class="page-index">
<dt><a href="#class-recursive_timed_mutex-synopsis">Class <code>recursive_timed_mutex</code>
<dl class="page-index">
<dt><a href="#class-recursive_timed_mutex-synopsis">Class <code>recursive_timed_mutex</code>
synopsis</a></dt>
<dt><a href="#class-recursive_timed_mutex-ctors">Class <code>recursive_timed_mutex</code>
<dt><a href="#class-recursive_timed_mutex-ctors">Class <code>recursive_timed_mutex</code>
constructors and destructor</a></dt>
</dl>
</dl>
@@ -65,26 +65,26 @@
lock concepts. For the best possible performance you should use the mutex class
that supports the minimum set of lock types that you need.</p>
<table summary="lock types" border="1" cellpadding="5">
<tr>
<tr>
<td><b>Mutex Class</b></td>
<td><b>Lock name</b></td>
<td><b>Lock Concept</b></td>
</tr>
<tr>
<tr>
<td valign="top"><a href="#recursive_mutex Synopsis"><code> recursive_mutex</code></a></td>
<td valign="middle"><code>scoped_lock</code></td>
<td valign="middle"><a href="lock_concept.html#ScopedLock"> ScopedLock</a></td>
</tr>
<tr>
<tr>
<td valign="top"><code><a href="#recursive_try_mutex Synopsis"> recursive_try_mutex</a></code></td>
<td valign="middle"><code>scoped_lock<br>
scoped_try_lock</code></td>
<td valign="middle"><a href="lock_concept.html#ScopedLock"> ScopedLock</a><br>
<a href="lock_concept.html#ScopedTryLock"> ScopedTryLock</a></td>
</tr>
<tr>
<tr>
<td valign="top"><code><a href=
"#recursive_timed_mutex Synopsis"> recursive_timed_mutex</a></code>
"#recursive_timed_mutex Synopsis"> recursive_timed_mutex</a></code>
</td>
<td valign="middle"><code>scoped_lock<br>
scoped_try_lock<br>
@@ -94,23 +94,23 @@
<a href="lock_concept.html#ScopedTimedLock"> ScopedTimedLock</a></td>
</tr>
</table>
<p>The <code>recursive_mutex</code>, <code>recursive_try_mutex</code> and <code>recursive_timed_mutex</code>
employ a <code>Recursive</code> <a href="mutex_concept.html#LockingStrategies">locking
strategy</a>, so attempts to recursively lock them succeed and an internal &quot;lock
count&quot; is maintained. Attempts to unlock them by a thread that does not
<p>The <code>recursive_mutex</code>, <code>recursive_try_mutex</code> and <code>recursive_timed_mutex</code>
employ a <code>Recursive</code> <a href="mutex_concept.html#LockingStrategies">locking
strategy</a>, so attempts to recursively lock them succeed and an internal &quot;lock
count&quot; is maintained. Attempts to unlock them by a thread that does not
own a lock on them will result in <b>undefined behavior</b>.</p>
<p>The <code>recursive_mutex</code>, <code>recursive_try_mutex</code> and <code>recursive_timed_mutex</code>
<p>The <code>recursive_mutex</code>, <code>recursive_try_mutex</code> and <code>recursive_timed_mutex</code>
leave the <a href=
"mutex_concept.html#SchedulingPolicies">scheduling policy</a> as <code>
Unspecified</code>. Programmers should assume that threads waiting for a lock
on objects of these types acquire the lock in a random order, even though the
"mutex_concept.html#SchedulingPolicies">scheduling policy</a> as <code>
Unspecified</code>. Programmers should assume that threads waiting for a lock
on objects of these types acquire the lock in a random order, even though the
specific behavior for a given platform may be different.</p>
<h2><a name="classes"></a>Classes</h2>
<h3><a name="class-recursive_mutex"></a>Class <code>recursive_mutex</code></h3>
<p>The <code>recursive_mutex</code> class is a model of <a href="mutex_concept.html#Mutex-concept">Mutex</a>
and <a href="overview.html#non-copyable">NonCopyable</a>, and provides no additional
<p>The <code>recursive_mutex</code> class is a model of <a href="mutex_concept.html#Mutex-concept">Mutex</a>
and <a href="overview.html#non-copyable">NonCopyable</a>, and provides no additional
facilities beyond the requirements of these concepts.</p>
<h4><a name="class-recursive_mutex-synopsis"></a>Class <code>recursive_mutex</code>
<h4><a name="class-recursive_mutex-synopsis"></a>Class <code>recursive_mutex</code>
synopsis</h4>
<pre>
namespace boost
@@ -120,33 +120,33 @@ namespace boost
{
public:
typedef [implementation defined; see Introduction] scoped_lock;
recursive_mutex();
~recursive_mutex();
};
};
</pre>
<h4><a name="class-recursive_mutex-ctors"></a>Class <code>recursive_mutex</code>
<h4><a name="class-recursive_mutex-ctors"></a>Class <code>recursive_mutex</code>
constructors and destructor</h4>
<pre>
recursive_mutex();
</pre>
<dl class="function-semantics">
<dl class="function-semantics">
<dt><b>Postconditions:</b> <code>*this</code> is in an unlocked state.</dt>
</dl>
<pre>
~recursive_mutex();
</pre>
<dl class="function-semantics">
<dl class="function-semantics">
<dt><b>Requires:</b> <code>*this</code> is in an unlocked sate.</dt>
<dt><b>Danger:</b> Destruction of a locked mutex is a serious programming error
<dt><b>Danger:</b> Destruction of a locked mutex is a serious programming error
resulting in undefined behavior such as a program crash.</dt>
</dl>
<h3><a name="class-recursive_try_mutex"></a>Class <code>recursive_try_mutex</code></h3>
<p>The <code>recursive_try_mutex</code> class is a model of <a href="mutex_concept.html#TryMutex-concept">TryMutex</a>
and <a href="overview.html#non-copyable">NonCopyable</a>, and provides no additional
<p>The <code>recursive_try_mutex</code> class is a model of <a href="mutex_concept.html#TryMutex-concept">TryMutex</a>
and <a href="overview.html#non-copyable">NonCopyable</a>, and provides no additional
facilities beyond the requirements of these concepts.</p>
<h4><a name="class-recursive_try_mutex-synopsis"></a>Class <code>recursive_try_mutex</code>
<h4><a name="class-recursive_try_mutex-synopsis"></a>Class <code>recursive_try_mutex</code>
synopsis</h4>
<pre>
namespace boost
@@ -157,33 +157,33 @@ namespace boost
Public:
typedef [implementation defined; see Introduction] scoped_lock;
typedef [implementation defined; see Introduction] scoped_try_lock;
recursive_try_mutex();
~recursive_try_mutex();
};
};
</pre>
<h4><a name="class-recursive_try_mutex-ctors"></a>Class <code>recursive_try_mutex</code>
<h4><a name="class-recursive_try_mutex-ctors"></a>Class <code>recursive_try_mutex</code>
constructors and destructor</h4>
<pre>
recursive_try_mutex();
</pre>
<dl class="function-semantics">
<dl class="function-semantics">
<dt><b>Postconditions:</b> <code>*this</code> is in an unlocked state.</dt>
</dl>
<pre>
~recursive_try_mutex();
</pre>
<dl class="function-semantics">
<dl class="function-semantics">
<dt><b>Requires:</b> <code>*this</code> is in an unlocked sate.</dt>
<dt><b>Danger:</b> Destruction of a locked mutex is a serious programming error
<dt><b>Danger:</b> Destruction of a locked mutex is a serious programming error
resulting in undefined behavior such as a program crash.</dt>
</dl>
<h3><a name="class-recursive_timed_mutex"></a>Class <code>recursive_timed_mutex</code></h3>
<p>The <code>recursive_timed_mutex</code> class is a model of <a href="mutex_concept.html#TimedMutex-concept">TimedMutex</a>
and <a href="overview.html#non-copyable">NonCopyable</a>, and provides no additional
<p>The <code>recursive_timed_mutex</code> class is a model of <a href="mutex_concept.html#TimedMutex-concept">TimedMutex</a>
and <a href="overview.html#non-copyable">NonCopyable</a>, and provides no additional
facilities beyond the requirements of these concepts.</p>
<h4><a name="class-recursive_timed_mutex-synopsis"></a>Class <code>recursive_timed_mutex</code>
<h4><a name="class-recursive_timed_mutex-synopsis"></a>Class <code>recursive_timed_mutex</code>
synopsis</h4>
<pre>
namespace boost
@@ -195,74 +195,30 @@ namespace boost
typedef [implementation defined; see Introduction] scoped_lock;
typedef [implementation defined; see Introduction] scoped_try_lock;
typedef [implementation defined; see Introduction] scoped_timed_lock;
recursive_timed_mutex();
~recursive_timed_mutex();
};
};
</pre>
<h4><a name="class-recursive_timed_mutex-ctors"></a>Class <code>recursive_timed_mutex</code>
<h4><a name="class-recursive_timed_mutex-ctors"></a>Class <code>recursive_timed_mutex</code>
constructors and destructor</h4>
<pre>
recursive_timed_mutex();
</pre>
<dl class="function-semantics">
<dl class="function-semantics">
<dt><b>Postconditions:</b> <code>*this</code> is in an unlocked state.</dt>
</dl>
<pre>
~recursive_timed_mutex();
</pre>
<dl class="function-semantics">
<dl class="function-semantics">
<dt><b>Requires:</b> <code>*this</code> is in an unlocked sate.</dt>
<dt><b>Danger:</b> Destruction of a locked mutex is a serious programming error
<dt><b>Danger:</b> Destruction of a locked mutex is a serious programming error
resulting in undefined behavior such as a program crash.</dt>
</dl>
<h2><a name="examples"></a>Example(s)</h2>
<pre>
#include <a href="../../../boost/thread/recursive_mutex.hpp">&lt;boost/thread/recursive_mutex.hpp&gt;</a>
#include <a href="../../../boost/thread/thread.hpp">&lt;boost/thread/thread.hpp&gt;</a>
#include &lt;iostream&gt;
class counter
{
public:
counter() : count(0) { }
int add(int val) {
boost::recursive_mutex::scoped_lock scoped_lock(mutex);
count += val;
return count;
}
int increment() {
boost::recursive_mutex::scoped_lock scoped_lock(mutex);
return add(1);
}
private:
boost::recursive_mutex mutex;
int count;
};
counter c;
void change_count(void*)
{
std::cout &lt;&lt; &quot;count == &quot; &lt;&lt; c.increment() &lt;&lt; std::endl;
}
int main(int, char*[])
{
const int num_threads=4;
boost::thread_group threads;
for (int i=0; i &lt; num_threads; ++i)
threads.create_thread(&amp;change_count, 0);
threads.join_all();
return 0;
}
</pre>
<p><a href="../example/recursive_mutex.cpp">libs/thread/example/recursive_mutex.cpp</a></p>
<p>The output is:</p>
<pre>
count == 1
@@ -271,18 +227,18 @@ count == 3
count == 4
</pre>
<hr>
<p>Revised
<p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
05 November, 2001
05 November, 2001
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p>
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
All Rights Reserved.</i></p>
<p>Permission to use, copy, modify, distribute and sell this software and its
documentation for any purpose is hereby granted without fee, provided that the
above copyright notice appear in all copies and that both that copyright notice
and this permission notice appear in supporting documentation. William E. Kempf
makes no representations about the suitability of this software for any purpose.
<p>Permission to use, copy, modify, distribute and sell this software and its
documentation for any purpose is hereby granted without fee, provided that the
above copyright notice appear in all copies and that both that copyright notice
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 &quot;as is&quot; without express or implied warranty.</p>
</body>
</html>

247
doc/rw_lock_concept.html Normal file
View File

@@ -0,0 +1,247 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<link rel="stylesheet" type="text/css" href="../../../boost.css">
<title>Boost.Threads - RWLock Concepts</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">RWLock Concepts</h2>
</td>
</tr>
</table>
<hr>
<dl class="index">
<dt><a href="#introduction">Introduction</a></dt>
<dt><a href="#requirements">Concept Requirements</a></dt>
<dl class="index">
<dt><a href="#lock-state-enumeration">Lock State Enumeration</a></dt>
<dt><a href="#RWLock-concept">RWLock Concept</a></dt>
<dt><a href="#ScopedRWLock-concept">ScopedRWLock Concept</a></dt>
<dt><a href="#ScopedTryRWLock-concept">ScopedTryRWLock Concept</a></dt>
<dt><a href="#ScopedTimedRWLock-concept">ScopedTimedRWLock Concept</a></dt>
</dl>
<dt><a href="#models">Models</a></h2>
<dt><a href="#footnotes">Footnotes</a></dt>
</dl>
<h2><a name="introduction"></a>Introduction</h2>
<p>The lock concepts provide exception safe means for locking and unlocking a
<a href="rw_mutex_concept.html"> rw_mutex model</a>. In other words they are
an implementation of the <i>Scoped Locking</i> <a href="bibliography.html#Schmidt 00">[Schmidt
00]</a> pattern. The <a href="#ScopedRWLock">ScopedRWLock</a> concept, with
<a href="#ScopedTryRWLock"> ScopedTryRWLock</a> and <a href="#ScopedTimedRWLock">ScopedTimedRWLock</a>
refinements, formalize the requirements.</p>
<p>Lock models are constructed with a reference to a <a href="mutex_concept.html">mutex
model</a> and typically acquire ownership of the <a href="mutex_concept.html">mutex
model</a> by setting its state to locked. They also ensure ownership is relinquished
in the destructor. Lock models also expose functions to query the lock status
and to manually lock and unlock the <a href="mutex_concept.html">mutex model</a>.</p>
<p>Instances of lock models are meant to be short lived, expected to be used at
block scope only. The lock models are not <a href="definitions.html#Thread-safe">thread-safe</a>.
Lock models must maintain state to indicate whether or not they've been locked
and this state is not protected by any synchronization concepts. For this reason
an instance of a lock model should never be shared between multiple threads.</p>
<h2><a name="requirements"></a>Concept Requirements</h2>
<p>[For documentation purposes, portions of the concept requirements are repeated
in the documentation for specific lock classes. Those copies need to be kept
in sync with the requirements here.]</p>
<h3><a name="lock-state-enumeration"></a>Lock State Enumeration</h3>
<p>An enumerated value that can be one of three possible values - {NO_LOCK, SHARED_LOCK,
or EXCL_LOCK).&nbsp; Each class modeling the Lock Concept will maintain this
state as its view of the lock-state of the controlled rw_mutex.</p>
<h3><a name="RWLock-concept"></a>RWLock Concept</h3>
<p>For a <a href="#ScopedRWLock">ScopedRWLock</a>, <a href="#ScopedTryRWLock">ScopedTryRWLock</a>,
or <a href="#ScopedTimedRWLock">ScopedTimedRWLock</a> type <code>L</code> and
an object <code>lk</code> and const object <code>clk</code> of that type, the
following expressions must be well-formed and have the indicated effects.</p>
<p>The Lock concept is used as a base for the <a href="#ScopedRWLock">ScopedRWLock</a>,
<a href="#ScopedTryRWLock">ScopedTryRWLock</a>, and <a href="#ScopedTimedRWLock">ScopedTimedRWLock</a>
refinements. The associated rw_mutex type is as specified for each of those
refinements respectively.</p>
<table summary="Lock expressions" border="1" cellpadding="5">
<tr>
<td><b>Expression</b></td>
<td><b>Effects</b></td>
</tr>
<tr>
<td valign="top"><code>(&amp;lk)-&gt;~L();</code></td>
<td><code>if (locked()) unlock();</code></td>
</tr>
<tr>
<td valign="top"><code>(&amp;clk)-&gt;operator const void*()</code></td>
<td>Returns type void*, non-zero if if the associated rw_mutex has been locked
by <code> clk</code>, otherwise 0.</td>
</tr>
<tr>
<td valign="top"><code>clk.locked()</code></td>
<td>Returns a <code>bool</code>, <code>(&amp;clk)-&gt;operator const void*()
!= 0</code></td>
</tr>
<tr>
<td valign="top"><code>clk.lockstate()</code></td>
<td><code>Returns an enumeration of the lock state,&nbsp;NO_LOCK, EXCL_LOCK
or SHARED_LOCK</code></td>
</tr>
<tr>
<td valign="top"><code>lk.wrlock()</code></td>
<td>Throws lock_error if locked(). If the associated rw_mutex is already locked
by some other thread, places the current thread in the <a href="definitions.html#State">
Blocked</a> state until the associated rw_mutex is unlocked, after which
the current thread is placed in the <a href="definitions.html#State">Ready</a>
state, eventually to be returned to the <a href="definitions.html#State">Running</a>
state.<br>
Postcondition: locked() and lockstate() == EXCL_LOCK</td>
</tr>
<tr>
<td valign="top"><code>lk.rdlock()</code></td>
<td>Throws lock_error if locked().&nbsp; If the associated rw_mutex cannot
immediately grant the shared lock, places the current thread in the <a href="definitions.html#State">
Blocked</a> state until the associated rw_ mutex can grant a shared lock,
after which the current thread is placed in the <a href="definitions.html#State">Ready</a>
state, eventually to be returned to the <a href="definitions.html#State">Running</a>
state.&nbsp;<br>
Postcondition: locked() and lockstate() == SHARED_LOCK</td>
</tr>
<tr>
<td valign="top"><code>lk.unlock()</code></td>
<td>If !locked(), throws lock_error, otherwise unlocks the associated rw_mutex.<br>
Postcondition: !locked()</td>
</tr>
</table>
<h3><a name="ScopedRWLock-concept"></a>ScopedRWLock Concept</h3>
<p>A ScopedRWLock must meet the <a href="#Lock">RWLock</a> requirements. For a
ScopedRWLock type <code>L</code> and an object <code>lk</code> of that type,
and an object <code>m</code> of a type meeting the <a href="mutex_concept.html#Mutex">
RWMutex</a> requirements, and an object <code>s</code> of type <code>lock_state</code>,
the following expressions must be well-formed and have the indicated effects.</p>
<table summary="ScopedRWLock expressions" border="1" cellpadding="5" width="732">
<tr>
<td width="91"><b>Expression</b></td>
<td width="609"><b>Effects</b></td>
</tr>
<tr>
<td valign="top" width="91"><code>L lk(m);</code></td>
<td width="609">Constructs an object <code>lk</code>, and associates rw_mutex
<code>m</code> with it, then calls <code>lock()</code></td>
</tr>
<tr>
<td valign="top" width="91"><code>L lk(m,s);</code></td>
<td width="609">Constructs an object <code>lk</code>, and associates rw_mutex
<code>m</code> with it, then if <code>s==SHARED_LOCK</code>, calls <code>sharedlock()
or if s==EXCL_LOCK then calls lock()</code></td>
</tr>
</table>
<h3><a name="ScopedTryRWLock-concept"></a>ScopedTryRWLock Concept</h3>
<p>A ScopedTryRWLock must meet the <a href="#Lock">RWLock</a> requirements. For
a ScopedTryRWLock type <code>L</code> and an object <code>lk</code> of that
type, and an object <code>m</code> of a type meeting the <a href="mutex_concept.html#TryMutex">
TryRWMutex</a> requirements, and an object <code>s</code> of type <code>lock_state</code>,
the following expressions must be well-formed and have the indicated effects.</p>
<table summary="ScopedTryRWLock expressions" border="1" cellpadding="5">
<tr>
<td width="157"><b>Expression</b></td>
<td><b>Effects</b></td>
</tr>
<tr>
<td valign="top" width="157"><code>L lk(m);</code></td>
<td>Constructs an object <code>lk</code>, and associates rw_mutex <code>m</code>
with it, then calls <code>try_lock()</code></td>
</tr>
<tr>
<td valign="top" width="157"><code>L lk(m,s);</code></td>
<td>Constructs an object <code>lk</code>, and associates rw_mutex <code>m</code>
with it, then if <code>s==SHARED_LOCK</code>, calls <code>sharedlock() or
if s==EXCL_LOCK then calls lock()</code></td>
</tr>
<tr>
<td valign="top" width="157"><code>lk.try_wrlock()</code></td>
<td>If locked(), throws <code>lock_error</code>. Makes a non-blocking attempt
to exclusive-lock the associated rw_mutex, returning <code>true</code> if
the lock attempt is successful, otherwise <code>false</code>.</td>
</tr>
<tr>
<td valign="top" width="157"><code>lk.try_rdlock()</code></td>
<td>If locked(), throws <code>lock_error</code>. Makes a non-blocking attempt
to shared-lock the associated rw_mutex, returning <code>true</code> if the
lock attempt is successful, otherwise <code>false</code>.</td>
</tr>
</table>
<h3><a name="ScopedTimedRWLock-concept"></a>ScopedTimedRWLock Concept</h3>
<p>A ScopedTimedRWLock must meet the <a href="#Lock">RWLock</a> requirements.
For a ScopedTimedRWLock type <code>L</code> and an object <code>lk</code> of
that type, and an object <code>m</code> of a type meeting the <a href="mutex_concept.html#TimedMutex">
TimedRWMutex</a> requirements, and an object <code>s</code> of type <code>lock_state</code>,
and an object <code>t</code> of type <code><a href="xtime.html">xtime</a></code>,
the following expressions must be well-formed and have the indicated effects.</p>
<table summary="ScopedTimedRWLock expressions" border="1" cellpadding="5">
<tr>
<td width="164"><b>Expression</b></td>
<td><b>Effects</b></td>
</tr>
<tr>
<td valign="top" width="164"><code>L lk(m,t);</code></td>
<td>Constructs an object <code>lk</code>, and associates rw_mutex <code>m</code>
with it, then calls <code>timed_lock(t)</code></td>
</tr>
<tr>
<td valign="top" width="164"><code>L lk(m,s);</code></td>
<td>Constructs an object <code>lk</code>, and associates rw_ mutex <code>m</code>
with it, then if <code>s==SHARED_LOCK</code>, calls <code>sharedlock() or
if s==EXCL_LOCK then calls lock()</code></td>
</tr>
<tr>
<td valign="top" width="164"><code>lk.timed_wrlock(t)</code></td>
<td>If locked(), throws lock_error. Makes a blocking attempt to exclusive-lock
the associated rw_mutex, and returns <code>true</code> if successful within
the specified time <code>t</code>, otherwise <code>false</code>.</td>
</tr>
<tr>
<td valign="top" width="164"><code>lk.timed_rdlock(t)</code></td>
<td>If locked(), throws lock_error. Makes a blocking attempt to shared-lock
the associated rw_mutex, and returns <code>true</code> if successful within
the specified time <code>t</code>, otherwise <code>false</code>.</td>
</tr>
</table>
<h2><a name="models"></a>Models</h2>
<p><b>Boost.Threads</b> currently supplies three classes which model lock concepts.</p>
<p>These classes are normally accessed via typedefs of the same name supplied
by a <a href="mutex_concept.html"> mutex model</a>.</p>
<table summary="Lock concept classes" border="1" cellpadding="5">
<tr>
<td><b>Concept</b></td>
<td><b>Refines</b></td>
<td><b>Classes Modeling the Concept</b></td>
</tr>
<tr>
<td><a href="#ScopedRWLock">ScopedRWLock</a></td>
<td>&nbsp;</td>
<td><a href="scoped_rw_lock.html">scoped_rw_lock</a></td>
</tr>
<tr>
<td><a href="#ScopedTryRWLock">ScopedTryRWLock</a></td>
<td><a href="#ScopedRWLock">ScopedRWLock</a></td>
<td><a href="scoped_try_rw_lock.html">scoped_try_rw_lock</a> </td>
</tr>
<tr>
<td><a href="#ScopedTimedRWLock">ScopedTimedRWLock</a></td>
<td><a href="#ScopedRWLock">ScopedRWLock</a></td>
<td><a href="scoped_timed_rw_lock.html">scoped_timed_rw_lock</a></td>
</tr>
</table>
<hr>
<p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
05 November, 2001
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p>
<p><i>&copy; Copyright <a href="mailto:{{address}}">{{author}}</a> 2002. All Rights
Reserved.</i></p>
</body>
</html>

353
doc/rw_mutex.html Normal file
View File

@@ -0,0 +1,353 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<link rel="stylesheet" type="text/css" href="../../../boost.css">
<title>Boost.Threads - Header &lt;boost/thread/rw_mutex.hpp&gt;</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">Header &lt;<a href="../../../boost/thread/rw_mutex.hpp">boost/thread/rw_mutex.hpp</a>&gt;</h2>
</td>
</tr>
</table>
<hr>
<h2>Contents</h2>
<dl class="page-index">
<dt><a href="#introduction">Introduction</a></dt>
<dt><a href="#macros">Macros</a></dt>
<dl class="page-index">
<dt><a href="#macro-spec">{{macro name}}</a></dt>
</dl>
<dt><a href="#values">Values</a></dt>
<dl class="page-index">
<dt><a href="#value-spec">{{value name}}</a></dt>
</dl>
<dt><a href="#types">Types</a></dt>
<dl class="page-index">
<dt><a href="#type-spec">{{type name}}</a></dt>
</dl>
<dt><a href="#classes">Classes</a></dt>
<dl class="page-index">
<dt><a href="#class-spec">Class <code>{{class name}}</code></a></dt>
<dl class="page-index">
<dt><a href="#class-spec-synopsis">Class <code>{{class name}}</code> synopsis</a></dt>
<dt><a href="#class-spec-ctors">Class <code>{{class name}}</code> constructors
and destructor</a></dt>
<dt><a href="#class-spec-comparisons">Class <code>{{class name}}</code>
comparison functions</a></dt>
<dt><a href="#class-spec-modifiers">Class <code>{{class name}}</code> modifier
functions</a></dt>
<dt><a href="#class-spec-observers">Class <code>{{class name}}</code> observer
functions</a></dt>
<dt><a href="#class-spec-statics">Class <code>{{class name}}</code> static
functions</a></dt>
</dl>
</dl>
<dt><a href="#functions">Functions</a></dt>
<dl class="page-index">
<dt><a href="#function-spec">{{function name}}</a></dt>
</dl>
<dt><a href="#objects">Objects</a></dt>
<dl class="page-index">
<dt><a href="#object-spec">{{object name}}</a></dt>
</dl>
<dt><a href="#examples">Example(s)</a></dt>
</dl>
<hr>
<h2><a name="introduction"></a>Introduction</h2>
<p>The <tt><a href="#rw_mutex Synopsis">rw_mutex</a></tt>, <tt><a href="#try_rw_mutex Synopsis">
try_rw_mutex</a></tt> and <tt><a href="#timed_rw_mutex Synopsis">timed_rw_mutex</a></tt>
classes define full featured models of the <a href="rw_mutex_concept.html#rw_mutex">
RWMutex</a>, <a href="rw_mutex_concept.html#TryMutex">TryRWMutex</a>, and <a href="rw_mutex_concept.html#TimedMutex">
TimedRWMutex</a> concepts. These types should be used to synchronize access
to shared resources.&nbsp; Recursive or non-recursive locking mechanics are
acheived by supplying the appropriate Mutex type as a parameter.</p>
<p>Each class supplies one or more typedefs for lock types which model matching
lock concepts. For the best possible performance you should use the rw_mutex
class that supports the minimum set of lock types that you need.</p>
<table summary="lock types" border="1" cellpadding="5">
<tr>
<td><b>rw_mutex Class</b></td>
<td><b>Lock name</b></td>
<td><b>Implementation defined Lock Type</b></td>
<td><b>Lock Concept</b></td>
</tr>
<tr>
<td valign="top"><a href="#rw_mutex Synopsis"><code> rw_mutex</code></a></td>
<td valign="center"><code> scoped_rw_lock</code></td>
<td valign="center"><code><a href="scoped_lock.html">boost::</a></code><a href="scoped_lock.html"><code>detail::thread::scoped_rw_lock&lt;rw_mutex&gt;</code></a></td>
<td valign="center">ScopedRWLock</td>
</tr>
<tr>
<td valign="top"><tt><a href="#try_rw_mutex Synopsis"> try_rw_mutex</a></tt>
</td>
<td valign="center"><code> scoped_rw_lock<br>
scoped_try_rw_lock</code></td>
<td valign="center"><code><a href="scoped_lock.html">boost::</a></code><a href="scoped_lock.html"><code>detail::thread::scoped_rw_lock&lt;try_rw_mutex&gt;</code></a>
<code><a href="scoped_try_lock.html"> <br>
</a><a href="scoped_lock.html">boost::</a></code><a href="scoped_lock.html"><code>detail::thread::scoped_try_rw_lock&lt;try_rw_mutex&gt;</code></a></td>
<td valign="center">ScopedRWLock<br>
ScopedRWTryLock</td>
</tr>
<tr>
<td valign="top"><code><a href="#timed_rw_mutex Synopsis"> timed_rw_mutex</a></code>
</td>
<td valign="center"><code> scoped_rw_lock<br>
scoped_try_rw_lock<br>
scoped_timed_rw_lock</code></td>
<td valign="center"><code><a href="scoped_lock.html">boost::</a></code><a href="scoped_lock.html"><code>detail::thread::scoped_rw_lock&lt;timed_rw_mutex&gt;</code></a>
<code><a href="scoped_try_lock.html"> <br>
</a><a href="scoped_lock.html">boost::</a></code><a href="scoped_lock.html"><code>detail::thread::scoped_try_rw_lock&lt;timed_rw_mutex&gt;</code></a><a href="scoped_timed_lock.html"><code><br>
</code></a><code><a href="scoped_lock.html">boost::</a></code><a href="scoped_lock.html"><code>detail::thread::scoped_timed_rw_lock&lt;timed_rw_mutex&gt;</code></a></td>
<td valign="center">ScopedRWLock<br>
ScopedRWTryLock<br>
ScopedRWTimedLock</td>
</tr>
</table>
<p>The <tt>rw_mutex</tt>, <tt>try_rw_mutex</tt> and <tt>timed_rw_mutex</tt> classes
leave the locking strategy as Unspecified.&nbsp; Programmers should assume that
threads that lock a rw_mutex, try_rw_mutex, or timed_rw_mutex multiple times
will deadlock, unless all of the lock requests are for read-locks.&nbsp;&nbsp;</p>
<p>The <tt>rw_mutex</tt>, <tt>try_rw_mutex</tt> and <tt>timed_rw_mutex</tt> allow
the programmer to explicitly choose&nbsp;the <a href="rw_mutex_concept.html#SchedulingPolicies">
scheduling policy</a> for the lock.&nbsp; This scheduling policy will dictate
how competing readers and writers will acquire the lock.&nbsp; It does not,
however, dictate the order that individual read or write requests will be granted,
in comparison to other requests of the same type.&nbsp;&nbsp;Programmers should
assume that threads waiting for a lock on objects of these types acquire the
lock in a random order, even though the specific behavior for a given platform
may be different.</p>
<H2>Release Notes/Caveats</H2>
<UL>
<LI> Self-deadlock is virtually guaranteed if a thread tries to lock the same
rw_mutex multiple times, unless all locks are read-locks (but see below)</LI>
<LI> This implementation does not protect against reader overflow.&nbsp; If
more than INT_MAX readers obtain or try to obtain a lock simultaneously, the
behavior is undefined.&nbsp; This will be addressed in a future release, but
it seems that detecting this condition &amp; reporting an error or throwing
an exception should suffice for realistic uses.&nbsp; Having readers beyond
INT_MAX wait for the count to decrease only pushes the overflow problem onto
another variable...&nbsp; Suggestions?</LI>
<LI> See the comments at the head of rw_mutex.cpp for a description of the implementation
itself.</LI>
</UL>
<h2><a name="macros"></a>Macros</h2>
<p><a name="macro-spec"></a>{{Macro specifications}}</p>
<h2><a name="values"></a>Values</h2>
<pre>
namespace boost {
typedef enum
{
sp_writer_priority,
sp_reader_priority,
sp_alternating_many_reads,
sp_alternating_single_reads
} rw_scheduling_policy;
typedef enum
{
NO_LOCK,
SHARED_LOCK,
EXCL_LOCK
} lockstate;
}
</pre>
<h2><a name="types"></a>Types</h2>
<p><a name="type-spec"></a>{{Type specifications}}</p>
<h2><a name="classes"></a>Classes</h2>
<h3><a name="class-rw_mutex"></a>Class <code>rw_mutex</code></h3>
<p>{{text}}</p>
<h4><a name="class-rw_mutex-synopsis"></a>Class <code>rw_mutex</code> synopsis</h4>
<pre>
namespace boost
{
class rw_mutex : private <a href="../../utility/utility.htm">boost::noncopyable</a> // Exposition only.
// Class mutex meets the <a href="overview.html#non-copyable">NonCopyable</a> requirement.
{
public:
typedef <i>[implementation defined; see <a href="#introduction">Introduction</a>]</i> scoped_rw_lock;
rw_mutex(rw_scheduling_policy sp=sp_writer_priority);
~rw_mutex();
};
};
</pre>
<h4><a name="class-rw_mutex-ctors"></a>Class <code>rw_mutex</code> constructors
and destructor</h4>
<pre>
rw_mutex(rw_scheduling_policy sp=sp_writer_priority);
</pre>
<dl class="function-semantics">
<dt><b>Postconditions:</b> <code>*this</code> is in the NO_LOCK state.</dt>
</dl>
<pre>
~rw_mutex();
</pre>
<dl class="function-semantics">
<dt><b>Requires:</b> <code>*this</code> is in the NO_LOCK state.</dt>
<dt><b>Effects:</b> Destroys <code>*this</code>.</dt>
<dt><b>Danger:</b> Destruction of a locked rw_mutex is a serious programming
error resulting in undefined behavior such as a program crash.</dt>
</dl>
<h3><a name="class-rw_try_mutex"></a>Class <code>rw_try_mutex</code></h3>
<p>{{text}}</p>
<h4><a name="class-rw_try_mutex-synopsis"></a>Class <code>rw_try_mutex</code>
synopsis</h4>
<pre>
namespace boost
{
class rw_mutex : private <a href="../../utility/utility.htm">boost::noncopyable</a> // Exposition only.
// Class mutex meets the <a href="overview.html#non-copyable">NonCopyable</a> requirement.
{
public:
typedef <i>[implementation defined; see <a href="#introduction">Introduction</a>]</i> scoped_rw_lock;
typedef <i>[implementation defined; see <a href="#introduction">Introduction</a>]</i> scoped_rw_try_lock;
rw_try_mutex(rw_scheduling_policy sp=sp_writer_priority);
~rw_try_mutex();
};
};
</pre>
<h4><a name="class-rw_try_mutex-ctors"></a>Class <code>rw_try_mutex</code> constructors
and destructor</h4>
<pre>
rw_try_mutex(rw_scheduling_policy sp=sp_writer_priority);
</pre>
<dl class="function-semantics">
<dt><b>Postconditions:</b> <code>*this</code> is in the NO_LOCK state.</dt>
</dl>
<pre>
~rw_try_mutex();
</pre>
<dl class="function-semantics">
<dt><b>Requires:</b> <code>*this</code> is in the NO_LOCK state.</dt>
<dt><b>Effects:</b> Destroys <code>*this</code>.</dt>
<dt><b>Danger:</b> Destruction of a locked rw_mutex is a serious programming
error resulting in undefined behavior such as a program crash.</dt>
</dl>
<h3><a name="class-rw_timed_mutex"></a>Class <code>rw_timed_mutex</code></h3>
<p>{{text}}</p>
<h4><a name="class-rw_timed_mutex-synopsis"></a>Class <code>rw_timed_mutex</code>
synopsis</h4>
<pre>
namespace boost
{
class rw_timed_mutex : private <a href="../../utility/utility.htm">boost::noncopyable</a> // Exposition only.
// Class mutex meets the <a href="overview.html#non-copyable">NonCopyable</a> requirement.
{
public:
typedef <i>[implementation defined; see <a href="#introduction">Introduction</a>]</i> scoped_rw_lock;
typedef <i>[implementation defined; see <a href="#introduction">Introduction</a>]</i> scoped_rw_try_lock;
typedef <i>[implementation defined; see <a href="#introduction">Introduction</a>]</i> scoped_rw_timed_lock;
rw_timed_mutex(rw_scheduling_policy sp=sp_writer_priority);
~rw_timed_mutex();
};
};
</pre>
<h4><a name="class-rw_timed_mutex-ctors"></a>Class <code>rw_timed_mutex</code>
constructors and destructor</h4>
<pre>
rw_timed_mutex(rw_scheduling_policy sp=sp_writer_priority);
</pre>
<dl class="function-semantics">
<dt><b>Postconditions:</b> <code>*this</code> is in the NO_LOCK state.</dt>
</dl>
<pre>
~rw_timed_mutex();
</pre>
<dl class="function-semantics">
<dt><b>Requires:</b> <code>*this</code> is in the NO_LOCK state.</dt>
<dt><b>Effects:</b> Destroys <code>*this</code>.</dt>
<dt><b>Danger:</b> Destruction of a locked rw_mutex is a serious programming
error resulting in undefined behavior such as a program crash.</dt>
</dl>
<h2><a name="examples"></a>Example(s)</h2>
<pre>
#include <a href="../../../boost/thread/rw_mutex.hpp">&lt;boost/thread/rw_mutex.hpp&gt;</a>
#include &lt;boost/thread/mutex.hpp&gt;
#include <a href="../../../boost/thread/thread.hpp">&lt;boost/thread/thread.hpp&gt;</a>
#include &lt;iostream&gt;
boost::mutex io_mutex; // The iostreams are not guaranteed to be <a href="definitions.html#Thread-safe">thread-safe</a>!
class counter
{
public:
counter() : count(0) { }
int increment() {
boost::rw_mutex::scoped_lock scoped_rw_lock(rw_mutex);
return ++count;
}
int get() {
boost::rw_mutex::scoped_lock scoped_rw_lock(rw_mutex,SHARED_LOCK);
return count;
}
private:
boost::rw_mutex rwm(boost::sp_writer_priority);
int count;
};
counter c;
void change_count(void*)
{
int i = c.increment();
boost::rw_mutex::scoped_lock scoped_lock(io_mutex);
std::cout &lt;&lt; "count == " &lt;&lt; i &lt;&lt; std::endl;
}
void get_count(void*)
{
int i = c.get();
boost::rw_mutex::scoped_lock scoped_lock(io_mutex);
std::cout &lt;&lt; "get_count == " &lt;&lt; i &lt;&lt; std::endl;
}
int main(int, char*[])
{
const int num_threads = 4;
boost::thread_group thrds;
for (int i=0; i &lt; num_threads; ++i)
{
thrds.create_thread(&amp;change_count, 0);
thrds.create_thread(&amp;get_count,0);
}
thrds.join_all();
return 0;
}
</pre>
<p>Typicial output might be:</p>
<pre>
count == 1
get_count == 1
get_count == 1
count == 2
count == 3
get_count == 3
count == 4
get_count == 4
</pre>
<p>Of course, exact output is platform dependent since the locking behavior with
competing readers and writers is undefined.</p>
<p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
05 November, 2001
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p>
<p><i>&copy; Copyright <a href="mailto:{{address}}">{{author}}</a> 2002. All Rights
Reserved.</i></p>
</body>
</html>

611
doc/rw_mutex_concept.html Normal file
View File

@@ -0,0 +1,611 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<link rel="stylesheet" type="text/css" href="../../../boost.css">
<title>Boost.Threads - RWMutex Concept</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">RWMutex Concept</h2>
</td>
</tr>
</table>
<hr>
<dl class="index">
<dt><a href="#introduction">Introduction</a></dt>
<dt><a href="#locking-strategies">Locking Strategies</a></dt>
<dl class="page-index">
<dt><a href="#locking-strategy-recursive">Recursive</a></dt>
<dt><a href="#locking-strategy-checked">Checked</a></dt>
<dt><a href="#locking-strategy-unchecked">Unchecked</a></dt>
<dt><a href="#locking-strategy-unspecified">Unspecified</a></dt>
</dl>
<dt><a href="#scheduling-policies">Scheduling Policies</a></dt>
<dt><a href="#requirements">Concept Requirements</a></dt>
<dt><a href="#models">Models</a></dt>
</dl>
<h2><a name="introduction"></a>Introduction</h2>
<p>A rw_mutex (short for reader-writer mutual-exclusion) concept serializes access
to a resource shared between multiple threads, where multiple readers can share
simultaneous access, but writers require exclusive access.&nbsp; The <a href="#Mutex">
RWMutex</a> concept, with <a href="#TryMutex">TryRWMutex</a> and <a href="#TimedMutex">
TimedRWMutex</a> refinements, formalize the requirements. A model that implements
RWMutex and its refinements has three states: <b>shared-locked</b> ,<b>exclusive-locked</b>
and <b>unlocked</b>. Before reading from a&nbsp; shared resource, a thread <b>shared-locks</b>
a Boost.Threads rw_mutex model object, insuring <a href="definitions.html#Thread-safe">
thread-safe</a> access for reading from the shared resource. Before writing
to a shared resource, a thread <b>exclusive-locks</b> a Boost.Threads rw_mutex
model object, insuring <a href="definitions.html#Thread-safe">thread-safe</a>
access for altering the shared resource.&nbsp; When use of the shared resource
is complete, the thread unlocks the mutex model object, allowing another thread
to acquire the lock and use the shared resource.</p>
<p> Some traditional C thread APIs like Pthreads provide implementations for rw_mutex
(also known as reader-writer locks).&nbsp; Others like Windows thread APIs do
not provide a rw_mutex primitive.&nbsp; Some of those APIs expose functions
to lock and unlock a rw_mutex model. This is dangerous since it's easy to forget
to unlock a locked rw_mutex. When the flow of control is complex, with multiple
return points, the likelihood of forgetting to unlock a rw_mutex model would
become even greater. When exceptions are thrown, it becomes nearly impossible
to ensure that the rw_mutex is unlocked properly when using these traditional
API's. The result is <a href="definitions.html#Deadlock">deadlock</a>.</p>
<p>Many C++ threading libraries use a pattern known as <i>Scoped Locking</i> <a href="bibliography.html#Schmidt 00">
[Schmidt 00]</a> to free the programmer from the need to explicitly lock and
unlock rw_mutexes. With this pattern, a <a href="lock_concept.html">lock concept</a>
is employed where the lock model's constructor locks the associated rw_mutex
model and the destructor automatically does the unlocking. The <b>Boost.Threads</b>
library takes this pattern to the extreme in that lock concepts are the only
way to lock and unlock a rw_mutex model: lock and unlock functions are not exposed
by any <b>Boost.Threads</b> rw_mutex models. This helps to ensure safe usage
patterns, especially when code throws exceptions.</p>
<h2><a name="locking-strategies"></a>Locking Strategies</h2>
<P>Every rw_mutex model follows one of several locking strategies. These strategies
define the semantics for the locking operation when the calling thread already
owns a lock on the rw_mutex model.</P>
<h3><a name="locking-strategy-recursive"></a>Recursive</h3>
<P>With a recursive locking strategy when a thread attempts to acquire an additional&nbsp;lock
on the rw_mutex model for which it already owns a lock, the operation is successful,
except&nbsp;possibly in the case where a shared-lock holding thread attempts
to&nbsp;obtain an exclusive lock.&nbsp; </P>
<P>
<TABLE id="Table9" width="100%" border="1">
<TR>
<TD width="22%">Lock Type Held</TD>
<TD width="18%">Lock Request Type</TD>
<TD width="60%">Action</TD>
</TR>
<TR>
<TD width="22%">shared-lock</TD>
<TD width="18%">shared-lock</TD>
<TD width="60%">Grant the shared lock immediately</TD>
</TR>
<TR>
<TD width="22%">shared-lock</TD>
<TD width="18%">exclusive-lock</TD>
<TD width="60%">
<P>If this thread is the only holder of the shared-lock, grants the exclusive
lock immediately.&nbsp; Otherwise throws lock_error() exception.</P>
</TD>
</TR>
<TR>
<TD width="22%">exclusive-locked</TD>
<TD width="18%">shared-lock</TD>
<TD width="60%">Grants the (additional) shared lock immediately.</TD>
</TR>
<TR>
<TD width="22%">exclusive-locked</TD>
<TD width="18%">exclusive-lock</TD>
<TD width="60%"> Grant the exclusive lock immediately</TD>
</TR>
</TABLE>
<P>Internally a lock count is maintained and the owning thread must unlock the
mutex model the same number of times that it's locked it before the mutex model's
state returns to unlocked. Since mutex models in <B>Boost.Threads</B> expose
locking functionality only through lock concepts, a thread will always unlock
a mutex model the same number of times that it locked it. This helps to eliminate
a whole set of errors typically found in traditional C style thread APIs.</P>
<P>Classes <A href="recursive_mutex.html">recursive_rw_mutex</A>, <A href="recursive_mutex.html">
recursive_try_rw_mutex</A> and <A href="recursive_mutex.html">recursive_timed_rw_mutex</A>
will use this locking strategy.&nbsp; Successful implementation of this locking
strategy may require thread identification (see below).</P>
<h3><a name="locking-strategy-checked"></a>Checked</h3>
<P>With a checked locking strategy when a thread attempts to acquire a lock on
the mutex model for which the thread already owns a lock, the operation will
fail with some sort of error indication, except in the case of multiple&nbsp;shared-lock
acquisition which is&nbsp;a normal operation for ANY RWMutex. &nbsp;Further,
attempts by a thread to unlock a mutex that was not locked by the thread will
also return some sort of error indication. In <B>Boost.Threads</B>, an exception
of type <A href="lock_error.html">lock_error</A> would be thrown in these cases.</P>
<B>
<P>
<TABLE id="Table10" width="100%" border="1">
<TR>
<TD width="22%">Lock Type Held</TD>
<TD width="18%">Lock Request Type</TD>
<TD width="60%">Action</TD>
</TR>
<TR>
<TD width="22%">shared-lock</TD>
<TD width="18%">shared-lock</TD>
<TD width="60%">Grant the shared lock immediately</TD>
</TR>
<TR>
<TD width="22%">shared-lock</TD>
<TD width="18%">exclusive-lock</TD>
<TD width="60%">
<P>Throw lock_error()</P>
</TD>
</TR>
<TR>
<TD width="22%">exclusive-locked</TD>
<TD width="18%">shared-lock</TD>
<TD width="60%">Throw lock_error()</TD>
</TR>
<TR>
<TD width="22%">exclusive-locked</TD>
<TD width="18%">exclusive-lock</TD>
<TD width="60%"> Throw lock_error()</TD>
</TR>
</TABLE>
<p></P>
</B>
<P><B> Boost.Threads</b> does not currently provide any rw_mutex models that use
this strategy.&nbsp; A successful implementation of this locking strategy would
likely require thread identification.</P>
<h3><a name="locking-strategy-unchecked"></a>Unchecked</h3>
<P>With an unchecked locking strategy when a thread attempts to acquire a lock
on the rw_mutex model for which the thread already owns a lock the operation
will <A href="definitions.html#Deadlock"> deadlock</A>. In general this locking
strategy is less safe than a checked or recursive strategy, but it can be&nbsp;a
faster strategy and so is employed by many libraries.</P>
<P>
<TABLE id="Table11" width="100%" border="1">
<TR>
<TD width="22%">Lock Type Held</TD>
<TD width="18%">Lock Request Type</TD>
<TD width="60%">Action</TD>
</TR>
<TR>
<TD width="22%">shared-lock</TD>
<TD width="18%">shared-lock</TD>
<TD width="60%">Grant the shared lock immediately</TD>
</TR>
<TR>
<TD width="22%">shared-lock</TD>
<TD width="18%">exclusive-lock</TD>
<TD width="60%">
<P>Deadlock</P>
</TD>
</TR>
<TR>
<TD width="22%">exclusive-locked</TD>
<TD width="18%">shared-lock</TD>
<TD width="60%">Deadlock</TD>
</TR>
<TR>
<TD width="22%">exclusive-locked</TD>
<TD width="18%">exclusive-lock</TD>
<TD width="60%"> Deadlock</TD>
</TR>
</TABLE>
<p></P>
<P><B>Boost.Threads</B> does not currently provide any mutex models that use this
strategy.&nbsp; For RWMutexes on platforms that contain natively recursive synchronization
primitives, implementing a guaranteed-deadlock can actually involve extra work,
and would likely require thread identification.</P>
<h3><a name="locking-strategy-unspecified"></a>Unspecified</h3>
<P>With an unspecified locking strategy, when a thread attempts to acquire a lock
on a rw_mutex model for which the thread already owns a lock the operation results
in <B>undefined behavior</B>. When a rw_mutex model has an unspecified locking
strategy the programmer must assume that the rw_mutex model instead uses an
unchecked strategy as the worse case, although some platforms may exhibit a
mix of unchecked and recursive behavior.</P>
<P>
<TABLE id="Table12" width="100%" border="1">
<TR>
<TD width="22%">Lock Type Held</TD>
<TD width="18%">Lock Request Type</TD>
<TD width="60%">Action</TD>
</TR>
<TR>
<TD width="22%">shared-lock</TD>
<TD width="18%">shared-lock</TD>
<TD width="60%">Grant the shared lock immediately</TD>
</TR>
<TR>
<TD width="22%">shared-lock</TD>
<TD width="18%">exclusive-lock</TD>
<TD width="60%">
<P>Undefined, but generally deadlock</P>
</TD>
</TR>
<TR>
<TD width="22%">exclusive-locked</TD>
<TD width="18%">shared-lock</TD>
<TD width="60%">Undefined, but generally deadlock</TD>
</TR>
<TR>
<TD width="22%">exclusive-locked</TD>
<TD width="18%">exclusive-lock</TD>
<TD width="60%"> Undefined, but generally deadlock</TD>
</TR>
</TABLE>
<p></P>
<P>In general a rw_mutex model with an unspecified locking strategy is unsafe,
and it requires programmer discipline to use the rw_mutex model properly. However,
this strategy allows an implementation to be as fast as possible with no restrictions
on its implementation. This is especially true for portable implementations
that wrap the native threading support of a platform. For this reason, the classes
<A href="rw_mutex.html">rw_mutex</A>, <A href="rw_mutex.html">try_rw_mutex</A>
and <A href="rw_mutex.html">timed_rw_mutex</A> use this locking strategy despite
the lack of safety.</P>
<h3>An Aside - Thread Identification</h3>
<P>RWMutexes can support specific Locking Strategies (recursive and checked) which
help to detect and protect against self-deadlock.&nbsp; Self-deadlock can occur
when a holder of a locked RWMutex attempts to obtain another lock.&nbsp; Given
an implemention "I" which is susceptible to self-deadlock but otherwise correct
and efficient, a recursive or checked implementation "Ir" or "Ic" can use the
same basic implementation, but make special checks against self-deadlock by
tracking the identities of thread(s) currently holding locks.&nbsp; This approach
makes deadlock detection othrogonal to the basic RWMutex implementaion.&nbsp;
</P>
<P> Alternatively, a different basic implementation for RWMutex concepts&nbsp;,
I' (I-Prime) may exist which uses recursive or checked versions of synchronization
primitives to produce a recursive or checked RWMutex while still providing flexibility
in terms of Scheduling Policies.
<P>Please refer to the <b>Boost.Threads</b> <a href="mutex_concept.html#LockingStrategies">
mutex concept</a> documentation for a discussion of locking strategies.&nbsp;
The rw_mutex supports both the <a href="mutex_concept.html#Recursive"> recursive</a>
and <a href="mutex_concept.html#Unspecified">unspecified</a> locking strategies.&nbsp;
RWMutexes are parameterized on a Mutex type which they use to control exclusive-locking
and access to internal state.
<H3>Another Aside - <A name="LockingPromotion">Lock Promotion</A></H3>
<P>RWMutexes can support lock promotion, where a mutex which is in the shared-locked
state transitions to an exclusive-locked state without releasing the lock.&nbsp;
If this functionality is supported at all by Boost.Threads, it will only be
through an explicit promote() operations.&nbsp; Extra care must be taken to
ensure that only one thread holding a shared lock can block awaiting promotion
at any given time.&nbsp;&nbsp;If more than one shared-lock holder is allowed
to enter a blocked state while waiting to be promoted, deadlock will result
since both threads will be waiting for the other to release their shared lock.
<h2><a name="scheduling-policies"></a>Scheduling Policies</h2>
<p>Every rw_mutex model follows one of several scheduling policies. These policies
define the semantics when the mutex model is unlocked and there is more than
one thread waiting to acquire a lock. In other words, the policy defines which
waiting thread shall acquire the lock.&nbsp; For rw_mutex, it is particularly
important to define the behavior when threads are requesting both shared and
exclusive access simultaneously.&nbsp; This will be referred to as "inter-class
scheduling".&nbsp;&nbsp;</p>
<p>For some types of inter-class scheduling, an intra-class scheduling policy
can also be defined that will describe the order in which waiting threads of
the same class will acquire the thread.</p>
<h3><a name="ReaderPriority">ReaderPriority</a></h3>
<p>With ReaderPriority, any pending request for a shared lock will have priority
over a pending request for an exclusive lock, irrespective of the current lock
state of the rw_mutex, and irrespective of the relative order that the pending
requests arrive.</p>
<table border="1" width="100%" id="Table1">
<tr>
<td width="22%">Current rw_mutex state</td>
<td width="18%">Request Type</td>
<td width="60%">Action</td>
</tr>
<tr>
<td width="22%">unlocked</td>
<td width="18%">shared-lock</td>
<td width="60%">Grant the shared lock immediately</td>
</tr>
<tr>
<td width="22%">shared-locked</td>
<td width="18%">shared-lock</td>
<td width="60%">Grant the additional shared lock immediately.</td>
</tr>
<tr>
<td width="22%">exclusive-locked</td>
<td width="18%">shared-lock</td>
<td width="60%">Wait to acquire the lock until the thread holding the exclusive-lock
releases its lock.&nbsp; A shared lock will be granted to all pending readers
before&nbsp;any other thread can acquire an exclusive lock.</td>
</tr>
<tr>
<td width="22%">unlocked</td>
<td width="18%">exclusive-lock</td>
<td width="60%">Grant the exclusive lock immediately, if and only if there
are no pending shared-lock requests.</td>
</tr>
<tr>
<td width="22%">shared-locked</td>
<td width="18%">exclusive-lock</td>
<td width="60%"> Wait to acquire the lock until all threads holding shared
locks release their locks -AND- no requests for shared locks exist.&nbsp;
If other exclusive-lock requests exist, the lock is granted in accordance
with the intra-request scheduling policy.</td>
</tr>
<tr>
<td width="22%">exclusive-locked</td>
<td width="18%">exclusive-lock</td>
<td width="60%">Wait to acquire the lock until the thread holding the exclusive
lock releases its lock -AND- no requests for shared locks exist.&nbsp; If
other exclusive-lock requests exist, the lock is granted in accordance with
the intra-request scheduling policy.</td>
</tr>
</table>
<h3><a name="WriterPriority">WriterPriority</a></h3>
<p>With WriterPriority, any pending request for an exclusive lock will have priority
over a pending request for a shared lock, irrespective of the current lock state
of the rw_mutex, and irrespective of the relative order that the pending requests
arrive.</p>
<table border="1" width="100%" id="Table2">
<tr>
<td width="22%">Current rw_mutex state</td>
<td width="18%">Request Type</td>
<td width="60%">Action</td>
</tr>
<tr>
<td width="22%">unlocked</td>
<td width="18%">shared-lock</td>
<td width="60%">Grant the shared lock immediately.</td>
</tr>
<tr>
<td width="22%">shared-locked</td>
<td width="18%">shared-lock</td>
<td width="60%">Grant the additional shared lock immediately, -IF- no outstanding
requests for an exclusive lock exist.</td>
</tr>
<tr>
<td width="22%">exclusive-locked</td>
<td width="18%">shared-lock</td>
<td width="60%"> Wait to acquire the lock until the thread holding the exclusive-lock
releases its lock.&nbsp; The shared lock will be granted once&nbsp;no other
outstanding exclusive-lock requests exist.</td>
</tr>
<tr>
<td width="22%">unlocked</td>
<td width="18%">exclusive-lock</td>
<td width="60%">Grant the exclusive lock immediately.</td>
</tr>
<tr>
<td width="22%">shared-locked</td>
<td width="18%">exclusive-lock</td>
<td width="60%">Wait to acquire the lock until all threads holding shared
locks release their locks.&nbsp; If other exclusive-lock requests exist,
the lock is granted in accordance with the intra-request scheduling policy.&nbsp;
This request will be granted before any new shared-lock requests are granted.</td>
</tr>
<tr>
<td width="22%">exclusive-locked</td>
<td width="18%">exclusive-lock</td>
<td width="60%">Wait to acquire the lock until the thread holding the exclusive
lock releases its lock.&nbsp; If other exclusive-lock requests exist, the
lock is granted in accordance with the intra-request scheduling policy.&nbsp;
This request will be granted before any new shared-lock requests are granted.</td>
</tr>
</table>
<h3><a name="AlteratingManyPriority">AlternatingPriority</a>/ManyReads</h3>
<p>With AlternatingPriority/ManyReads, reader or writer starvation is avoided
by alternatively granting shared or exclusive access when pending requests exist
for both types of locks.&nbsp; Outstanding shared-lock requests are treated
as a group when it is the "reader's turn"</p>
<table border="1" width="100%" id="Table3">
<tr>
<td width="22%">Current rw_mutex state</td>
<td width="18%">Request Type</td>
<td width="60%">Action</td>
</tr>
<tr>
<td width="22%">unlocked</td>
<td width="18%">shared-lock</td>
<td width="60%">Grant the shared lock immediately.</td>
</tr>
<tr>
<td width="22%">shared-locked</td>
<td width="18%">shared-lock</td>
<td width="60%">Grant the additional shared lock immediately, -IF- no outstanding
requests for an exclusive lock exist.&nbsp; If outstanding exclusive-lock
requests exist, this lock will not be granted until at least one of the
exclusive locks is granted and released. If other shared-lock requests exist,
all shared-locks will be granted as a group.</td>
</tr>
<tr>
<td width="22%">exclusive-locked</td>
<td width="18%">shared-lock</td>
<td width="60%"> Wait to acquire the lock until the thread holding the exclusive-lock
releases its lock.&nbsp; If other outstanding exclusive-lock requests exist,
they will have to wait until all current shared-lock requests are serviced.</td>
</tr>
<tr>
<td width="22%">unlocked</td>
<td width="18%">exclusive-lock</td>
<td width="60%">Grant the exclusive lock immediately.</td>
</tr>
<tr>
<td width="22%">shared-locked</td>
<td width="18%">exclusive-lock</td>
<td width="60%">
<P>Wait to acquire the lock until all threads holding shared locks release
their locks.&nbsp; </P>
<P>If other&nbsp;exclusive-lock requests exist, this lock will be granted
to one of them in accordance with the intra-request scheduling policy.</P>
</td>
</tr>
<tr>
<td width="22%">exclusive-locked</td>
<td width="18%">exclusive-lock</td>
<td width="60%">Wait to acquire the lock until the thread holding the exclusive
lock releases its lock.&nbsp;&nbsp; If other outstanding shared-lock requests
exist, this lock will not be granted until all of the currently waiting
shared locks&nbsp;are granted and released.&nbsp; If other exclusive-lock
requests exist, this lock will be granted in accordance with the intra-request
scheduling policy.</td>
</tr>
</table>
<H3>
<H3><A name="AlteratingSinglePriority">AlternatingPriority</A>/SingleReads</H3>
</H3>
<P>With AlternatingPriority/ManyReads, reader or writer starvation is avoided
by alternatively granting shared or exclusive access when pending requests exist
for both types of locks.&nbsp; Outstanding shared-lock requests are services
one at a time&nbsp;when it is the "reader's turn"</P>
<H3>
<TABLE id="Table13" width="100%" border="1">
<TR>
<TD width="22%">Current rw_mutex state</TD>
<TD width="18%">Request Type</TD>
<TD width="60%">Action</TD>
</TR>
<TR>
<TD width="22%">unlocked</TD>
<TD width="18%">shared-lock</TD>
<TD width="60%">Grant the shared lock immediately.</TD>
</TR>
<TR>
<TD width="22%">shared-locked</TD>
<TD width="18%">shared-lock</TD>
<TD width="60%">Grant the additional shared lock immediately, -IF- no outstanding
requests for an exclusive lock exist.&nbsp; If outstanding exclusive-lock
requests exist, this lock will not be granted until at least one of the
exclusive locks is granted and released. </TD>
</TR>
<TR>
<TD width="22%">exclusive-locked</TD>
<TD width="18%">shared-lock</TD>
<TD width="60%">
<P>Wait to acquire the lock until the thread holding the exclusive-lock
releases its lock.</P>
<P>If other outstanding exclusive-lock requests exist, exactly one shared-lock
request will be granted before the next exclusive lock is granted.</P>
</TD>
</TR>
<TR>
<TD width="22%">unlocked</TD>
<TD width="18%">exclusive-lock</TD>
<TD width="60%">Grant the exclusive lock immediately.</TD>
</TR>
<TR>
<TD width="22%">shared-locked</TD>
<TD width="18%">exclusive-lock</TD>
<TD width="60%">
<P>Wait to acquire the lock until all threads holding shared locks release
their locks.&nbsp; </P>
<P>If other&nbsp;exclusive-lock requests exist, this lock will be granted
to one of them in accordance with the intra-request scheduling policy.</P>
</TD>
</TR>
<TR>
<TD width="22%">exclusive-locked</TD>
<TD width="18%">exclusive-lock</TD>
<TD width="60%">Wait to acquire the lock until the thread holding the exclusive
lock releases its lock.&nbsp;&nbsp; If other outstanding shared-lock requests
exist, this lock can not be granted until exactly one shared-lock request
is granted and released.&nbsp; If other exclusive-lock requests exist,
this lock will be granted in accordance with the intra-request scheduling
policy.</TD>
</TR>
</TABLE>
</H3>
<h3>Intra-Request Scheduling Policy</h3>
<p>Please refer to the <b>Boost.Threads</b> <a href="mutex_concept.html#SchedulingPolicies">
mutex concept</a> documentation for a discussion of mutex scheduling policies,
which are identical to RWMutex Intra-Request scheduling policies.&nbsp; The
rw_mutex supports only the <a href="mutex_concept.html#UnspecifiedScheduling">
Unspecified</a> intra-request scheduling policy.&nbsp; That is, given a set
of threads waiting for exclusive locks, the order (amongst themselves) in which
they receive the lock is unspecified.</p>
<h2><a name="requirements"></a>Concept Requirements</h2>
<h3>RW<a name="Mutex">Mutex</a> Concept</h3>
<p>A RWMutex object has three states: shared-locked, exclusive-locked, and unlocked.
RWMutex object state can only be determined by an object meeting the <a href="rw_lock_concept.html#ScopedLock">
ScopedRWLock</a> requirements and constructed for the RWMutex object.</p>
<p>A RWMutex is <a href="../../utility/utility.htm#Class noncopyable">noncopyable</a>.</p>
<p> For a RWMutex type RWM,&nbsp;and an object m of that type, the following expressions
must be well-formed and have the indicated effects.</p>
<table summary="Mutex expressions" border="1" cellpadding="5" id="Table5">
<tr>
<td><b>Expression</b></td>
<td><b>Effects</b></td>
</tr>
<tr>
<td><code>RWM m;</code></td>
<td>Constructs a rw_mutex object m. Post-condition: m is unlocked.</td>
</tr>
<tr>
<td><code>(&amp;m)-&gt;~RWM();</code></td>
<td>Precondition: m is unlocked. Destroys a rw_mutex object m.</td>
</tr>
<tr>
<td><code>RWM::scoped_rw_lock</code></td>
<td>A type meeting the <a href="rw_lock_concept.html#ScopedRWLock">ScopedRWLock</a>
requirements.&nbsp;&nbsp;</td>
</tr>
</table>
<h3><a name="TryMutex">TryRWMutex</a> Concept</h3>
<p>A TryRWMutex must meet the <a href="#RWMutex">RWMutex</a> requirements. In
addition, for a TryRWMutex type RWM and an object m of that type, the following
expressions must be well-formed and have the indicated effects.</p>
<table summary="TryMutex expressions" border="1" cellpadding="5" id="Table6">
<tr>
<td><b>Expression</b></td>
<td><b>Effects</b></td>
</tr>
<tr>
<td><code>RWM::scoped_try_rw_lock</code></td>
<td>A type meeting the <a href="rw_lock_concept.html#ScopedTryRWLock">ScopedTryRWLock</a>
requirements.</td>
</tr>
</table>
<h3><a name="TimedMutex">TimedRWMutex</a> Concept</h3>
<p>A TimedRWMutex must meet the <a href="#TryMutex">TryRWMutex</a> requirements.
In addition, for a TimedRWMutex type RWM and an object m of that type, the following
expressions must be well-formed and have the indicated effects.</p>
<table summary="TimedMutex expressions" border="1" cellpadding="5" id="Table7">
<tr>
<td><b>Expression</b></td>
<td><b>Effects</b></td>
</tr>
<tr>
<td><code>RWM::scoped_timed_rw_lock</code></td>
<td>A type meeting the <a href="rw_lock_concept.html#ScopedTimedRWLock">ScopedTimedRWLock</a>
requirements.</td>
</tr>
</table>
<h2><a name="models"></a>Models</h2>
<p><b>Boost.Threads</b> currently supplies three classes which model rw_mutex
concepts.</p>
<table summary="Mutex concept classes" border="1" cellpadding="5" id="Table8">
<tr>
<td><b>Concept</b></td>
<td><b>Refines</b></td>
<td><b>Classes Modeling the Concept</b></td>
</tr>
<tr>
<td valign="top"><a href="#Mutex">RWMutex</a></td>
<td valign="top">&nbsp;</td>
<td><a href="rw_mutex.html">rw_mutex&lt;Mutex&gt;</a></td>
</tr>
<tr>
<td valign="top"><a href="#TryMutex">TryRWMutex</a></td>
<td valign="top"><a href="#Mutex">RWMutex</a></td>
<td><a href="rw_mutex.html">try_rw_mutex&lt;TryMutex&gt; </a> </td>
</tr>
<tr>
<td valign="top"><a href="#TimedMutex">TimedRWMutex</a></td>
<td valign="top"><a href="#TryMutex">TryRWMutex</a></td>
<td><a href="rw_mutex.html">timed_rw_mutex&lt;TimedMutex&gt; </a> </td>
</tr>
</table>
<hr>
<p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
05 November, 2001
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p>
<p><i>&copy; Copyright <a href="mailto:{{address}}">{{author}}</a> 2002. All Rights
Reserved.</i></p>
</body>
</html>

View File

@@ -7,11 +7,11 @@
<body link="#0000ff" vlink="#800080">
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
"header">
<tr>
<td valign="top" width="300">
<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">
<td valign="top">
<h1 align="center">Boost.Threads</h1>
<h2 align="center">Header &lt;<a href="../../../boost/thread/thread.hpp">boost/thread.hpp</a>&gt;</h2>
</td>
@@ -19,33 +19,33 @@
</table>
<hr>
<h2>Contents</h2>
<dl class="page-index">
<dl class="page-index">
<dt><a href="#introduction">Introduction</a></dt>
<dt><a href="#classes">Classes</a></dt>
<dl class="page-index">
<dl class="page-index">
<dt><a href="#class-thread">Class <code>thread</code></a></dt>
<dl class="page-index">
<dl class="page-index">
<dt><a href="#class-thread-synopsis">Class <code>thread</code> synopsis</a></dt>
<dt><a href="#class-thread-ctors">Class <code>thread</code> constructors
<dt><a href="#class-thread-ctors">Class <code>thread</code> constructors
and destructor</a></dt>
<dt><a href="#class-thread-comparisons">Class <code>thread</code> comparison
<dt><a href="#class-thread-comparisons">Class <code>thread</code> comparison
functions</a></dt>
<dt><a href="#class-thread-modifiers">Class <code>thread</code> modifier
<dt><a href="#class-thread-modifiers">Class <code>thread</code> modifier
functions</a></dt>
<dt><a href="#class-thread-statics">Class <code>thread</code> static functions</a></dt>
</dl>
<dt><a href="#class-thread_group">Class <code>thread_group</code></a></dt>
<dl class="page-index">
<dt><a href="#class-thread_group-synopsis">Class <code>thread_group</code>
<dl class="page-index">
<dt><a href="#class-thread_group-synopsis">Class <code>thread_group</code>
synopsis</a></dt>
<dt><a href="#class-thread_group-ctors">Class <code>thread_group</code>
<dt><a href="#class-thread_group-ctors">Class <code>thread_group</code>
constructors and destructor</a></dt>
<dt><a href="#class-thread_group-modifiers">Class <code>thread_group</code>
<dt><a href="#class-thread_group-modifiers">Class <code>thread_group</code>
modifier functions</a></dt>
</dl>
</dl>
<dt><a href="#examples">Example(s)</a></dt>
<dl class="page-index">
<dl class="page-index">
<dt><a href="#example-thread">Simple usage of <code>boost::thread</code></a></dt>
<dt><a href="#example-thread_group">Simple usage of <code>boost::thread_group</code></a></dt>
</dl>
@@ -57,32 +57,32 @@
which are used to create, observe and manage threads and groups of threads.</p>
<h2><a name="classes"></a>Classes</h2>
<h3><a name="class-thread"></a>Class <code>thread</code></h3>
<p>The <code>thread</code> class represents threads of execution, and provides
the functionality to create and manage threads within the <b> Boost.Threads</b>
library. See <a href="definitions.html"> Definitions</a> for a precise description
of &quot;thread of execution&quot;, and for definitions of threading related
<p>The <code>thread</code> class represents threads of execution, and provides
the functionality to create and manage threads within the <b> Boost.Threads</b>
library. See <a href="definitions.html"> Definitions</a> for a precise description
of &quot;thread of execution&quot;, and for definitions of threading related
terms and of thread states such as &quot;blocked&quot;.</p>
<p>A thread of execution has an initial function. For the program&#39;s initial
thread, the initial function is <code>main()</code>. For other threads, the
initial function is <code>operator()</code> of the function object passed to
<p>A thread of execution has an initial function. For the program&#39;s initial
thread, the initial function is <code>main()</code>. For other threads, the
initial function is <code>operator()</code> of the function object passed to
the class <code>thread</code> constructor.</p>
<p>A thread of execution is said to be &quot;finished&quot; or &quot;finished
execution&quot; when its initial function returns or is terminated. This includes
completion of all thread cleanup handlers, and completion of the normal C++
function return behaviors, such as destruction of automatic storage (stack)
<p>A thread of execution is said to be &quot;finished&quot; or &quot;finished
execution&quot; when its initial function returns or is terminated. This includes
completion of all thread cleanup handlers, and completion of the normal C++
function return behaviors, such as destruction of automatic storage (stack)
objects and releasing any associated implementation resources.</p>
<p>A thread object has an associated state which is either &quot;joinable&quot;
<p>A thread object has an associated state which is either &quot;joinable&quot;
or &quot;non-joinable&quot;.</p>
<p>Except as described below, the policy used by an implementation of <b>Boost.Threads</b>
<p>Except as described below, the policy used by an implementation of <b>Boost.Threads</b>
to schedule transitions between thread states is unspecified.</p>
<p><b>Note:</b> Just as the lifetime of a file may be different from the lifetime
of an iostream object which represents the file, the lifetime of a thread of
execution may be different from the <code> thread</code> object which represents
the thread of execution. In particular, after a call to <code>join()</code>,
the thread of execution will no longer exist even though the <code>thread</code>
object continues to exist until the end of its normal lifetime. The converse
is also possible; if a <code>thread</code> object is destroyed without <code>join()</code>
having first been called, the thread of execution continues until its initial
<p><b>Note:</b> Just as the lifetime of a file may be different from the lifetime
of an iostream object which represents the file, the lifetime of a thread of
execution may be different from the <code> thread</code> object which represents
the thread of execution. In particular, after a call to <code>join()</code>,
the thread of execution will no longer exist even though the <code>thread</code>
object continues to exist until the end of its normal lifetime. The converse
is also possible; if a <code>thread</code> object is destroyed without <code>join()</code>
having first been called, the thread of execution continues until its initial
function completes.</p>
<h4><a name="class-thread-synopsis"></a>Class <code>thread</code> synopsis</h4>
<pre>
@@ -107,13 +107,13 @@ public:
};
} // namespace boost
</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>
<pre>
thread();
</pre>
<dl class="function-semantics">
<dt><b>Effects:</b> Constructs a <code>thread</code> object representing the
<dl class="function-semantics">
<dt><b>Effects:</b> Constructs a <code>thread</code> object representing the
current thread of execution.</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>
@@ -121,43 +121,43 @@ thread();
<pre>
thread(const <a href="../../function/index.html">boost::function0</a>&lt;void&gt;&amp; threadfunc);
</pre>
<dl class="function-semantics">
<dt><b>Effects:</b> Starts a new thread of execution and constructs a <code>thread</code>
object representing it. Copies <code> threadfunc</code> (which in turn copies
the function object wrapped by <code>threadfunc</code>) to an internal location
which persists for the lifetime of the new thread of execution. Calls <code>operator()</code>
on the copy of the <code>threadfunc</code> function object in the new thread
<dl class="function-semantics">
<dt><b>Effects:</b> Starts a new thread of execution and constructs a <code>thread</code>
object representing it. Copies <code> threadfunc</code> (which in turn copies
the function object wrapped by <code>threadfunc</code>) to an internal location
which persists for the lifetime of the new thread of execution. Calls <code>operator()</code>
on the copy of the <code>threadfunc</code> function object in the new thread
of execution.</dt>
<dt><b>Postconditions:</b> <code>*this</code> is joinable.</dt>
<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>
</dl>
<pre>
~Thread();
</pre>
<dl class="function-semantics">
<dt><b>Effects:</b> Destroys <code>*this</code>. The actual thread of execution
<dl class="function-semantics">
<dt><b>Effects:</b> Destroys <code>*this</code>. The actual thread of execution
may continue to execute after the <code>thread</code> object has been destroyed.</dt>
<dt><b>Note:</b> If <code>*this</code> is joinable the actual thread of execution
becomes &quot;detached&quot;. Any resources used by the thread will be reclaimed
when the thread of execution completes. To ensure such a thread of execution
runs to completion before the <code> thread</code> object is destroyed, call
<dt><b>Note:</b> If <code>*this</code> is joinable the actual thread of execution
becomes &quot;detached&quot;. Any resources used by the thread will be reclaimed
when the thread of execution completes. To ensure such a thread of execution
runs to completion before the <code> thread</code> object is destroyed, call
<code>join()</code>.</dt>
</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>
<pre>
bool operator==(const thread&amp; rhs) const;
</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>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>
</dl>
<pre>
bool operator!=(const thread&amp; rhs) const;
</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>Returns:</b> <code>!(*this==rhs)</code>.</dt>
</dl>
@@ -165,40 +165,40 @@ bool operator!=(const thread&amp; rhs) const;
<pre>
void join();
</pre>
<dl class="function-semantics">
<dl class="function-semantics">
<dt><b>Requires:</b> <code>*this</code> is joinable.</dt>
<dt><b>Effects:</b> The current thread of execution blocks until the initial
function of the thread of execution represented by <code> *this</code> finishes
<dt><b>Effects:</b> The current thread of execution blocks until the initial
function of the thread of execution represented by <code> *this</code> finishes
and all resources are reclaimed.</dt>
<dt><b>Postconditions:</b> <code>*this</code> is non-joinable.</dt>
<dt><b>Notes:</b> If <code>*this == thread()</code> the result is implementation
defined. If the implementation doesn&#39;t detect this the result will be
<dt><b>Notes:</b> If <code>*this == thread()</code> the result is implementation
defined. If the implementation doesn&#39;t detect this the result will be
<a href="definitions.html#Deadlock"> deadlock</a>.</dt>
</dl>
<h4><a name="class-thread-statics"></a>Class <code>thread</code> static functions</h4>
<pre>
static void sleep(const <a href="xtime.html">xtime</a>&amp; XT);
</pre>
<dl class="function-semantics">
<dt><b>Effects:</b> The current thread of execution blocks until <code> XT</code>
<dl class="function-semantics">
<dt><b>Effects:</b> The current thread of execution blocks until <code> XT</code>
is reached.</dt>
</dl>
<pre>
static void yield();
</pre>
<dl class="function-semantics">
<dt><b>Effects:</b> The current thread of execution is placed in the &quot;ready&quot;
<dl class="function-semantics">
<dt><b>Effects:</b> The current thread of execution is placed in the &quot;ready&quot;
state.</dt>
<dt><b>Notes:</b> Allow the current thread to give up the rest of its time slice
(or other scheduling quota) to another thread. Particularly useful in non-preemptive
<dt><b>Notes:</b> Allow the current thread to give up the rest of its time slice
(or other scheduling quota) to another thread. Particularly useful in non-preemptive
implementations.</dt>
</dl>
<h3><a name="class-thread_group"></a>Class <code>thread_group</code></h3>
<p>The <tt>thread_group</tt> class provides a container for easy grouping of threads
<p>The <tt>thread_group</tt> class provides a container for easy grouping of threads
to simplify several common thread creation and management idioms.</p>
<p>All <tt>thread_group</tt> member functions are <a href=
"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>
<pre>
namespace boost {
@@ -216,62 +216,62 @@ namespace boost {
};
} // namespace boost
</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>
<pre>
thread_group();
</pre>
<dl class="function-semantics">
<dl class="function-semantics">
<dt><b>Effects:</b> Constructs an empty <code>thread_group</code> container.</dt>
</dl>
<pre>
~thread_group();
</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>Notes:</b> Behavior is undefined if another thread references *this during
<dt><b>Notes:</b> Behavior is undefined if another thread references *this during
the execution of the destructor.</dt>
</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>
<pre>
thread* create_thread(const boost::function0&lt;void&gt;&amp; threadfunc);
</pre>
<dl class="function-semantics">
<dt><b>Effects:</b> Creates a new <tt>thread</tt> object that executes <tt>threadfunc</tt>
and adds it to the <tt>thread_group</tt> container object&#39;s list of managed
<dl class="function-semantics">
<dt><b>Effects:</b> Creates a new <tt>thread</tt> object that executes <tt>threadfunc</tt>
and adds it to the <tt>thread_group</tt> container object&#39;s list of managed
<tt>thread</tt> objects.</dt>
<dt><b>Returns:</b> Pointer to the newly created thread.</dt>
</dl>
<pre>
void add_thread(thread* thrd);
</pre>
<dl class="function-semantics">
<dt><b>Effects:</b> Adds <tt>thrd</tt> to the <tt>thread_group</tt> object&#39;s
list of managed <tt>thread</tt> objects. The <tt>thrd</tt> object must have
<dl class="function-semantics">
<dt><b>Effects:</b> Adds <tt>thrd</tt> to the <tt>thread_group</tt> object&#39;s
list of managed <tt>thread</tt> objects. The <tt>thrd</tt> object must have
been allocated via operator new and will be deleted when the group is destroyed.</dt>
</dl>
<pre>
Void remove_thread(thread* thrd);
</pre>
<dl class="function-semantics">
<dt><b>Effects:</b> Removes <code>*this</code>&#39;s list of managed <tt>thread</tt>
<dl class="function-semantics">
<dt><b>Effects:</b> Removes <code>*this</code>&#39;s list of managed <tt>thread</tt>
objects.</dt>
<dt><b>Throws:</b> ? if <tt>thrd</tt> is not it <code>*this</code>&#39;s list
<dt><b>Throws:</b> ? if <tt>thrd</tt> is not it <code>*this</code>&#39;s list
of managed <tt>thread</tt> objects.</dt>
</dl>
<pre>
Void join_all();
</pre>
<dl class="function-semantics">
<dt><b>Effects:</b> Calls <code>join()</code> on each of the managed <tt>thread</tt>
<dl class="function-semantics">
<dt><b>Effects:</b> Calls <code>join()</code> on each of the managed <tt>thread</tt>
objects.</dt>
</dl>
<h2><a name="functions"></a>Functions</h2>
<pre>
<a name="function-spec"></a>{{function}}
</pre>
<dl class="function-semantics">
<dl class="function-semantics">
<dt><b>Requires:</b> {{text}}</dt>
<dt><b>Effects:</b> {{text}}</dt>
<dt><b>Postconditions:</b> {{text}}</dt>
@@ -284,63 +284,14 @@ Void join_all();
<p><a name="object-spec"></a>{{Object specifications}}</p>
<h2><a name="examples"></a>Example(s)</h2>
<h3><a name="example-thread"></a>Simple usage of <code>boost::thread</code></h3>
<pre>
#include &lt;boost/thread/thread.hpp&gt;
#include &lt;iostream&gt;
struct thread_alarm
{
thread_alarm(int secs) : m_secs(secs) { }
void operator()()
{
boost::xtime XT;
boost::xtime_get(&amp;XT, boost::TIME_UTC);
xt.sec += m_secs;
boost::thread::sleep(XT);
std::cout &lt;&lt; &quot;alarm sounded...&quot; &lt;&lt; std::endl;
}
int m_secs;
};
int main(int argc, char* argv[])
{
int secs = 5;
std::cout &lt;&lt; &quot;setting alarm for 5 seconds...&quot; &lt;&lt; std::endl;
thread_alarm alarm(secs);
boost::thread thrd(alarm);
thrd.join();
}
</pre>
<p><a href="../example/thread.cpp">libs/thread/example/thread.cpp</a></p>
<p>The output is:</p>
<pre>
setting alarm for 5 seconds...
alarm sounded...
</pre>
<h3><a name="example-thread_group"></a>Simple usage of <code>boost::thread_group</code></h3>
<pre>
#include &lt;boost/thread/thread.hpp&gt;
#include &lt;iostream&gt;
int count = 0;
boost::mutex mutex;
void increment_count()
{
boost::mutex::lock lock(mutex);
std::cout &lt;&lt; &quot;count = &quot; &lt;&lt; ++count &lt;&lt; std::endl;
}
int main(int argc, char* argv[])
{
boost::thread_group threads;
for (int i = 0; i &lt; 10; ++i)
threads.create_thread(&amp;increment_count);
threads.join_all();
}
</pre>
<p><a href="../example/thread_group.cpp">libs/thread/example/thread_group.cpp</a></p>
<p>The output is:</p>
<pre>
count = 1
@@ -355,18 +306,18 @@ count = 9
count = 10
</pre>
<hr>
<p>Revised
<p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
05 November, 2001
05 November, 2001
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p>
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
All Rights Reserved.</i></p>
<p>Permission to use, copy, modify, distribute and sell this software and its
documentation for any purpose is hereby granted without fee, provided that the
above copyright notice appear in all copies and that both that copyright notice
and this permission notice appear in supporting documentation. William E. Kempf
makes no representations about the suitability of this software for any purpose.
<p>Permission to use, copy, modify, distribute and sell this software and its
documentation for any purpose is hereby granted without fee, provided that the
above copyright notice appear in all copies and that both that copyright notice
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 &quot;as is&quot; without express or implied warranty.</p>
</body>
</html>

207
doc/thread_pool.html Normal file
View File

@@ -0,0 +1,207 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<link rel="stylesheet" type="text/css" href="../../../boost.css">
<title>Boost.Threads - Header &lt;boost/thread/thread_pool.hpp&gt;</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">Header &lt;<a href="../../../boost/thread/thread_pool.hpp">boost/thread/thread_pool.hpp</a>&gt;</h2>
</td>
</tr>
</table>
<hr>
<h2>Contents</h2>
<dl class="page-index">
<dt><a href="#introduction">Introduction</a></dt>
<dt><a href="#classes">Classes</a></dt>
<dl class="page-index">
<dt><a href="#class-thread_pool">Class <code>thread_pool</code></a></dt>
<dl class="page-index">
<dt><a href="#class-thread_pool-synopsis">Class <code>thread_pool</code> synopsis</a></dt>
<dt><a href="#class-thread_pool-ctors">Class <code>thread_pool</code> constructors and destructor</a></dt>
<dt><a href="#class-thread_pool-modifiers">Class <code>thread_pool</code> modifier functions</a></dt>
</dl>
</dl>
<dt><a href="#examples">Example(s)</a></dt>
</dl>
<hr>
<h2><a name="introduction"></a>Introduction</h2>
<p>Include the header &lt;<a href="../../../boost/thread/thread_pool.hpp">boost/thread/thread_pool.hpp</a>&gt;
to define the <a href="#class-thread_pool">thread_pool</a> class.</p>
<h2><a name="classes"></a>Classes</h2>
<h3><a name="class-thread_pool"></a>Class <code>thread_pool</code></h3>
<p>The <tt>thread_pool</tt> class provides&nbsp;an interface for&nbsp;running
jobs on a dynamically managed set&nbsp;of worker threads called a pool.&nbsp;
When a job is added, it can execute on any&nbsp;available thread in the pool.&nbsp;
This class controls&nbsp;both the maximum and minimum number of threads&nbsp;in
the pool.&nbsp; If a thread in the pool is sitting idle&nbsp;for a period&nbsp;of
time, it&nbsp;will exit unless by exiting the number of threads would dip below
the minimum. Thread pools provide an optimization over creating a new thread
for each job since the pool can often remove the overhead of thread creation.</p>
<h4><a name="class-thread_pool-synopsis"></a>Class <code>thread_pool</code> synopsis</h4>
<pre>
namespace boost
{
class thread_pool : <a href="../../utility/utility.htm#Class noncopyable">boost::noncopyable</a> // Exposition only.
// Class thread meets the <a href="overview.html#non-copyable">NonCopyable</a> requirement.
{
public:
thread_pool(int max_threads=std::numeric_limits&lt;int&gt;::max(),
int min_threads=0,
int timeout_secs=5);
~thread_pool();
void add(const boost::function0&lt;void&gt; &amp;job);
void join();
void cancel();
void detach();
};
};
</pre>
<h4><a name="class-spec-ctors"></a>Class <code>thread_pool</code> constructors and destructor</h4>
<pre>
thread_pool(int max_threads=std::numeric_limits&lt;int&gt;::max(),
int min_threads=0,
int timeout_secs=5);
</pre>
<dl class="function-semantics">
<dt><b>Effects:</b> Constructs a thread pool object and starts min_threads threads
running in the pool.</dt>
</dl>
<pre>
~thread_pool();
</pre>
<dl class="function-semantics">
<dt><b>Effects:</b> Calls join() if neither join() nor detach() were called
previously for this thread_pool.&nbsp; If detach() was not called, destroys all
resources associated with the threads in the pool and with the queue of jobs
still waiting to be executed.</dt>
</dl>
<h4><a name="class-spec-modifiers"></a>Class <code>thread_pool</code> modifier
functions</h4>
<pre>
void add(const boost::function0&lt;void&gt;&amp; job);
</pre>
<dl class="function-semantics">
<dt><b>Effects:</b> Adds <tt>job</tt> to the <tt>thread_pool</tt> object's list of
jobs waiting to be executed.&nbsp; If any threads in the pool are idle, the job
will be execute as soon as the idle thread is scheduled by the operating
system.&nbsp; If no threads are idle and the number of threads in the pool is
less than the maximum number provided to the constructor, an additional thread
is created and added to the pool.&nbsp; That new thread will execute this job
as soon as it is scheduled by the operating system.&nbsp; If no threads are
idle and&nbsp;the thread count is at the maximum, this job will be queued until
a thread becomes available.&nbsp; Currently, queued jobs are processed in FIFO
order.</dt>
<dt><b>Throws:</b> std::runtime_error if join() or detach() have
previously been called for this thread_pool object.</dt>
</dl>
<pre>
void detach();
</pre>
<dl class="function-semantics">
<dt><b>Effects:</b> Relinquishes control of the pool of threads by this thread_pool
object.&nbsp; Any threads in the pool will continue to run and continue to
process any queued jobs, but no new threads will be created, and any subsequent
attempts to add new jobs will result in an exception.</dt>
<dt><b>Throws:</b> std::runtime_error if join()&nbsp;has previously
been called for this thread_pool object.</dt>
</dl>
<pre>
void cancel();
</pre>
<dl class="function-semantics">
<dt><b>Effects:</b> Removes all queued jobs from the thread_pool's internal queue,
and calls cancel() on all boost::thread objects in the pool.&nbsp; The specific
behavior of those threads will be dictated by their cancellation behavior - the
pool threads may be executing a user's job that deferrs cancellation, for
example.</dt>
<dt><b>Throws:</b> std::runtime_error if join() or detach() have
previously been called for this thread_pool object.</dt>
<dt><b>Note:</b> for the current version (1.27.0) of Boost.Threads, thread::cancel() is
not provided.&nbsp; This function -will- clear out all queued jobs, but any
currently executing jobs will not be cancelled.</dt>
</dl>
<pre>
void join();
</pre>
<dl class="function-semantics">
<dt><b>Effects:</b> Waits until all queued jobs are completed by the thread pool,
and then join()s will all of the threads in the pool.&nbsp; When join()
returns, no running threads will remain in the pool, and this object is invalid
for anything except destruction.&nbsp; Any calls to cancel(), join(), detach(),
or add() will result in an exception.</dt>
</dl>
<h2><a name="examples"></a>Example(s)</h2>
<pre>
#include &lt;boost/thread/thread_pool.hpp&gt;
#include &lt;boost/thread/mutex.hpp&gt;
#include &lt;iostream&gt;
boost::mutex io_mutex;
class job_adapter {
public:
job_adapter(void (*func)(int), int param) :
_func(func), _param(param){ }
void operator()() const { _func(_param); }
private:
void (*_func)(int);
int _param;
};
void simple_job(int param)
{
boost::mutex::scoped_lock l(io_mutex);
std::cout &lt;&lt; param &lt;&lt; " squared is " &lt;&lt; (param*param) &lt;&lt; "\n";
}
int main(int argc, char* argv[])
{
boost::thread_pool tp;
for (int i = 1; i &lt;= 10; ++i)
tp.add(simple_job);
tp.join();
return 0;
}
</pre>
<p>Typical output would be:</p>
<pre>
1 squared is 1
2 squared is 4
3 squared is 9
4 squared is 16
5 squared is 25
7 squared is 49
6 squared is 36
8 squared is 64
10 squared is 100
9 squared is 81
</pre>
<P>While the jobs are dispatched in the order they are received, the scheduling of
the individual threads in the pool is platform-dependent.</P>
<P>
<p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
05 November, 2001
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p>
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a>, David Moore 2001-2002.
All Rights Reserved.</i></p>
<p>Permission to use, copy, modify, distribute and sell this software and its
documentation for any purpose is hereby granted without fee, provided that the
above copyright notice appear in all copies and that both that copyright notice
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 &quot;as is&quot; without express or implied warranty.</p>
</body>
</html>

View File

@@ -7,11 +7,11 @@
<body link="#0000ff" vlink="#800080">
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
"header">
<tr>
<td valign="top" width="300">
<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">
<td valign="top">
<h1 align="center">Boost.Threads</h1>
<h2 align="center">Header &lt;<a href="../../../boost/thread/tss.hpp">boost/thread/tss.hpp</a>&gt;</h2>
</td>
@@ -19,19 +19,19 @@
</table>
<hr>
<h2>Contents</h2>
<dl class="page-index">
<dl class="page-index">
<dt><a href="#introduction">Introduction</a></dt>
<dt><a href="#classes">Classes</a></dt>
<dl class="page-index">
<dl class="page-index">
<dt><a href="#class-thread_specific_ptr">Class <code>thread_specific_ptr</code></a></dt>
<dl class="page-index">
<dt><a href="#class-thread_specific_ptr-synopsis">Class <code>thread_specific_ptr</code>
<dl class="page-index">
<dt><a href="#class-thread_specific_ptr-synopsis">Class <code>thread_specific_ptr</code>
synopsis</a></dt>
<dt><a href="#class-thread_specific_ptr-ctors">Class <code>thread_specific_ptr</code>
<dt><a href="#class-thread_specific_ptr-ctors">Class <code>thread_specific_ptr</code>
constructors and destructor</a></dt>
<dt><a href="#class-thread_specific_ptr-modifiers">Class <code>thread_specific_ptr</code>
<dt><a href="#class-thread_specific_ptr-modifiers">Class <code>thread_specific_ptr</code>
modifier functions</a></dt>
<dt><a href="#class-thread_specific_ptr-observers">Class <code>thread_specific_ptr</code>
<dt><a href="#class-thread_specific_ptr-observers">Class <code>thread_specific_ptr</code>
observer functions</a></dt>
</dl>
</dl>
@@ -44,23 +44,26 @@
which is used to manage data associated with specific thread instances.</p>
<h2><a name="classes"></a>Classes</h2>
<h3><a name="class-thread_specific_ptr"></a>Class <code>thread_specific_ptr</code></h3>
<p>The <code>thread_specific_ptr</code> class defines an interface for using thread
specific storage. Thread specific storage is data associated with individual
threads and is often used to make operations <a href="definitions.html#Thread-safe">thread-safe</a>
<p>The <code>thread_specific_ptr</code> class defines an interface for using thread
specific storage. Thread specific storage is data associated with individual
threads and is often used to make operations <a href="definitions.html#Thread-safe">thread-safe</a>
that rely on global data.</p>
<p>Template <code>thread_specific_ptr</code> stores a pointer to an object obtained
via <code>new</code> on a thread-by-thread basis and calls delete on the contained
pointer when the thread terminates. Each thread initially stores the null pointer
in each <code> thread_specific_ptr</code> instance.</p>
via <code>new</code> on a thread-by-thread basis and calls a specified cleanup
handler on the contained pointer when the thread terminates. The cleanup handlers
are called in the reverse order of construction of the <code>thread_specific_ptr</code>s,
and for the initial thread are called by the destructor, providing the same
ordering gaurantees as for normal declarations. Each thread initially stores
the null pointer in each <code> thread_specific_ptr</code> instance.</p>
<p>The template <code>thread_specific_ptr</code> is useful in the following cases:</p>
<ul>
<li>An interface was originally written assuming a single thread of control
<li>An interface was originally written assuming a single thread of control
and is being ported to a multithreaded environment.</li>
<li>Each thread of control invokes sequences of methods that share data that
must be logically accessed through a globally visible access point, but are
<li>Each thread of control invokes sequences of methods that share data that
must be logically accessed through a globally visible access point, but are
physically unique for each thread, instead of being explicitly passed.</li>
</ul>
<h4><a name="class-thread_specific_ptr-synopsis"></a>Class <code>thread_specific_ptr</code>
<h4><a name="class-thread_specific_ptr-synopsis"></a>Class <code>thread_specific_ptr</code>
synopsis</h4>
<pre>
namespace boost
@@ -81,58 +84,108 @@ namespace boost
};
};
</pre>
<h4><a name="class-thread_specific_ptr-ctors"></a>Class <code>thread_specific_ptr</code>
<h4><a name="class-thread_specific_ptr-ctors"></a>Class <code>thread_specific_ptr</code>
constructors and destructor</h4>
<pre>
thread_specific_ptr();
</pre>
<dl class="function-semantics">
<dl class="function-semantics">
<dt><b>Requires:</b> The expression <code>delete get()</code> is well formed.</dt>
<dt><b>Postconditions:</b> A thread specific storage has been reserved for use
by <code>*this</code> in all threads, with each thread initially storing a
null pointer.</dt>
<dt><b>Effects:</b> A thread-specific data key is allocated and visible to all
threads in the process. Upon creation, the value <code>NULL</code> will be
associated with the new key in all active threads. Upon thread creation, the
value <code>NULL</code> will be associated with all defined keys in the new
thread. A cleanup method is registered with the key that will call <code>delete</code>
on the value associated with the key for a thread when it exits. When a thread
exits, if a key has a registered cleanup method and the thread has a non-<code>NULL</code>
value associated with that key, the value of the key is set to <code>NULL</code>
and then the cleanup method is called with the previously associated value
as its sole argument. The order in which registered cleanup methods are called
when a thread exits is undefined. If after all the cleanup methods have been
called for all non-<code>NULL</code> values, there are still some non-<code>NULL</code>
values with associated cleanup handlers the result is undefined behavior.</dt>
<dt><b>Throws:</b> <code>boost::thread_resource_error</code> if the necessary
resources can not be obtained.</dt>
<dt><b>Note:</b> There is an implementation specific limit to the number of
thread specific storage objects that can be created, and this limit may be
small.</dt>
<dt><b>Note:</b> There may be an implementation specific limit to the number
of thread specific storage objects that can be created, and this limit may
be small.</dt>
<dt><b>Rationale:</b> The most common need for cleanup will be to call <code>delete</code>
on the associated value. If other forms of cleanup are required the overloaded
constructor should be called instead.</dt>
</dl>
<pre>
thread_specific_ptr(void (*cleanup)(void*));
</pre>
<dl class="function-semantics">
<dt><b>Effects:</b> A thread-specific data key is allocated and visible to all
threads in the process. Upon creation, the value <code>NULL</code> will be
associated with the new key in all active threads. Upon thread creation, the
value <code>NULL</code> will be associated with all defined keys in the new
thread. The <code>cleanup</code> method is registered with the key and will
be called for a thread with the value associated with the key for that thread
when it exits. When a thread exits, if a key has a registered cleanup method
and the thread has a non-<code>NULL</code> value associated with that key,
the value of the key is set to <code>NULL</code> and then the cleanup method
is called with the previously associated value as its sole argument. The order
in which registered cleanup methods are called when a thread exits is undefined.
If after all the cleanup methods have been called for all non-<code>NULL</code>
values, there are still some non-<code>NULL</code> values with associated
cleanup handlers the result is undefined behavior.</dt>
<dt><b>Throws:</b> <code>boost::thread_resource_error</code> if the necessary
resources can not be obtained.</dt>
<dt><b>Note:</b> There may be an implementation specific limit to the number
of thread specific storage objects that can be created, and this limit may
be small.</dt>
<dt><b>Rationale:</b> There is the occasional need to register specialized cleanup
methods, or to register no cleanup method at all (done by passing <code>NULL</code>
to this constructor.</dt>
</dl>
<pre>
~thread_specific_ptr();
</pre>
<dl class="function-semantics">
<dt><b>Effects:</b> Deletes the thread-specific data key allocated by the constructor.
The thread-specific data values associated with the key need not be <code>NULL</code>.
It is the responsibility of the application to perform any cleanup actions
for data associated with the key.</dt>
<dt><b>Note:</b> Does not destroy any data that may be stored in any thread&#39;s
thread specific storage. For this reason you should not destroy a <code>thread_specific_ptr</code>
object until you are certain there are no threads running that have made use
of its thread specific storage.</dt>
<dt><b>Rationale:</b> Associated data is not cleaned up because registered cleanup
methods need to be run in the thread that allocated the associated data to
be gauranteed to work correctly. There's no safe way to inject the call into
another thread's execution path, making it impossible to call the cleanup
methods safely.</dt>
</dl>
<h4><a name="class-thread_specific_ptr-modifiers"></a>Class <code>thread_specific_ptr</code>
<h4><a name="class-thread_specific_ptr-modifiers"></a>Class <code>thread_specific_ptr</code>
modifier functions</h4>
<pre>
T* release();
</pre>
<dl class="function-semantics">
<dt><b>Postconditions:</b> <code>*this</code> holds the null pointer for the
<dl class="function-semantics">
<dt><b>Postconditions:</b> <code>*this</code> holds the null pointer for the
current thread.</dt>
<dt><b>Returns:</b> <code>this-&gt;get()</code> prior to the call.</dt>
<dt><b>Rationale:</b> This method provides a mechanism for the user to relinquish
control of the data associated with the thread-specific key.</dt>
</dl>
<pre>
void reset(T* p=0);
</pre>
<dl class="function-semantics">
<dt><b>Effects:</b> If <code>this-&gt;get()!= p</code> then <code>delete this-&gt;get()</code>.
</dt>
<dt><b>Effects:</b> If <code>this-&gt;get()!= p &amp;&amp; p != NULL</code>
then call the associated cleanup function. </dt>
<dt><b>Postconditions:</b> <code>*this</code> holds the pointer <code> p</code>
for the current thread.</dt>
<dt><b>Note:</b> The pointer will be deleted when the thread terminates.</dt>
</dl>
<h4><a name="class-thread_specific_ptr-observers"></a>Class <code>thread_specific_ptr</code>
<h4><a name="class-thread_specific_ptr-observers"></a>Class <code>thread_specific_ptr</code>
observer functions</h4>
<pre>
T* get() const;
</pre>
<dl class="function-semantics">
<dt><b>Returns:</b> The object stored in thread specific storage for the current
<dl class="function-semantics">
<dt><b>Returns:</b> The object stored in thread specific storage for the current
thread for <code>*this</code>.</dt>
<dt><b>Note:</b> Each thread initially returns 0.</dt>
</dl>
@@ -140,61 +193,30 @@ T* get() const;
T* operator-&gt;() const;
</pre>
<dl class="function-semantics">
<dt><b>Returns:</b> <code>this-&lt;get()</code>.</dt>
<dt><b>Returns:</b> <code>this-&gt;get()</code>.</dt>
</dl>
<pre>
T& operator*() const;
</pre>
<dl class="function-semantics">
<dt><b>Requires:</b> <code>this-&lt;get() != 0</code></dt>
<dt><b>Returns:</b> <code>this-&lt;get()</code>.</dt>
<dt><b>Requires:</b> <code>this-&gt;get() != 0</code></dt>
<dt><b>Returns:</b> <code>this-&gt;get()</code>.</dt>
</dl>
<h2><a name="examples"></a>Example(s)</h2>
<pre>
#include <a href="../../../boost/thread/thread.hpp">&lt;boost/thread/thread.hpp&gt;</a>
#include <a href="../../../boost/thread/tss.hpp">&lt;boost/thread/tss.hpp&gt;</a>
#include &lt;cassert&gt;
boost::thread_specific_ptr&lt;int&gt; value;
void increment()
{
int* p = value.get();
++*p;
}
void thread_proc()
{
value.reset(new int(0)); // initialize the thread&#39;s storage
for (int i=0; i&lt;10; ++i)
{
increment();
int* p = value.get();
assert(*p == i+1);
}
}
int main(int argc, char* argv[])
{
boost::thread_group threads;
for (int i=0; i&lt;5; ++i)
threads.create_thread(&amp;thread_proc);
threads.join_all();
}
</pre>
<p><a href="../example/tss.cpp">libs/thread/example/tss.cpp</a></p>
<hr>
<p>Revised
<p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
05 November, 2001
05 November, 2001
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p>
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
All Rights Reserved.</i></p>
<p>Permission to use, copy, modify, distribute and sell this software and its
documentation for any purpose is hereby granted without fee, provided that the
above copyright notice appear in all copies and that both that copyright notice
and this permission notice appear in supporting documentation. William E. Kempf
makes no representations about the suitability of this software for any purpose.
<p>Permission to use, copy, modify, distribute and sell this software and its
documentation for any purpose is hereby granted without fee, provided that the
above copyright notice appear in all copies and that both that copyright notice
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 &quot;as is&quot; without express or implied warranty.</p>
</body>
</html>

View File

@@ -7,11 +7,11 @@
<body link="#0000ff" vlink="#800080">
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
"header">
<tr>
<td valign="top" width="300">
<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">
<td valign="top">
<h1 align="center">Boost.Threads</h1>
<h2 align="center">Header &lt;<a href="../../../boost/thread/xtime.hpp">boost/thread/xtime.hpp</a>&gt;</h2>
</td>
@@ -19,21 +19,21 @@
</table>
<hr>
<h2>Contents</h2>
<dl class="page-index">
<dl class="page-index">
<dt><a href="#introduction">Introduction</a></dt>
<dt><a href="#values">Values</a></dt>
<dl class="page-index">
<dl class="page-index">
<dt><a href="#value-spec">TIME_UTC</a></dt>
</dl>
<dt><a href="#classes">Classes</a></dt>
<dl class="page-index">
<dl class="page-index">
<dt><a href="#class-spec">Struct <code>xtime</code></a></dt>
<dl class="page-index">
<dl class="page-index">
<dt><a href="#class-xtime-synopsis">Struct <code>xtime</code> synopsis</a></dt>
</dl>
</dl>
<dt><a href="#functions">Functions</a></dt>
<dl class="page-index">
<dl class="page-index">
<dt><a href="#function-xtime_get"><code>xtime_get</code></a></dt>
</dl>
<dt><a href="#examples">Example(s)</a></dt>
@@ -51,15 +51,15 @@ enum
TIME_UTC
}
</pre>
<p>The clock type for Coordinated Universal Time (UTC). The epoch for this clock
<p>The clock type for Coordinated Universal Time (UTC). The epoch for this clock
type is 1970-01-01 00:00:00. This is the only clock type supported by <b>Boost.Threads</b>.</p>
<h2><a name="classes"></a>Classes</h2>
<h3><a name="class-xtime"></a>Struct <code>xtime</code></h3>
<p>The <code>xtime</code> type is used to represent a point on some time scale
or a duration in time. This type may be proposed for the C standard by Markus
Kuhn. <b>Boost.Threads</b> provides only a very minimal implementation of this
proposal and it&#39;s expected that a full implementation (or some other time
library) will be provided in Boost as a separate library, at which time <b>Boost.Threads</b>
<p>The <code>xtime</code> type is used to represent a point on some time scale
or a duration in time. This type may be proposed for the C standard by Markus
Kuhn. <b>Boost.Threads</b> provides only a very minimal implementation of this
proposal and it&#39;s expected that a full implementation (or some other time
library) will be provided in Boost as a separate library, at which time <b>Boost.Threads</b>
will deprecate its implementation.</p>
<h4><a name="class-xtime-synopsis"></a>Struct <code>xtime</code> synopsis</h4>
<pre>
@@ -80,42 +80,31 @@ namespace boost
<pre>
<a name="function-xtime_get"></a>int xtime_get(struct xtime* xtp, int clock_type);
</pre>
<dl class="function-semantics">
<dt><b>Postconditions:</b> <code>xtp</code> represents the current point in
<dl class="function-semantics">
<dt><b>Postconditions:</b> <code>xtp</code> represents the current point in
time as a duration since the epoch specified by the <code> clock_type</code>.</dt>
<dt><b>Returns:</b> <code>clock_type</code> if successful, otherwise 0.</dt>
<dt><b>Note:</b> The resolution is implementation specific. For many implementations
the best resolution of time is far more than one nanosecond, and even when
the resolution is reasonably good, the latency of a call to <code>xtime_get()</code>
may be significant. For maximum portability, avoid durations of less than
<dt><b>Note:</b> The resolution is implementation specific. For many implementations
the best resolution of time is far more than one nanosecond, and even when
the resolution is reasonably good, the latency of a call to <code>xtime_get()</code>
may be significant. For maximum portability, avoid durations of less than
one second.</dt>
</dl>
<h2><a name="examples"></a>Example(s)</h2>
<pre>
#include <a href="../../../boost/thread/thread.hpp">&lt;boost/thread/thread.hpp&gt;</a>
#include <a href="../../../boost/thread/tss.hpp">&lt;boost/thread/xtime.hpp&gt;</a>
int main(int argc, char* argv[])
{
boost::xtime xt;
boost::xtime_get(&amp;XT, boost::TIME_UTC);
xt.sec += 1;
boost::thread::sleep(XT); // Sleep for 1 second
}
</pre>
<p><a href="../example/xtime.cpp">libs/thread/example/xtime.cpp</a></p>
<hr>
<p>Revised
<p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
05 November, 2001
05 November, 2001
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p>
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
All Rights Reserved.</i></p>
<p>Permission to use, copy, modify, distribute and sell this software and its
documentation for any purpose is hereby granted without fee, provided that the
above copyright notice appear in all copies and that both that copyright notice
and this permission notice appear in supporting documentation. William E. Kempf
makes no representations about the suitability of this software for any purpose.
<p>Permission to use, copy, modify, distribute and sell this software and its
documentation for any purpose is hereby granted without fee, provided that the
above copyright notice appear in all copies and that both that copyright notice
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 &quot;as is&quot; without express or implied warranty.</p>
</body>
</html>

View File

@@ -2,22 +2,6 @@
# distribute this software is granted provided this copyright notice appears
# in all copies. This software is provided "as is" without express or implied
# warranty, and with no claim as to its suitability for any purpose.
#
# Boost.Threads build 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:
# 1. PTW32 may be used on Win32 platforms to specify that the pthreads-win32
# library should be used instead of "native" threads. This feature is
# mostly used for testing and it's generally recommended you use the
# native threading libraries instead. PTW32 should be set to be a list
# of two strings, the first specifying the installation path of the
# pthreads-win32 library and the second specifying which library
# variant to link against (see the pthreads-win32 documentation).
# Example: jam -sPTW32="c:\pthreads-win32 pthreadVCE.lib"
# Declare the location of this subproject relative to the root.
subproject libs/thread/example ;
@@ -28,41 +12,23 @@ subproject libs/thread/example ;
SEARCH on <module@>threads.jam = $(BOOST_ROOT)/libs/thread/build ;
include <module@>threads.jam ;
#######################
# Declare the Boost.Threads example program monitor.
exe monitor
: monitor/monitor.cpp
<lib>../build/boost_thread
$(threadmon)
: <include>$(BOOST_ROOT)
$(pthreads-win32)
<threading>multi
: debug release <runtime-link>static/dynamic
template example
## sources ##
: <template>thread_base <lib>../build/boost_thread <lib>../../test/build/unit_test_framework $(threadmon)
## requirements ##
:
## default build ##
: release <runtime-link>static
;
#######################
# Declare the Boost.Threads example program starvephil.
exe starvephil
: starvephil/starvephil.cpp
<lib>../build/boost_thread
$(threadmon)
: <include>$(BOOST_ROOT)
$(pthreads-win32)
<threading>multi
: debug release <runtime-link>static/dynamic
;
#######################
# Declare the Boost.Threads example program tennis.
exe tennis
: tennis/tennis.cpp
<lib>../build/boost_thread
$(threadmon)
: <include>$(BOOST_ROOT)
$(pthreads-win32)
<threading>multi
: debug release <runtime-link>static/dynamic
;
exe monitor : <template>example monitor.cpp ;
exe starvephil : <template>example starvephil.cpp ;
exe tennis : <template>example tennis.cpp ;
exe condition : <template>example condition.cpp ;
exe mutex : <template>example mutex.cpp ;
exe once : <template>example once.cpp ;
exe recursive_mutex : <template>example recursive_mutex.cpp ;
exe thread : <template>example thread.cpp ;
exe thread_group : <template>example thread_group.cpp ;
exe tss : <template>example tss.cpp ;
exe xtime : <template>example xtime.cpp ;

68
example/condition.cpp Normal file
View File

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

106
example/monitor.cpp Normal file
View File

@@ -0,0 +1,106 @@
#include <vector>
#include <iostream>
#include <boost/thread/condition.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/recursive_mutex.hpp>
#include <boost/thread/thread.hpp>
namespace {
const int ITERS = 100;
boost::mutex io_mutex;
}
template <typename M>
class buffer_t
{
public:
typedef typename M::scoped_lock scoped_lock;
buffer_t(int n)
: p(0), c(0), full(0), buf(n)
{
}
void send(int m)
{
scoped_lock lk(mutex);
while (full == buf.size())
cond.wait(lk);
buf[p] = m;
p = (p+1) % buf.size();
++full;
cond.notify_one();
}
int receive()
{
scoped_lock lk(mutex);
while (full == 0)
cond.wait(lk);
int i = buf[c];
c = (c+1) % buf.size();
--full;
cond.notify_one();
return i;
}
static buffer_t& get_buffer()
{
static buffer_t buf(2);
return buf;
}
static void do_sender_thread()
{
for (int n = 0; n < ITERS; ++n)
{
{
boost::mutex::scoped_lock lock(io_mutex);
std::cout << "sending: " << n << std::endl;
}
get_buffer().send(n);
}
}
static void do_receiver_thread()
{
for (int x=0; x < (ITERS/2); ++x)
{
int n = get_buffer().receive();
{
boost::mutex::scoped_lock lock(io_mutex);
std::cout << "received: " << n << std::endl;
}
}
}
private:
M mutex;
boost::condition cond;
unsigned int p, c, full;
std::vector<int> buf;
};
template <typename M>
void do_test(M* dummy=0)
{
typedef buffer_t<M> buffer_type;
buffer_type::get_buffer();
boost::thread thrd1(&buffer_type::do_receiver_thread);
boost::thread thrd2(&buffer_type::do_receiver_thread);
boost::thread thrd3(&buffer_type::do_sender_thread);
thrd1.join();
thrd2.join();
thrd3.join();
}
void test_buffer()
{
do_test<boost::mutex>();
do_test<boost::recursive_mutex>();
}
int main()
{
test_buffer();
return 0;
}

41
example/mutex.cpp Normal file
View File

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

25
example/once.cpp Normal file
View File

@@ -0,0 +1,25 @@
#include <boost/thread/thread.hpp>
#include <boost/thread/once.hpp>
#include <cassert>
int value=0;
boost::once_flag once = BOOST_ONCE_INIT;
void init()
{
++value;
}
void thread_proc()
{
boost::call_once(&init, once);
}
int main(int argc, char* argv[])
{
boost::thread_group threads;
for (int i=0; i<5; ++i)
threads.create_thread(&thread_proc);
threads.join_all();
assert(value == 1);
}

View File

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

171
example/starvephil.cpp Normal file
View File

@@ -0,0 +1,171 @@
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/xtime.hpp>
#include <iostream>
#include <time.h>
namespace
{
boost::mutex iomx;
}
class canteen
{
public:
canteen() : m_chickens(0) { }
void get(int id)
{
boost::mutex::scoped_lock lock(m_mutex);
while (m_chickens == 0)
{
{
boost::mutex::scoped_lock lock(iomx);
std::cout << "(" << clock() << ") Phil" << id <<
": wot, no chickens? I'll WAIT ..." << std::endl;
}
m_condition.wait(lock);
}
{
boost::mutex::scoped_lock lock(iomx);
std::cout << "(" << clock() << ") Phil" << id <<
": those chickens look good ... one please ..." << std::endl;
}
m_chickens--;
}
void put(int value)
{
boost::mutex::scoped_lock lock(m_mutex);
{
boost::mutex::scoped_lock lock(iomx);
std::cout << "(" << clock() <<
") Chef: ouch ... make room ... this dish is very hot ..." << std::endl;
}
boost::xtime xt;
boost::xtime_get(&xt, boost::TIME_UTC);
xt.sec += 3;
boost::thread::sleep(xt);
m_chickens += value;
{
boost::mutex::scoped_lock lock(iomx);
std::cout << "(" << clock() <<
") Chef: more chickens ... " << m_chickens <<
" now available ... NOTIFYING ..." << std::endl;
}
m_condition.notify_all();
}
private:
boost::mutex m_mutex;
boost::condition m_condition;
int m_chickens;
};
canteen g_canteen;
void chef()
{
const int chickens = 4;
{
boost::mutex::scoped_lock lock(iomx);
std::cout << "(" << clock() << ") Chef: starting ..." << std::endl;
}
for (;;)
{
{
boost::mutex::scoped_lock lock(iomx);
std::cout << "(" << clock() << ") Chef: cooking ..." << std::endl;
}
boost::xtime xt;
boost::xtime_get(&xt, boost::TIME_UTC);
xt.sec += 2;
boost::thread::sleep(xt);
{
boost::mutex::scoped_lock lock(iomx);
std::cout << "(" << clock() << ") Chef: " << chickens
<< " chickens, ready-to-go ..." << std::endl;
}
g_canteen.put(chickens);
}
}
struct phil
{
phil(int id) : m_id(id) { }
void run() {
{
boost::mutex::scoped_lock lock(iomx);
std::cout << "(" << clock() << ") Phil" << m_id << ": starting ..." << std::endl;
}
for (;;)
{
if (m_id > 0)
{
boost::xtime xt;
boost::xtime_get(&xt, boost::TIME_UTC);
xt.sec += 3;
boost::thread::sleep(xt);
}
{
boost::mutex::scoped_lock lock(iomx);
std::cout << "(" << clock() << ") Phil" << m_id
<< ": gotta eat ..." << std::endl;
}
g_canteen.get(m_id);
{
boost::mutex::scoped_lock lock(iomx);
std::cout << "(" << clock() << ") Phil" << m_id
<< ": mmm ... that's good ..." << std::endl;
}
}
}
static void do_thread(void* param) {
static_cast<phil*>(param)->run();
}
int m_id;
};
struct thread_adapt
{
thread_adapt(void (*func)(void*), void* param) : _func(func), _param(param) { }
int operator()() const
{
_func(_param);
return 0;
}
void (*_func)(void*);
void* _param;
};
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;
};
int main(int argc, char* argv[])
{
boost::thread thrd_chef(&chef);
phil p[] = { phil(0), phil(1), phil(2), phil(3), phil(4) };
boost::thread thrd_phil0(thread_adapter(&phil::do_thread, &p[0]));
boost::thread thrd_phil1(thread_adapter(&phil::do_thread, &p[1]));
boost::thread thrd_phil2(thread_adapter(&phil::do_thread, &p[2]));
boost::thread thrd_phil3(thread_adapter(&phil::do_thread, &p[3]));
boost::thread thrd_phil4(thread_adapter(&phil::do_thread, &p[4]));
thrd_chef.join();
thrd_phil0.join();
thrd_phil1.join();
thrd_phil2.join();
thrd_phil3.join();
thrd_phil4.join();
return 0;
}

120
example/tennis.cpp Normal file
View File

@@ -0,0 +1,120 @@
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/xtime.hpp>
#include <iostream>
#if defined(BOOST_HAS_WINTHREADS)
# include <windows.h>
# include <process.h>
#endif
enum game_state
{
START,
PLAYER_A,
PLAYER_B,
GAME_OVER,
ONE_PLAYER_GONE,
BOTH_PLAYERS_GONE
};
int state;
boost::mutex mutex;
boost::condition cond;
char* player_name(int state)
{
if (state == PLAYER_A)
return "PLAYER-A";
if (state == PLAYER_B)
return "PLAYER-B";
throw "bad player";
return 0;
}
void player(void* param)
{
boost::mutex::scoped_lock lock(mutex);
int active = (int)param;
int other = active == PLAYER_A ? PLAYER_B : PLAYER_A;
while (state < GAME_OVER)
{
std::cout << player_name(active) << ": Play." << std::endl;
state = other;
cond.notify_all();
do
{
cond.wait(lock);
if (state == other)
std::cout << "---" << player_name(active) << ": Spurious wakeup!" << std::endl;
} while (state == other);
}
++state;
std::cout << player_name(active) << ": Gone." << std::endl;
cond.notify_all();
}
struct thread_adapt
{
thread_adapt(void (*func)(void*), void* param) : _func(func), _param(param) { }
int operator()() const
{
_func(_param);
return 0;
}
void (*_func)(void*);
void* _param;
};
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;
};
int main(int argc, char* argv[])
{
state = START;
boost::thread thrda(thread_adapter(&player, (void*)PLAYER_A));
boost::thread thrdb(thread_adapter(&player, (void*)PLAYER_B));
boost::xtime xt;
boost::xtime_get(&xt, boost::TIME_UTC);
xt.sec += 1;
boost::thread::sleep(xt);
{
boost::mutex::scoped_lock lock(mutex);
std::cout << "---Noise ON..." << std::endl;
}
for (int i = 0; i < 1000000; ++i)
cond.notify_all();
{
boost::mutex::scoped_lock lock(mutex);
std::cout << "---Noise OFF..." << std::endl;
state = GAME_OVER;
cond.notify_all();
do
{
cond.wait(lock);
} while (state != BOTH_PLAYERS_GONE);
}
std::cout << "GAME OVER" << std::endl;
thrda.join();
thrdb.join();
return 0;
}

29
example/thread.cpp Normal file
View File

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

19
example/thread_group.cpp Normal file
View File

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

30
example/tss.cpp Normal file
View File

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

10
example/xtime.cpp Normal file
View File

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

View File

@@ -0,0 +1,38 @@
// Copyright (C) 2002
// David Moore, 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_BARRIER_JDM030602_HPP
#define BOOST_BARRIER_JDM030602_HPP
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp>
namespace boost {
class barrier
{
public:
barrier(unsigned int count);
~barrier();
bool wait();
private:
mutex m_mutex;
condition m_cond;
unsigned int m_threshold;
unsigned int m_count;
unsigned int m_generation;
};
} // namespace boost
#endif

View File

@@ -91,7 +91,7 @@ private:
enter_wait();
#endif
typedef typename detail::thread::lock_ops<M> lock_ops;
typedef detail::thread::lock_ops<M> lock_ops;
typename lock_ops::lock_state state;
lock_ops::unlock(mutex, state);
@@ -111,7 +111,7 @@ private:
enter_wait();
#endif
typedef typename detail::thread::lock_ops<M> lock_ops;
typedef detail::thread::lock_ops<M> lock_ops;
typename lock_ops::lock_state state;
lock_ops::unlock(mutex, state);

View File

@@ -0,0 +1,334 @@
// Copyright (C) 2002
// David Moore
//
// Original scoped_lock implementation
// Copyright (C) 2001
// 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. David Moore makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#ifndef BOOST_XRWLOCK_JDM031002_HPP
#define BOOST_XRWLOCK_JDM031002_HPP
#include <boost/utility.hpp>
#include <boost/thread/exceptions.hpp>
namespace boost {
class condition;
struct xtime;
typedef enum
{
NO_LOCK=0,
SHARED_LOCK=1,
EXCL_LOCK=2
} rw_lock_state;
namespace detail { namespace thread {
template <typename Mutex>
class rw_lock_ops : private noncopyable
{
private:
rw_lock_ops() { }
public:
static void wrlock(Mutex& m)
{
m.do_wrlock();
}
static void rdlock(Mutex& m)
{
m.do_rdlock();
}
static void wrunlock(Mutex& m)
{
m.do_wrunlock();
}
static void rdunlock(Mutex &m)
{
m.do_rdunlock();
}
static bool try_wrlock(Mutex &m)
{
return m.do_try_wrlock();
}
static bool try_rdlock(Mutex &m)
{
return m.do_try_rdlock();
}
static bool timed_wrlock(Mutex &m,const xtime &xt)
{
return m.do_timed_wrlock(xt);
}
static bool timed_rdlock(Mutex &m,const xtime &xt)
{
return m.do_timed_rdlock(xt);
}
};
template <typename RWMutex>
class scoped_rw_lock : private noncopyable
{
public:
typedef RWMutex mutex_type;
explicit scoped_rw_lock(RWMutex& mx, rw_lock_state initial_state=SHARED_LOCK)
: m_mutex(mx), m_locked(NO_LOCK)
{
if(initial_state == SHARED_LOCK)
rdlock();
else if(initial_state == EXCL_LOCK)
wrlock();
}
~scoped_rw_lock()
{
if(m_locked != NO_LOCK)
unlock();
}
void rdlock()
{
if (m_locked != NO_LOCK) throw lock_error();
rw_lock_ops<RWMutex>::rdlock(m_mutex);
m_locked = SHARED_LOCK;
}
void wrlock()
{
if(m_locked != NO_LOCK) throw lock_error();
rw_lock_ops<RWMutex>::wrlock(m_mutex);
m_locked = EXCL_LOCK;
}
void unlock()
{
if (m_locked == NO_LOCK) throw lock_error();
if(m_locked == SHARED_LOCK)
rw_lock_ops<RWMutex>::rdunlock(m_mutex);
else
rw_lock_ops<RWMutex>::wrunlock(m_mutex);
m_locked = NO_LOCK;
}
bool locked() const
{
return m_locked != NO_LOCK;
}
operator const void*() const
{
return (m_locked != NO_LOCK) ? this : 0;
}
rw_lock_state state() const
{
return m_locked;
}
private:
RWMutex& m_mutex;
rw_lock_state m_locked;
};
template <typename TryRWMutex>
class scoped_try_rw_lock : private noncopyable
{
public:
typedef TryRWMutex mutex_type;
explicit scoped_try_rw_lock(TryRWMutex& mx)
: m_mutex(mx), m_locked(NO_LOCK)
{
try_rdlock();
}
scoped_try_rw_lock(TryRWMutex& mx, rw_lock_state initial_state)
: m_mutex(mx), m_locked(NO_LOCK)
{
if(initial_state == SHARED_LOCK)
rdlock();
else if(initial_state == EXCL_LOCK)
wrlock();
}
~scoped_try_rw_lock()
{
if(m_locked != NO_LOCK)
unlock();
}
void rdlock()
{
if (m_locked != NO_LOCK) throw lock_error();
rw_lock_ops<TryRWMutex>::rdlock(m_mutex);
m_locked = SHARED_LOCK;
}
bool try_rdlock()
{
if (m_locked != NO_LOCK) throw lock_error();
if(rw_lock_ops<TryRWMutex>::try_rdlock(m_mutex))
{
m_locked = SHARED_LOCK;
return true;
}
return false;
}
void wrlock()
{
if(m_locked != NO_LOCK) throw lock_error();
rw_lock_ops<TryRWMutex>::wrlock(m_mutex);
m_locked = EXCL_LOCK;
}
bool try_wrlock()
{
if (m_locked != NO_LOCK) throw lock_error();
if(rw_lock_ops<TryRWMutex>::try_wrlock(m_mutex))
{
m_locked = EXCL_LOCK;
return true;
}
return false;
}
void unlock()
{
if (m_locked == NO_LOCK) throw lock_error();
if(m_locked == SHARED_LOCK)
rw_lock_ops<TryRWMutex>::rdunlock(m_mutex);
else
rw_lock_ops<TryRWMutex>::wrunlock(m_mutex);
m_locked = NO_LOCK;
}
bool locked() const
{
return m_locked != NO_LOCK;
}
operator const void*() const
{
return (m_locked != NO_LOCK) ? this : 0;
}
rw_lock_state state() const
{
return m_locked;
}
private:
TryRWMutex& m_mutex;
rw_lock_state m_locked;
};
template <typename TimedRWMutex>
class scoped_timed_rw_lock : private noncopyable
{
public:
typedef TimedRWMutex mutex_type;
explicit scoped_timed_rw_lock(TimedRWMutex& mx, const xtime &xt)
: m_mutex(mx), m_locked(NO_LOCK)
{
timed_sharedlock(xt);
}
scoped_timed_rw_lock(TimedRWMutex& mx, rw_lock_state initial_state)
: m_mutex(mx), m_locked(NO_LOCK)
{
if(initial_state == SHARED_LOCK)
rdlock();
else if(initial_state == EXCL_LOCK)
wrlock();
}
~scoped_timed_rw_lock()
{
if(m_locked != NO_LOCK)
unlock();
}
void rdlock()
{
if (m_locked != NO_LOCK) throw lock_error();
rw_lock_ops<TimedRWMutex>::rdlock(m_mutex);
m_locked = SHARED_LOCK;
}
bool timed_rdlock(const xtime &xt)
{
if (m_locked != NO_LOCK) throw lock_error();
if(rw_lock_ops<TimedRWMutex>::timed_rdlock(m_mutex,xt))
{
m_locked = SHARED_LOCK;
return true;
}
return false;
}
void wrlock()
{
if(m_locked != NO_LOCK) throw lock_error();
rw_lock_ops<TimedRWMutex>::wrlock(m_mutex);
m_locked = EXCL_LOCK;
}
bool timed_wrlock(const xtime &xt)
{
if (m_locked != NO_LOCK) throw lock_error();
if(rw_lock_ops<TimedRWMutex>::timed_wrlock(m_mutex,xt))
{
m_locked = EXCL_LOCK;
return true;
}
return false;
}
void unlock()
{
if (m_locked == NO_LOCK) throw lock_error();
if(m_locked == SHARED_LOCK)
rw_lock_ops<TimedRWMutex>::rdunlock(m_mutex);
else
rw_lock_ops<TimedRWMutex>::wrunlock(m_mutex);
m_locked = NO_LOCK;
}
bool locked() const
{
return m_locked != NO_LOCK;
}
operator const void*() const
{
return (m_locked != NO_LOCK) ? this : 0;
}
rw_lock_state state() const
{
return m_locked;
}
private:
TimedRWMutex& m_mutex;
rw_lock_state m_locked;
};
} // namespace thread
} // namespace detail
} // namespace boost
// Change Log:
// 03/10/02 Initial version
#endif

View File

@@ -30,8 +30,8 @@ typedef pthread_once_t once_flag;
#elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
typedef bool once_flag;
#define BOOST_ONCE_INIT false
typedef long once_flag;
#define BOOST_ONCE_INIT 0
#endif

View File

@@ -0,0 +1,214 @@
// Copyright (C) 2002
// David Moore
//
// Original mutex design and implementation
// Copyright (C) 2001
// 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. David Moore makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
//
//
// A Boost::threads implementation of a synchronization
// primitive which can allow multiple readers or a single
// writer to have access to a shared resource.
#ifndef BOOST_RW_MUTEX_JDM030602_HPP
#define BOOST_RW_MUTEX_JDM030602_HPP
#include <boost/config.hpp>
#ifndef BOOST_HAS_THREADS
# error Thread support is unavailable!
#endif
#include <boost/utility.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/detail/lock.hpp>
#include <boost/thread/detail/rw_lock.hpp>
#include <boost/thread/condition.hpp>
namespace boost {
typedef enum
{
sp_writer_priority,
sp_reader_priority,
sp_alternating_many_reads,
sp_alternating_single_reads
} rw_scheduling_policy;
namespace detail { namespace thread {
// Shared implementation construct for explicit Scheduling Policies
//
// This implementation is susceptible to self-deadlock, though....
template<typename Mutex>
struct rw_mutex_impl
{
typedef detail::thread::scoped_lock<Mutex> scoped_lock;
typedef detail::thread::scoped_try_lock<Mutex> scoped_try_lock;
typedef detail::thread::scoped_timed_lock<Mutex> scoped_timed_lock;
rw_mutex_impl(rw_scheduling_policy sp) :
m_num_waiting_writers(0),
m_num_waiting_readers(0),
m_num_waiting_promotion(0),
m_state(0),
m_sp(sp),
m_readers_next(1)
{}
Mutex m_prot;
condition m_waiting_writers;
condition m_waiting_readers;
int m_num_waiting_writers;
int m_num_waiting_readers;
condition m_waiting_promotion;
int m_num_waiting_promotion;
int m_state; // -1 = excl locked
// 0 = unlocked
// 1-> INT_MAX - shared locked
rw_scheduling_policy m_sp;
// For alternating priority policies, who goes next?
int m_readers_next;
void do_rdlock();
void do_wrlock();
void do_wrunlock();
void do_rdunlock();
bool do_try_wrlock();
bool do_try_rdlock();
bool do_timed_wrlock(const xtime &xt);
bool do_timed_rdlock(const xtime &xt);
bool do_try_promote_rdlock();
void do_wakeups();
};
}// namespace detail
}// namespace thread
class rw_mutex : private noncopyable
{
public:
rw_mutex(rw_scheduling_policy sp) :
m_impl(sp)
{
}
~rw_mutex(){}
rw_scheduling_policy policy() const {return m_impl.m_sp;}
friend class detail::thread::rw_lock_ops<rw_mutex>;
typedef detail::thread::scoped_rw_lock<rw_mutex> scoped_rw_lock;
typedef detail::thread::scoped_try_rw_lock<rw_mutex> scoped_try_rw_lock;
private:
// Operations that will eventually be done only
// via lock types
void do_wrlock();
void do_rdlock();
void do_wrunlock();
void do_rdunlock();
detail::thread::rw_mutex_impl<mutex> m_impl;
};
class try_rw_mutex : private noncopyable
{
public:
try_rw_mutex(rw_scheduling_policy sp) :
m_impl(sp)
{
}
~try_rw_mutex(){}
rw_scheduling_policy policy() const {return m_impl.m_sp;}
friend class detail::thread::rw_lock_ops<try_rw_mutex>;
typedef detail::thread::scoped_rw_lock<try_rw_mutex> scoped_rw_lock;
typedef detail::thread::scoped_try_rw_lock<try_rw_mutex> scoped_try_rw_lock;
private:
// Operations that will eventually be done only
// via lock types
void do_wrlock();
void do_rdlock();
void do_wrunlock();
void do_rdunlock();
bool do_try_wrlock();
bool do_try_rdlock();
detail::thread::rw_mutex_impl<try_mutex> m_impl;
};
class timed_rw_mutex : private noncopyable
{
public:
timed_rw_mutex(rw_scheduling_policy sp) :
m_impl(sp)
{
}
~timed_rw_mutex(){}
rw_scheduling_policy policy() const {return m_impl.m_sp;}
friend class detail::thread::rw_lock_ops<timed_rw_mutex>;
typedef detail::thread::scoped_rw_lock<timed_rw_mutex> scoped_rw_lock;
typedef detail::thread::scoped_try_rw_lock<timed_rw_mutex> scoped_try_rw_lock;
typedef detail::thread::scoped_timed_rw_lock<timed_rw_mutex> scoped_timed_rw_lock;
private:
// Operations that will eventually be done only
// via lock types
void do_wrlock();
void do_rdlock();
void do_wrunlock();
void do_rdunlock();
bool do_try_wrlock();
bool do_try_rdlock();
bool do_timed_wrlock(const xtime &xt);
bool do_timed_rdlock(const xtime &xt);
detail::thread::rw_mutex_impl<timed_mutex> m_impl;
};
} // namespace boost
#endif

View File

@@ -0,0 +1,56 @@
// Copyright (C) 2002
// William E. Kempf, David Moore
//
// 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_MUTEX_JDM062402_HPP
#define BOOST_MUTEX_JDM062402_HPP
#include <boost/config.hpp>
#ifndef BOOST_HAS_THREADS
# error Thread support is unavailable!
#endif
#include <boost/utility.hpp>
#include <boost/function.hpp>
#include <boost/thread/exceptions.hpp>
#include <string>
namespace boost {
class shared_memory
{
public:
// Obtain a shared memory block len bytes long, zero initialized
shared_memory(const char *name,size_t len);
// Obtain a shared memory block and initialize it with initfunc
shared_memory(const char *name,size_t len,const boost::function2<void,void *,size_t> &initfunc);
~shared_memory();
void *get(){return m_ptr;}
private:
void create(const char *name,
size_t len);
void *m_ptr; // Pointer to shared memory block
int m_mem_obj; // Platform specific handle to shared memory block
void *m_h_event; // Platform specific handle to event saying block initialized.
size_t m_len;
boost::function2<void,void *,size_t> m_initfunc;
};
}; // namespace boost
#endif

View File

@@ -34,9 +34,17 @@ namespace boost {
struct xtime;
class thread_cancel
{
public:
thread_cancel() { }
};
class thread : private noncopyable
{
public:
enum category_type { boost, native, adopted };
thread();
explicit thread(const function0<void>& threadfunc);
~thread();
@@ -44,23 +52,16 @@ public:
bool operator==(const thread& other) const;
bool operator!=(const thread& other) const;
category_type category() const;
void join();
void cancel();
static void test_cancel();
static void sleep(const xtime& xt);
static void yield();
private:
#if defined(BOOST_HAS_WINTHREADS)
void* m_thread;
unsigned int m_id;
#elif defined(BOOST_HAS_PTHREADS)
private:
pthread_t m_thread;
#elif defined(BOOST_HAS_MPTASKS)
MPQueueID m_pJoinQueueID;
MPTaskID m_pTaskID;
#endif
bool m_joinable;
void* m_handle;
};
class thread_group : private noncopyable
@@ -72,6 +73,7 @@ public:
thread* create_thread(const function0<void>& threadfunc);
void add_thread(thread* thrd);
void remove_thread(thread* thrd);
thread* thread_group::find(thread& thrd);
void join_all();
private:

View File

@@ -0,0 +1,52 @@
// Copyright (C) 2002 David Moore
//
// Based on Boost.Threads
// Copyright (C) 2001
// William E. Kempf
//
// Derived loosely from work queue manager in "Programming POSIX Threads"
// by David Butenhof.
//
// 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_POOL_JDM031802_HPP
#define BOOST_THREAD_POOL_JDM031802_HPP
#include <boost/config.hpp>
#ifndef BOOST_HAS_THREADS
# error Thread support is unavailable!
#endif
#include <boost/function.hpp>
#include <boost/limits.hpp>
namespace boost {
class thread_pool
{
public:
thread_pool(int max_threads=std::numeric_limits<int>::max(),
int min_threads=0,
int timeout_secs=5,
int timeout_nsecs=0);
~thread_pool();
void add(const boost::function0<void> &job);
void join();
void cancel();
void detach();
private:
class impl;
impl* m_pimpl;
};
} // namespace boost
#endif

View File

@@ -18,6 +18,7 @@
#endif
#include <boost/utility.hpp>
#include <boost/function.hpp>
#if defined(BOOST_HAS_PTHREADS)
# include <pthread.h>
@@ -26,56 +27,71 @@
#endif
namespace boost {
namespace detail {
class tss_ref
{
public:
tss_ref();
};
class tss : private noncopyable
{
public:
tss(void (*cleanup)(void*)=0);
tss(boost::function1<void, void*> cleanup);
~tss();
void* get() const;
bool set(void* value);
void set(void* value);
void cleanup(void* p);
private:
#if defined(BOOST_HAS_WINTHREADS)
unsigned long m_key;
void (*m_cleanup)(void*);
#elif defined(BOOST_HAS_PTHREADS)
pthread_key_t m_key;
#elif defined(BOOST_HAS_MPTASKS)
TaskStorageIndex m_key;
void (*m_cleanup)(void*);
#endif
int m_slot;
int m_generation;
};
#if defined(BOOST_HAS_MPTASKS)
void thread_cleanup();
#endif
}
struct tss_adapter
{
tss_adapter(boost::function1<void, void*> cleanup) : m_cleanup(cleanup) { }
void operator()(void* p) { m_cleanup(p); }
boost::function1<void, void*> m_cleanup;
};
} // namespace detail
template <typename T>
class thread_specific_ptr : private noncopyable
{
public:
thread_specific_ptr() : m_tss(&thread_specific_ptr<T>::cleanup) { }
thread_specific_ptr() : m_tss(detail::tss_adapter(&thread_specific_ptr<T>::cleanup)) { }
thread_specific_ptr(void (*clean)(void*)) : m_tss(detail::tss_adapter(clean)) { }
~thread_specific_ptr() { reset(); }
T* get() const { return static_cast<T*>(m_tss.get()); }
T* operator->() const { return get(); }
T& operator*() const { return *get(); }
T* release() { T* temp = get(); m_tss.set(0); return temp; }
void reset(T* p=0) { T* cur = get(); if (cur == p) return; delete cur; m_tss.set(p); }
void reset(T* p=0) { T* cur = get(); if (cur == p) return; m_tss.set(p); if (cur) m_tss.cleanup(cur); }
private:
static void cleanup(void* p) { delete static_cast<T*>(p); }
mutable detail::tss m_tss;
detail::tss m_tss;
};
} // namespace boost
namespace {
// This injects a tss_ref into every namespace and helps to insure we get a proper
// value for the "main" thread
boost::detail::tss_ref _tss_ref__7BAFF4714CFC42ae9C425F60CE3714D8;
}
// Change Log:
// 6 Jun 01 WEKEMPF Initial version.
// 30 May 02 WEKEMPF Added interface to set specific cleanup handlers. Removed TLS slot limits
// from most implementations.
#endif // BOOST_TSS_WEK070601_HPP

View File

@@ -40,6 +40,13 @@ struct xtime
};
int xtime_get(struct xtime* xtp, int clock_type);
inline int xtime_cmp(const xtime& xt1, const xtime& xt2)
{
int res = (int)(xt1.sec - xt2.sec);
if (res == 0)
res = (int)(xt1.nsec - xt2.nsec);
return res;
}
} // namespace boost

8
index.html Normal file
View File

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

45
src/barrier.cpp Normal file
View File

@@ -0,0 +1,45 @@
// Copyright (C) 2002
// David Moore, 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/barrier.hpp>
namespace boost {
barrier::barrier(unsigned int count)
: m_threshold(count), m_count(count), m_generation(0)
{
if (count == 0)
throw std::invalid_argument("count cannot be zero.");
}
barrier::~barrier()
{
}
bool barrier::wait()
{
boost::mutex::scoped_lock lock(m_mutex);
unsigned int gen = m_generation;
if (--m_count == 0)
{
m_generation++;
m_count = m_threshold;
m_cond.notify_all();
return true;
}
while (gen == m_generation)
m_cond.wait(lock);
return false;
}
} // namespace boost

View File

@@ -244,14 +244,28 @@ void condition::do_wait()
bool condition::do_timed_wait(const xtime& xt)
{
int milliseconds;
to_duration(xt, milliseconds);
bool ret = false;
unsigned int res = 0;
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue), milliseconds);
assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
bool ret = (res == WAIT_OBJECT_0);
for (;;)
{
int milliseconds;
to_duration(xt, milliseconds);
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue), milliseconds);
assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
ret = (res == WAIT_OBJECT_0);
if (res == WAIT_TIMEOUT)
{
xtime cur;
xtime_get(&cur, TIME_UTC);
if (xtime_cmp(xt, cur) > 0)
continue;
}
break;
}
unsigned was_waiting=0;
unsigned was_gone=0;

View File

@@ -72,7 +72,7 @@ OSStatus safe_enter_critical_region(MPCriticalRegionID pCriticalRegionID, Durati
if(lDuration != kDurationImmediate && lDuration != kDurationForever)
{
sExpiration = AddDurationToAbsolute(lDuration, UpTime());
}
}
lStatus = MPEnterCriticalRegion(pCriticalRegionCriticalRegionID, lDuration);
assert(lStatus == noErr || lStatus == kMPTimeoutErr);
if(lStatus == noErr)
@@ -92,7 +92,7 @@ OSStatus safe_enter_critical_region(MPCriticalRegionID pCriticalRegionID, Durati
// no time left
lDuration = kDurationImmediate;
}
}
}
// if we entered the critical region, exit it again
lStatus = MPExitCriticalRegion(pCriticalRegionCriticalRegionID);
assert(lStatus == noErr);

View File

@@ -145,12 +145,25 @@ bool timed_mutex::do_trylock()
bool timed_mutex::do_timedlock(const xtime& xt)
{
int milliseconds;
to_duration(xt, milliseconds);
unsigned int res = 0;
for (;;)
{
int milliseconds;
to_duration(xt, milliseconds);
unsigned int res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), milliseconds);
assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
return res == WAIT_OBJECT_0;
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), milliseconds);
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;
}
}
void timed_mutex::do_unlock()

View File

@@ -59,17 +59,51 @@ static void do_once()
}
#elif defined(BOOST_HAS_MPTASKS)
void *remote_call_proxy(void *pData)
{
std::pair<void (*)(), boost::once_flag *> &rData(*reinterpret_cast<std::pair<void (*)(), boost::once_flag *> *>(pData));
if(*rData.second == false)
namespace {
void *remote_call_proxy(void *pData)
{
rData.first();
*rData.second = true;
std::pair<void (*)(), boost::once_flag *> &rData(*reinterpret_cast<std::pair<void (*)(), boost::once_flag *> *>(pData));
if(*rData.second == false)
{
rData.first();
*rData.second = true;
}
return(NULL);
}
}
#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);
}
return(NULL);
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
@@ -78,12 +112,7 @@ namespace boost {
void call_once(void (*func)(), once_flag& flag)
{
#if defined(BOOST_HAS_WINTHREADS)
once_flag tmp = flag;
// Memory barrier would be needed here to prevent race conditions on some platforms with
// partial ordering.
if (!tmp)
if (compare_exchange(&flag, 1, 1) == 0)
{
#if defined(BOOST_NO_STRINGSTREAM)
std::ostrstream strm;
@@ -101,16 +130,10 @@ void call_once(void (*func)(), once_flag& flag)
res = WaitForSingleObject(mutex, INFINITE);
assert(res == WAIT_OBJECT_0);
tmp = flag;
if (!tmp)
if (compare_exchange(&flag, 1, 1) == 0)
{
func();
tmp = true;
// Memory barrier would be needed here to prevent race conditions on some platforms
// with partial ordering.
flag = tmp;
InterlockedExchange(&flag, 1);
}
res = ReleaseMutex(mutex);

View File

@@ -195,23 +195,35 @@ bool recursive_timed_mutex::do_trylock()
bool recursive_timed_mutex::do_timedlock(const xtime& xt)
{
int milliseconds;
to_duration(xt, milliseconds);
unsigned int res = 0;
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), milliseconds);
assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
if (res == WAIT_OBJECT_0)
for (;;)
{
if (++m_count > 1)
int milliseconds;
to_duration(xt, milliseconds);
unsigned int res = 0;
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), milliseconds);
assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
if (res == WAIT_TIMEOUT)
{
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
assert(res);
xtime cur;
xtime_get(&cur, TIME_UTC);
if (xtime_cmp(xt, cur) > 0)
continue;
}
return true;
if (res == WAIT_OBJECT_0)
{
if (++m_count > 1)
{
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
assert(res);
}
return true;
}
return false;
}
return false;
}
void recursive_timed_mutex::do_unlock()

599
src/rw_mutex.cpp Normal file
View File

@@ -0,0 +1,599 @@
// rw_mutex.cpp
//
// Implementaion for Reader/Writer lock
//
// Notes:
//
// This implementation is based on ACE's rw_lock_t implementation, with the added
// functionality of supporting different Scheduling Policies.
//
// The underlying implementation is shared by rw_mutex, try_rw_mutex, and
// timed_rw_mutex.
//
// The basic implementation strategy involves a mutex, m_prot which is locked during
// ANY rw_mutex operation, locking or unlocking. m_prot protects the invariants
// of the implementation.
//
// The variable m_state takes the following values:
// -1 - Exclusive locked
// 0 - Unlocked
// 1 -> INT_MAX, shared locked, m_state == # of shared locks.
//
// Should a thread need to block for a shared or exclusive lock, two
// member condition variables, m_waiting_readers and m_waiting_writers
// are available for waiting. m_prot is used as the controlling mutex
// when waiting in these cases.
//
// The number of waiting readers and writers are tracked via member variables
// m_num_waiting_readers and m_num_waiting_writers.
//
//
// This particular implementation cannot prevent self-deadlock w/o adding some means
// of identifying the thread(s) holding locks.
// A recursive_try_mutex used "under the hood" could be used to detect and prevent
// exclusive->exclusive self-deadlock since only the same thread would be able to
// obtain a second lock on this recursive mutex....
/*
// for example, if rw_mutex_impl has an additional member:
//
// struct rw_mutex_impl {
// // ...
// recursive_try_mutex m_self_detect;
// }
//
template<typename Mutex>
void
rw_mutex_impl<Mutex>::
do_wrlock()
{
// Lock our exclusive access. This protects internal state
Mutex::scoped_lock l(m_prot);
if(m_state == -1)
{
recursive_try_mutex sl(m_self_detect);
if(sl.locked())
{
// It is us that already held the lock!
// Do something to hold the m_self_detect lock
// and bail out
}
else
{
// It is someone else. fall back to normal waiting.
}
}
// Wait until no exclusive lock is held.
//
// Note: Scheduling priorities are enforced in the unlock()
// call. unlock will wake the proper thread.
while(m_state != 0)
{
m_num_waiting_writers++;
m_waiting_writers.wait(l);
m_num_waiting_writers--;
}
m_state = -1;
}
// Unfortunately, the above doesn't work to detect shared->exclusive deadlock where
// a shared lock holder tries for an exclusive lock.
*/
#include <boost/thread/rw_mutex.hpp>
#include <cassert>
namespace boost {
namespace detail { namespace thread {
template<typename Mutex>
void
rw_mutex_impl<Mutex>::
do_rdlock()
{
// Lock our exclusive access. This protects internal state
typename Mutex::scoped_lock l(m_prot);
// Wait until no exclusive lock is held.
//
// Note: Scheduling priorities are enforced in the unlock()
// call. unlock will wake the proper thread.
while(m_state < 0)
{
m_num_waiting_readers++;
m_waiting_readers.wait(l);
m_num_waiting_readers--;
}
// Increase the reader count
m_state++;
}
template<typename Mutex>
void
rw_mutex_impl<Mutex>::
do_wrlock()
{
// Lock our exclusive access. This protects internal state
typename Mutex::scoped_lock l(m_prot);
// Wait until no exclusive lock is held.
//
// Note: Scheduling priorities are enforced in the unlock()
// call. unlock will wake the proper thread.
while(m_state != 0)
{
m_num_waiting_writers++;
m_waiting_writers.wait(l);
m_num_waiting_writers--;
}
m_state = -1;
}
template<typename Mutex>
bool
rw_mutex_impl<Mutex>::
do_try_rdlock()
{
bool ret;
// Lock our exclusive access. This protects internal state
typename Mutex::scoped_lock l(m_prot);
if(!l.locked())
return false;
if(m_state == -1)
{
// We are already locked exclusively. A try_rdlock always returns
// immediately in this case
ret = false;
}
else if(m_num_waiting_writers > 0)
{
// There are also waiting writers. Use scheduling policy.
if(m_sp == sp_reader_priority)
{
m_state++;
ret = true;
}
else if(m_sp == sp_writer_priority)
{
// A writer is waiting - don't grant this try lock, and
// return immediately (don't increase waiting_readers count)
ret = false;
}
else
{
// For alternating scheduling priority,
// I don't think that try_ locks should step in front of others
// who have already indicated that they are waiting.
// It seems that this could "game" the system and defeat
// the alternating mechanism.
ret = false;
}
}
else
{
// No waiting writers. Grant (additonal) read lock regardless of
// scheduling policy.
m_state++;
ret = true;
}
return ret;
}
/*
*
* try_promote_rdlock - not yet in production....
*
*
*
template<typename Mutex>
bool
rw_mutex_impl<Mutex>::
do_try_promote_rdlock()
{
RWMutexImpl::scoped_lock l(m_prot);
if(m_state == -1)
{
// promoting a write-locked to a read lock is a serious error.
throw lock_error();
}
else if(m_num_waiting_promotion > 0)
{
// Someone else is already trying to upgrade. Avoid deadlock by
// returning false.
return false;
}
else
{
while(m_state > 1) // While there are other readers
{
m_num_waiting_writers++;
m_num_waiting_promotion = 1;
m_waiting_promotion.wait(l);
m_num_waiting_promotion = 0;
m_num_waiting_writers--;
}
// We got the exclusive lock!
m_state == -1;
}
}
*/
template<typename Mutex>
bool
rw_mutex_impl<Mutex>::
do_try_wrlock()
{
bool ret;
typename Mutex::scoped_lock l(m_prot);
if(!l.locked())
return false;
if(m_state != 0)
{
// We are already busy and locked.
// Scheduling priority doesn't matter here.
ret = false;
}
else
{
m_state = -1;
ret = true;
}
return ret;
}
template<typename Mutex>
bool
rw_mutex_impl<Mutex>::
do_timed_rdlock(const boost::xtime &xt)
{
// Lock our exclusive access. This protects internal state
typename Mutex::scoped_timed_lock l(m_prot,xt);
if(!l.locked())
return false;
// Wait until no exclusive lock is held.
//
// Note: Scheduling priorities are enforced in the unlock()
// call. unlock will wake the proper thread.
while(m_state < 0)
{
m_num_waiting_readers++;
if(!m_waiting_readers.timed_wait(l,xt))
{
m_num_waiting_readers--;
return false;
}
m_num_waiting_readers--;
}
// Increase the reader count
m_state++;
return true;
}
template<typename Mutex>
bool
rw_mutex_impl<Mutex>::
do_timed_wrlock(const boost::xtime &xt)
{
typename Mutex::scoped_timed_lock l(m_prot,xt);
if(!l.locked())
return false;
// Wait until no exclusive lock is held.
//
// Note: Scheduling priorities are enforced in the unlock()
// call. unlock will wake the proper thread.
while(m_state != 0)
{
m_num_waiting_writers++;
if(!m_waiting_writers.timed_wait(l,xt))
{
m_num_waiting_writers--;
return false;
}
m_num_waiting_writers--;
}
m_state = -1;
return true;
}
template<typename Mutex>
void
rw_mutex_impl<Mutex>::
do_rdunlock()
{
// Protect internal state.
typename Mutex::scoped_lock l(m_prot);
if(m_state > 0) // Release a reader.
m_state--;
else
throw lock_error(); // Trying to release a writer???
// If we have someone waiting to be promoted....
if(m_num_waiting_promotion == 1 && m_state == 1)
{
m_waiting_promotion.notify_one();
}
else if(m_state == 0)
{
do_wakeups();
}
}
template<typename Mutex>
void
rw_mutex_impl<Mutex>::
do_wakeups()
{
if( m_num_waiting_writers > 0 &&
m_num_waiting_readers > 0)
{
// We have both types waiting, and -either- could proceed.
// Choose which to release based on scheduling policy.
if(m_sp == sp_reader_priority)
{
m_waiting_readers.notify_all();
}
else if(m_sp == sp_writer_priority)
{
m_waiting_writers.notify_one();
}
else // one of the alternating mechanisms
{
if(m_readers_next == 1)
{
m_readers_next = 0;
if(m_sp == sp_alternating_many_reads)
{
m_waiting_readers.notify_all();
}
else
{
// sp_alternating_single_reads
m_waiting_readers.notify_one();
}
}
else
{
m_waiting_writers.notify_one();
m_readers_next = 1;
}
}
}
else if(m_num_waiting_writers > 0)
{
// Only writers - scheduling doesn't matter
m_waiting_writers.notify_one();
}
else if(m_num_waiting_readers > 0)
{
// Only readers - scheduling doesn't matter
m_waiting_readers.notify_all();
}
}
template<typename Mutex>
void
rw_mutex_impl<Mutex>::
do_wrunlock()
{
// Protect internal state.
typename Mutex::scoped_lock l(m_prot);
if(m_state == -1)
m_state = 0;
else
throw lock_error();
// After a writer is unlocked, we are always back in the unlocked state.
//
do_wakeups();
}
} // namespace thread
} // namespace detail
void
rw_mutex::
do_rdlock()
{
m_impl.do_rdlock();
}
void
rw_mutex::
do_wrlock()
{
m_impl.do_wrlock();
}
void
rw_mutex::
do_rdunlock()
{
m_impl.do_rdunlock();
}
void
rw_mutex::
do_wrunlock()
{
m_impl.do_wrunlock();
}
void
try_rw_mutex::
do_rdlock()
{
m_impl.do_rdlock();
}
void
try_rw_mutex::
do_wrlock()
{
m_impl.do_wrlock();
}
void
try_rw_mutex::
do_wrunlock()
{
m_impl.do_wrunlock();
}
void
try_rw_mutex::
do_rdunlock()
{
m_impl.do_rdunlock();
}
bool
try_rw_mutex::
do_try_rdlock()
{
return m_impl.do_try_rdlock();
}
bool
try_rw_mutex::
do_try_wrlock()
{
return m_impl.do_try_wrlock();
}
void
timed_rw_mutex::
do_rdlock()
{
m_impl.do_rdlock();
}
void
timed_rw_mutex::
do_wrlock()
{
m_impl.do_wrlock();
}
void
timed_rw_mutex::
do_rdunlock()
{
m_impl.do_rdunlock();
}
void
timed_rw_mutex::
do_wrunlock()
{
m_impl.do_wrunlock();
}
bool
timed_rw_mutex::
do_try_rdlock()
{
return m_impl.do_try_rdlock();
}
bool
timed_rw_mutex::
do_try_wrlock()
{
return m_impl.do_try_wrlock();
}
bool
timed_rw_mutex::
do_timed_rdlock(const xtime &xt)
{
return m_impl.do_timed_rdlock(xt);
}
bool
timed_rw_mutex::
do_timed_wrlock(const xtime &xt)
{
return m_impl.do_timed_wrlock(xt);
}
} // namespace boost

262
src/shared_memory.cpp Normal file
View File

@@ -0,0 +1,262 @@
// Copyright (C) 2002
// William E. Kempf, David Moore
//
// 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/shared_memory.hpp>
#if defined(BOOST_HAS_WINTHREADS)
#include <windows.h>
// Next line should really be BOOST_HAS_POSIX_xxx
#elif defined(BOOST_HAS_PTHREADS)
#include <sys/shm.h>
#include <sys/mman.h>
// Need to busy-wait on POSIX
#include <boost/thread/thread.hpp>
#include <boost/thread/xtime.hpp>
#endif
namespace
{
const int HEADER_ALIGN=16;
struct hdr
{
size_t len;
unsigned int count;
};
void fillzero(void *ptr, size_t len)
{
memset(ptr,0,len);
}
void noinit(void *,size_t)
{
}
};
namespace boost
{
shared_memory::
shared_memory(const char *name,size_t len) : m_ptr(NULL),m_mem_obj(0),m_h_event(NULL),
m_len(len),m_initfunc(&noinit)
{
create(name,len);
}
// Obtain a shared memory block and initialize it with initfunc
shared_memory::
shared_memory(const char *name,size_t len,const boost::function2<void,void *,size_t> &initfunc) :
m_ptr(NULL),m_mem_obj(0),m_h_event(NULL),m_len(len),m_initfunc(initfunc)
{
create(name,len);
}
shared_memory::
~shared_memory()
{
if(m_ptr)
{
m_ptr = ((char *) m_ptr - HEADER_ALIGN);
hdr *p_hdr = (hdr *)m_ptr;
if(p_hdr)
{
p_hdr->count--;
}
#if defined(BOOST_HAS_WINTHREADS)
UnmapViewOfFile(m_ptr);
if(m_mem_obj)
{
CloseHandle(reinterpret_cast<HANDLE>(m_mem_obj));
}
if(m_h_event)
{
CloseHandle(reinterpret_cast<HANDLE>(m_h_event));
}
#elif defined (BOOST_HAS_PTHREADS)
if(p_hdr->count == 0)
{
shm_unlink(m_name);
}
munmap(m_ptr,m_len);
#endif
}
}
void
shared_memory::
create(const char *name,size_t len)
{
#if defined(BOOST_HAS_WINTHREADS)
HANDLE h_map = NULL;
HANDLE h_event = NULL;
DWORD ret;
bool b_creator = false;
std::string obj_name = "_EVT_";
obj_name += name;
h_event = CreateEvent(NULL,TRUE,FALSE,obj_name.c_str());
if(h_event == NULL)
{
throw boost::thread_resource_error();
}
b_creator = (GetLastError() != ERROR_ALREADY_EXISTS);
h_map = CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE,0,len+HEADER_ALIGN,name);
if(h_map)
{
m_ptr = (char *)MapViewOfFile(h_map,FILE_MAP_WRITE,0,0,0);
if(m_ptr)
{
// Get a pointer to our header, and move our real ptr past this.
hdr *p_hdr = (hdr *)m_ptr;
m_ptr = ((char *)m_ptr + HEADER_ALIGN);
if(b_creator)
{
// Call the initialization function for the user area.
m_initfunc(m_ptr,len);
p_hdr->len = len;
p_hdr->count = 1;
SetEvent(h_event);
}
else
{
ret = WaitForSingleObject(h_event,INFINITE);
if(ret != WAIT_OBJECT_0)
{
CloseHandle(h_event);
CloseHandle(h_map);
throw boost::thread_resource_error();
}
// We've got a previously constructed object.
(p_hdr->count)++;
}
}
else
{
CloseHandle(h_event);
throw boost::thread_resource_error();
}
}
m_mem_obj = reinterpret_cast<int>(h_map);
m_h_event = reinterpret_cast<void *>(h_event);
#elif defined (BOOST_HAS_PTHREADS)
int fd_smo; // descriptor to shared memory object
bool b_creator = true;
fd_smo = shm_open(name,O_RDWR|O_CREAT|O_EXCL,SHM_MODE);
if(fd_smo == -1)
{
if(errno == EEXIST)
{
// We lost the race. We should just re-open with shared access
// below.
fd_smo = shm_open(name,O_RDWR,SHM_MODE);
b_creator = false
}
else
{
throw boost::thread_resource_error();
}
}
else
{
// We're the creator. Use ftrunctate to set the size.
b_creator = true;
//
// Add error check on ftruncate.
ftruncate(fd_smo,len+HEADER_ALIGN);
}
m_ptr = (char *)mmap(NULL,len + HEADER_ALIGN,
PROT_READ|PROT_WRITE,
MAP_SHARED,
fd_smo,
0);
if(m_ptr)
{
// Get a pointer to our header, and move our real ptr past this.
hdr *p_hdr = (hdr *)ptr;
m_ptr = ((char *)m_ptr + HEADER_ALIGN);
if(b_creator)
{
// Call the initialization function for the user area.
//flock(fd_smo);
initfunc(ptr,len);
p_hdr->len = len;
p_hdr->count = 1;
//funlock(fd_sm0);
}
else
{
// Need an event here. For now, busy wait.
while(p_hdr->len == 0)
{
//flock(fd_smo);
//funlock(fd_smo);
boost::xtime xt;
boost::xtime_get(&xt,boost::TIME_UTC);
xt.sec++;
boost::thread::sleep(xt);
}
// We've got a previously constructed object.
(p_hdr->count)++;
}
}
close(fd_smo);
mem_obj = NULL; //reinterpret_cast<int>(h_map);
event_obj = NULL; //reinterpret_cast<void *>(h_event);
#endif
}
} // namespace boost

View File

@@ -12,44 +12,195 @@
#include <boost/thread/thread.hpp>
#include <boost/thread/xtime.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/tss.hpp>
#include <new>
#include <memory>
#include <cassert>
#if defined(BOOST_HAS_WINTHREADS)
# include <windows.h>
# include <process.h>
#elif defined(BOOST_HAS_MPTASKS)
# include <DriverServices.h>
# include "init.hpp"
# include "safe.hpp"
# include <boost/thread/tss.hpp>
# include <DriverServices.h>
# include "init.hpp"
# include "safe.hpp"
#endif
#include "timeconv.inl"
namespace {
class thread_param
class thread_data
{
public:
thread_param(const boost::function0<void>& threadfunc) : m_threadfunc(threadfunc), m_started(false) { }
void wait()
{
boost::mutex::scoped_lock scoped_lock(m_mutex);
while (!m_started)
m_condition.wait(scoped_lock);
}
void started()
{
boost::mutex::scoped_lock scoped_lock(m_mutex);
m_started = true;
m_condition.notify_one();
}
enum
{
creating,
running,
joining,
joined
};
thread_data(const boost::function0<void>& threadfunc);
thread_data();
~thread_data();
void addref();
bool release();
boost::thread::category_type category();
void join();
void cancel();
void test_cancel();
void run();
private:
boost::mutex m_mutex;
boost::condition m_condition;
const boost::function0<void>& m_threadfunc;
bool m_started;
boost::condition m_cond;
boost::function0<void> m_threadfunc;
unsigned int m_refcount;
int m_state;
#if defined(BOOST_HAS_WINTHREADS)
HANDLE m_thread;
#elif defined(BOOST_HAS_PTHREADS)
pthread_t m_thread;
#elif defined(BOOST_HAS_MPTASKS)
MPQueueID m_pJoinQueueID;
MPTaskID m_pTaskID;
#endif
boost::thread::category_type m_category;
bool m_canceled;
};
void release_tss_data(void* pdata)
{
thread_data* tdata = (thread_data*)pdata;
assert(tdata);
if (tdata->release())
delete tdata;
}
boost::thread_specific_ptr<thread_data> tss_thread_data(&release_tss_data);
thread_data::thread_data(const boost::function0<void>& threadfunc)
: m_threadfunc(threadfunc), m_refcount(2), m_state(creating), m_category(boost::thread::boost), m_canceled(false)
{
}
thread_data::thread_data()
: m_refcount(2), m_state(running), m_category(boost::thread::native), m_canceled(false)
{
#if defined(BOOST_HAS_WINTHREADS)
DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(),
&m_thread, 0, FALSE, DUPLICATE_SAME_ACCESS);
#elif defined(BOOST_HAS_PTHREADS)
m_thread = pthread_self();
#endif
}
thread_data::~thread_data()
{
if (m_category == boost::thread::native || m_state != joined)
{
int res = 0;
#if defined(BOOST_HAS_WINTHREADS)
res = CloseHandle(m_thread);
assert(res);
#elif defined(BOOST_HAS_PTHREADS)
res = pthread_detach(m_thread);
assert(res == 0);
#elif defined(BOOST_HAS_MPTASKS)
OSStatus lStatus = threads::mac::detail::safe_wait_on_queue(m_pJoinQueueID, NULL, NULL, NULL, kDurationForever);
assert(lStatus == noErr);
#endif
}
}
void thread_data::addref()
{
boost::mutex::scoped_lock lock(m_mutex);
++m_refcount;
}
bool thread_data::release()
{
boost::mutex::scoped_lock lock(m_mutex);
return (--m_refcount == 0);
}
boost::thread::category_type thread_data::category()
{
boost::mutex::scoped_lock lock(m_mutex);
return m_category;
}
void thread_data::join()
{
boost::mutex::scoped_lock lock(m_mutex);
while (m_state == creating || m_state == joining)
m_cond.wait(lock);
if (m_state != joined)
{
m_state = joining;
m_cond.notify_all();
lock.unlock();
int res = 0;
#if defined(BOOST_HAS_WINTHREADS)
res = WaitForSingleObject(m_thread, INFINITE);
assert(res == WAIT_OBJECT_0);
res = CloseHandle(m_thread);
assert(res);
#elif defined(BOOST_HAS_PTHREADS)
res = pthread_join(m_thread, 0);
assert(res == 0);
#elif defined(BOOST_HAS_MPTASKS)
OSStatus lStatus = threads::mac::detail::safe_wait_on_queue(m_pJoinQueueID, NULL, NULL, NULL, kDurationForever);
assert(lStatus == noErr);
#endif
lock.lock();
m_state = joined;
}
}
void thread_data::cancel()
{
boost::mutex::scoped_lock lock(m_mutex);
m_canceled = true;
}
void thread_data::test_cancel()
{
boost::mutex::scoped_lock lock(m_mutex);
if (m_canceled)
throw boost::thread_cancel();
}
void thread_data::run()
{
{
boost::mutex::scoped_lock lock(m_mutex);
#if defined(BOOST_HAS_WINTHREADS)
DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(),
&m_thread, 0, FALSE, DUPLICATE_SAME_ACCESS);
#elif defined(BOOST_HAS_PTHREADS)
m_thread = pthread_self();
#endif
m_state = thread_data::running;
m_cond.notify_all();
}
m_threadfunc();
}
struct thread_equals
{
thread_equals(boost::thread& thrd) : m_thrd(thrd) { }
bool operator()(boost::thread* thrd) { return *thrd == m_thrd; }
boost::thread& m_thrd;
};
} // unnamed namespace
@@ -65,13 +216,16 @@ static OSStatus thread_proxy(void* param)
{
try
{
thread_param* p = static_cast<thread_param*>(param);
boost::function0<void> threadfunc = p->m_threadfunc;
p->started();
threadfunc();
thread_data* tdata = static_cast<thread_data*>(param);
tss_thread_data.reset(tdata);
tdata->run();
}
catch (boost::thread_cancel)
{
}
catch (...)
{
terminate();
}
#if defined(BOOST_HAS_MPTASKS)
::boost::detail::thread_cleanup();
@@ -84,32 +238,42 @@ static OSStatus thread_proxy(void* param)
namespace boost {
thread::thread()
: m_joinable(false)
: m_handle(0)
{
#if defined(BOOST_HAS_WINTHREADS)
m_thread = reinterpret_cast<void*>(GetCurrentThread());
m_id = GetCurrentThreadId();
#elif defined(BOOST_HAS_PTHREADS)
m_thread = pthread_self();
#elif defined(BOOST_HAS_MPTASKS)
#if defined(BOOST_HAS_MPTASKS)
threads::mac::detail::thread_init();
threads::mac::detail::create_singletons();
m_pTaskID = MPCurrentTaskID();
m_pJoinQueueID = kInvalidID;
#endif
thread_data* tdata = tss_thread_data.get();
if (tdata == 0)
{
tdata = new(std::nothrow) thread_data;
if (!tdata)
throw thread_resource_error();
tss_thread_data.reset(tdata);
}
else
tdata->addref();
m_handle = tdata;
}
thread::thread(const function0<void>& threadfunc)
: m_joinable(true)
: m_handle(0)
{
thread_param param(threadfunc);
std::auto_ptr<thread_data> param(new(std::nothrow) thread_data(threadfunc));
if (param.get() == 0)
throw thread_resource_error();
#if defined(BOOST_HAS_WINTHREADS)
m_thread = reinterpret_cast<void*>(_beginthreadex(0, 0, &thread_proxy, &param, 0, &m_id));
if (!m_thread)
unsigned int id;
HANDLE h = (HANDLE)_beginthreadex(0, 0, &thread_proxy, param.get(), 0, &id);
if (!h)
throw thread_resource_error();
#elif defined(BOOST_HAS_PTHREADS)
int res = 0;
res = pthread_create(&m_thread, 0, &thread_proxy, &param);
pthread_t t;
res = pthread_create(&t, 0, &thread_proxy, param.get());
if (res != 0)
throw thread_resource_error();
#elif defined(BOOST_HAS_MPTASKS)
@@ -123,7 +287,7 @@ thread::thread(const function0<void>& threadfunc)
lStatus = MPCreateQueue(&m_pJoinQueueID);
if(lStatus != noErr) throw thread_resource_error();
lStatus = MPCreateTask(&thread_proxy, &param, 0UL, m_pJoinQueueID, NULL, NULL,
lStatus = MPCreateTask(&thread_proxy, param.get(), 0UL, m_pJoinQueueID, NULL, NULL,
0UL, &m_pTaskID);
if(lStatus != noErr)
{
@@ -132,36 +296,19 @@ thread::thread(const function0<void>& threadfunc)
throw thread_resource_error();
}
#endif
param.wait();
m_handle = param.release();
}
thread::~thread()
{
if (m_joinable)
{
#if defined(BOOST_HAS_WINTHREADS)
int res = 0;
res = CloseHandle(reinterpret_cast<HANDLE>(m_thread));
assert(res);
#elif defined(BOOST_HAS_PTHREADS)
pthread_detach(m_thread);
#elif defined(BOOST_HAS_MPTASKS)
assert(m_pJoinQueueID != kInvalidID);
OSStatus lStatus = MPDeleteQueue(m_pJoinQueueID);
assert(lStatus == noErr);
#endif
}
// thread_data* tdata = static_cast<thread_data*>(m_handle);
// if (tdata && tdata->release())
// delete tdata;
}
bool thread::operator==(const thread& other) const
{
#if defined(BOOST_HAS_WINTHREADS)
return other.m_id == m_id;
#elif defined(BOOST_HAS_PTHREADS)
return pthread_equal(m_thread, other.m_thread) != 0;
#elif defined(BOOST_HAS_MPTASKS)
return other.m_pTaskID == m_pTaskID;
#endif
return m_handle == other.m_handle;
}
bool thread::operator!=(const thread& other) const
@@ -169,59 +316,71 @@ bool thread::operator!=(const thread& other) const
return !operator==(other);
}
thread::category_type thread::category() const
{
thread_data* tdata = static_cast<thread_data*>(m_handle);
return tdata->category();
}
void thread::join()
{
int res = 0;
#if defined(BOOST_HAS_WINTHREADS)
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_thread), INFINITE);
assert(res == WAIT_OBJECT_0);
res = CloseHandle(reinterpret_cast<HANDLE>(m_thread));
assert(res);
#elif defined(BOOST_HAS_PTHREADS)
res = pthread_join(m_thread, 0);
assert(res == 0);
#elif defined(BOOST_HAS_MPTASKS)
OSStatus lStatus = threads::mac::detail::safe_wait_on_queue(m_pJoinQueueID, NULL, NULL, NULL, kDurationForever);
assert(lStatus == noErr);
#endif
// This isn't a race condition since any race that could occur would
// have us in undefined behavior territory any way.
m_joinable = false;
thread_data* tdata = static_cast<thread_data*>(m_handle);
tdata->join();
}
void thread::cancel()
{
thread_data* tdata = static_cast<thread_data*>(m_handle);
tdata->cancel();
}
void thread::test_cancel()
{
thread self;
thread_data* tdata = static_cast<thread_data*>(self.m_handle);
tdata->test_cancel();
}
void thread::sleep(const xtime& xt)
{
for (int foo=0; foo < 5; ++foo)
{
#if defined(BOOST_HAS_WINTHREADS)
int milliseconds;
to_duration(xt, milliseconds);
Sleep(milliseconds);
int milliseconds;
to_duration(xt, milliseconds);
Sleep(milliseconds);
#elif defined(BOOST_HAS_PTHREADS)
# if defined(BOOST_HAS_PTHREAD_DELAY_NP)
timespec ts;
to_timespec_duration(xt, ts);
int res = 0;
res = pthread_delay_np(&ts);
assert(res == 0);
timespec ts;
to_timespec_duration(xt, ts);
int res = 0;
res = pthread_delay_np(&ts);
assert(res == 0);
# elif defined(BOOST_HAS_NANOSLEEP)
timespec ts;
to_timespec_duration(xt, ts);
timespec ts;
to_timespec_duration(xt, ts);
// nanosleep takes a timespec that is an offset, not
// an absolute time.
nanosleep(&ts, 0);
// nanosleep takes a timespec that is an offset, not
// an absolute time.
nanosleep(&ts, 0);
# else
mutex mx;
mutex::scoped_lock lock(mx);
condition cond;
cond.timed_wait(lock, xt);
mutex mx;
mutex::scoped_lock lock(mx);
condition cond;
cond.timed_wait(lock, xt);
# endif
#elif defined(BOOST_HAS_MPTASKS)
int microseconds;
to_microduration(xt, microseconds);
Duration lMicroseconds(kDurationMicrosecond * microseconds);
AbsoluteTime sWakeTime(DurationToAbsolute(lMicroseconds));
threads::mac::detail::safe_delay_until(&sWakeTime);
int microseconds;
to_microduration(xt, microseconds);
Duration lMicroseconds(kDurationMicrosecond * microseconds);
AbsoluteTime sWakeTime(DurationToAbsolute(lMicroseconds));
threads::mac::detail::safe_delay_until(&sWakeTime);
#endif
xtime cur;
xtime_get(&cur, TIME_UTC);
if (xtime_cmp(xt, cur) <= 0)
return;
}
}
void thread::yield()
@@ -288,11 +447,25 @@ void thread_group::remove_thread(thread* thrd)
// For now we'll simply ignore requests to remove a thread object that's not in the group.
// Should we consider this an error and either throw or return an error value?
std::list<thread*>::iterator it = std::find(m_threads.begin(), m_threads.end(), thrd);
assert(it != m_threads.end());
if (it != m_threads.end())
m_threads.erase(it);
}
thread* thread_group::find(thread& thrd)
{
mutex::scoped_lock scoped_lock(m_mutex);
// For now we'll simply ignore requests to remove a thread object that's not in the group.
// Should we consider this an error and either throw or return an error value?
std::list<thread*>::iterator it = std::find_if(m_threads.begin(), m_threads.end(), thread_equals(thrd));
if (it != m_threads.end())
return *it;
return 0;
}
void thread_group::join_all()
{
mutex::scoped_lock scoped_lock(m_mutex);

361
src/thread_pool.cpp Normal file
View File

@@ -0,0 +1,361 @@
// Copyright (C) 2002 David Moore
//
// Based on Boost.Threads
// Copyright (C) 2001
// William E. Kempf
//
// Derived loosely from work queue manager in "Programming POSIX Threads"
// by David Butenhof.
//
// 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_pool.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/xtime.hpp>
#include <boost/bind.hpp>
#include <list>
#include <queue>
#include <stdexcept>
#include <cassert>
namespace boost
{
class thread_pool::impl
{
public:
impl(int max_threads, int min_threads, int timeout_secs, int timeout_nsecs);
~impl();
void add(const boost::function0<void> &job);
void join();
void cancel();
void detach();
void worker_harness();
private:
typedef enum
{
RUNNING,
CANCELLING,
JOINING,
JOINED,
DETACHED
} thread_pool_state;
typedef std::queue<boost::function0<void> > job_q;
condition m_more_work;
condition m_done;
mutex m_prot;
job_q m_jobs;
thread_group m_workers;
thread_pool_state m_state;
int m_max_threads; // Max threads allowed
int m_min_threads;
int m_thread_count; // Current number of threads
int m_idle_count; // Number of idle threads
int m_timeout_secs; // How long to keep idle threads
int m_timeout_nsecs;
};
thread_pool::impl::impl(int max_threads, int min_threads, int timeout_secs, int timeout_nsecs)
: m_state(RUNNING), m_max_threads(max_threads), m_min_threads(min_threads),
m_thread_count(0), m_idle_count(0), m_timeout_secs(timeout_secs), m_timeout_nsecs(timeout_nsecs)
{
// Immediately launch some worker threads.
//
// Not an exception safe implementation, yet.
while (min_threads-- > 0)
{
m_workers.create_thread(bind(&thread_pool::impl::worker_harness, this));
m_thread_count++;
}
}
thread_pool::impl::~impl()
{
// Join in the destructor, unless they have already
// joined or detached.
mutex::scoped_lock lock(m_prot);
if (m_state == RUNNING)
{
lock.unlock();
join();
}
}
void thread_pool::impl::add(const boost::function0<void> &job)
{
mutex::scoped_lock lock(m_prot);
// Note - can never reach this point if m_state == CANCELLED
// because the m_prot is held during the entire cancel operation.
assert(m_state == RUNNING);
m_jobs.push(job);
if (m_idle_count > 0)
m_more_work.notify_one();
else if (m_thread_count < m_max_threads)
{
// No idle threads, and we're below our limit. Spawn a new
// worker.
// What we really need is thread::detach(), or "create suspended"
m_workers.create_thread(bind(&thread_pool::impl::worker_harness, this));
m_thread_count++;
}
}
void thread_pool::impl::join()
{
mutex::scoped_lock lock(m_prot);
assert(m_state == RUNNING);
if (m_thread_count > 0)
{
m_state = JOINING;
// if any threads are idling, wake them.
if (m_idle_count > 0)
m_more_work.notify_all();
// Track the shutdown progress of the threads.
while (m_thread_count > 0)
m_done.wait(lock);
}
m_workers.join_all();
m_state = JOINED;
}
// This is a "weak" form of cancel which empties out the job queue and takes
// the thread count down to zero.
//
// Upon receiving more work, the thread count would grow back up to min_threads.
//
// Cancel will be much stronger once full thread cancellation is in place!
void thread_pool::impl::cancel()
{
mutex::scoped_lock lock(m_prot);
assert(m_state == RUNNING);
if (m_thread_count > 0)
{
m_state = CANCELLING;
// Cancelling kills any unexecuted jobs.
while (!m_jobs.empty())
m_jobs.pop();
/* If we had cancel, this would be something like....
m_workers.cancel_all();
while(m_cancel_count > 0)
m_all_cancelled.wait(lock);
*/
}
m_state = RUNNING; // Go back to accepting work.
}
void thread_pool::impl::detach()
{
mutex::scoped_lock lock(m_prot);
if (m_state == RUNNING)
{
m_min_threads = 0;
m_state = DETACHED;
}
else
{
// detach during/after a join has no effect - the join will
// complete.
}
}
void thread_pool::impl::worker_harness()
{
boost::thread me;
xtime timeout;
int timedout;
mutex::scoped_lock lock(m_prot);
for (;;)
{
timedout = 0;
xtime_get(&timeout, boost::TIME_UTC);
timeout.sec += m_timeout_secs;
timeout.nsec += m_timeout_nsecs;
while (m_jobs.empty() && (m_state == RUNNING))
{
m_idle_count++;
bool status = m_more_work.timed_wait(lock, timeout);
m_idle_count--;
if (!status)
{
timedout = 1;
return;
}
}
if (!m_jobs.empty() && m_state != CANCELLING)
{
boost::function0<void> jobfunc = m_jobs.front();
m_jobs.pop();
lock.unlock();
jobfunc();
lock.lock();
}
else if (m_jobs.empty() && m_state == JOINING)
{
m_thread_count--;
// If we are the last worker exiting, let everyone know about it!
if (m_thread_count == 0)
m_done.notify_all();
return;
}
else if (m_jobs.empty() && m_state == DETACHED)
{
m_thread_count--;
// If we are the last worker exiting, let everyone know about it!
if (m_thread_count == 0)
{
lock.unlock();
delete this;
}
return;
}
/*
* If there's no more work, and we wait for as long as
* we're allowed, then terminate this server thread.
*/
if (m_jobs.empty() && timedout)
{
if (m_thread_count > m_min_threads)
{
m_thread_count--;
if (m_state == DETACHED &&
m_thread_count == 0)
{
lock.unlock();
delete this;
return;
}
// We aren't in a JOINING or CANCELLING state, so trim
// down our resource usage and clean ourselves up.
thread* thrd = m_workers.find(me);
m_workers.remove_thread(thrd);
delete thrd;
return;
}
}
}
}
thread_pool::thread_pool(int max_threads, int min_threads, int timeout_secs, int timeout_nsecs)
: m_pimpl(new impl(max_threads, min_threads, timeout_secs, timeout_nsecs))
{
}
thread_pool::~thread_pool()
{
if (m_pimpl != NULL)
delete m_pimpl;
}
void thread_pool::add(const boost::function0<void> &job)
{
assert(m_pimpl);
m_pimpl->add(job);
}
void thread_pool::join()
{
assert(m_pimpl);
m_pimpl->join();
}
void thread_pool::cancel()
{
assert(m_pimpl);
m_pimpl->cancel();
}
void thread_pool::detach()
{
assert(m_pimpl);
// Tell our implementation it is running detached.
m_pimpl->detach();
m_pimpl = NULL;
}
/*thread_grp::thread_grp()
{
}
thread_grp::~thread_grp()
{
for (std::list<boost::thread*>::iterator it = m_threads.begin(); it != m_threads.end(); ++it)
delete (*it);
}
boost::thread* thread_grp::create_thread(const function0<void>& threadfunc)
{
std::auto_ptr<boost::thread> thrd(new boost::thread(threadfunc));
m_threads.push_back(thrd.get());
return thrd.release();
}
// Delete the thread in the group with identity equal to thrd
void thread_grp::delete_thread_equal_to(boost::thread *thrd)
{
std::list<boost::thread*>::iterator it = m_threads.begin();
for ( ;it != m_threads.end(); ++it)
{
if (**it == *thrd)
break;
}
assert(it != m_threads.end());
if (it != m_threads.end())
{
boost::thread *pthread = *it;
m_threads.erase(it);
delete pthread;
}
}
void thread_grp::join_all()
{
for (std::list<boost::thread*>::iterator it =
m_threads.begin(); it != m_threads.end(); ++it)
{
(*it)->join();
}
}*/
} // namespace boost

View File

@@ -19,13 +19,10 @@
typedef void (__cdecl * handler)(void);
typedef std::list<handler> exit_handlers;
typedef std::set<exit_handlers*> registered_handlers;
namespace
{
CRITICAL_SECTION cs;
DWORD key;
registered_handlers registry;
}
#if defined(__BORLANDC__)
@@ -38,7 +35,6 @@ BOOL WINAPI DllMain(HANDLE module, DWORD reason, LPVOID)
switch (reason)
{
case DLL_PROCESS_ATTACH:
InitializeCriticalSection(&cs);
key = TlsAlloc();
break;
case DLL_THREAD_ATTACH:
@@ -49,39 +45,14 @@ BOOL WINAPI DllMain(HANDLE module, DWORD reason, LPVOID)
exit_handlers* handlers = static_cast<exit_handlers*>(TlsGetValue(key));
if (handlers)
{
for (exit_handlers::iterator it = handlers->begin(); it != handlers->end(); ++it)
for (exit_handlers::reverse_iterator it = handlers->rbegin(); it != handlers->rend(); ++it)
(*it)();
// Remove the exit handler list from the registered lists and then destroy it.
EnterCriticalSection(&cs);
registry.erase(handlers);
LeaveCriticalSection(&cs);
delete handlers;
}
}
break;
case DLL_PROCESS_DETACH:
{
// Assume the main thread is ending (call its handlers) and all other threads
// have already ended. If this DLL is loaded and unloaded dynamically at run time
// this is a bad assumption, but this is the best we can do.
exit_handlers* handlers = static_cast<exit_handlers*>(TlsGetValue(key));
if (handlers)
{
for (exit_handlers::iterator it = handlers->begin(); it != handlers->end(); ++it)
(*it)();
}
// Destroy any remaining exit handlers. Above we assumed there'd only be the main
// thread left, but to insure we don't get memory leaks we won't make that assumption
// here.
EnterCriticalSection(&cs);
for (registered_handlers::iterator it = registry.begin(); it != registry.end(); ++it)
delete (*it);
LeaveCriticalSection(&cs);
DeleteCriticalSection(&cs);
TlsFree(key);
}
break;
}
return TRUE;
@@ -112,25 +83,9 @@ int on_thread_exit(void (__cdecl * func)(void))
delete handlers;
return -1;
}
// Attempt to register this new handler so that memory can be properly
// cleaned up.
try
{
EnterCriticalSection(&cs);
registry.insert(handlers);
LeaveCriticalSection(&cs);
}
catch (...)
{
LeaveCriticalSection(&cs);
delete handlers;
return -1;
}
}
// Attempt to add the handler to the list of exit handlers. If it's been previously
// added just report success and exit.
// Attempt to add the handler to the list of exit handlers.
try
{
handlers->push_front(func);

View File

@@ -59,7 +59,7 @@ namespace {
res = boost::xtime_get(&cur, boost::TIME_UTC);
assert(res == boost::TIME_UTC);
if (xt.sec < cur.sec || (xt.sec == cur.sec && xt.nsec < cur.nsec))
if (boost::xtime_cmp(xt, cur) <= 0)
{
ts.tv_sec = 0;
ts.tv_nsec = 0;
@@ -90,7 +90,7 @@ namespace {
res = boost::xtime_get(&cur, boost::TIME_UTC);
assert(res == boost::TIME_UTC);
if (xt.sec < cur.sec || (xt.sec == cur.sec && xt.nsec < cur.nsec))
if (boost::xtime_cmp(xt, cur) <= 0)
milliseconds = 0;
else
{
@@ -107,7 +107,7 @@ namespace {
res = boost::xtime_get(&cur, boost::TIME_UTC);
assert(res == boost::TIME_UTC);
if (xt.sec < cur.sec || (xt.sec == cur.sec && xt.nsec < cur.nsec))
if (boost::xtime_get(&cur, boost::TIME_UTC) <= 0)
microseconds = 0;
else
{

View File

@@ -11,66 +11,302 @@
#include <boost/thread/tss.hpp>
#include <boost/thread/once.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/exceptions.hpp>
#include <vector>
#include <stdexcept>
#include <cassert>
#if defined(BOOST_HAS_WINTHREADS)
# include <windows.h>
# include "threadmon.hpp"
#endif
#if defined(BOOST_HAS_WINTHREADS)
#include "threadmon.hpp"
#include <map>
namespace {
typedef std::pair<void(*)(void*), void*> cleanup_info;
typedef std::map<int, cleanup_info> cleanup_handlers;
typedef std::vector<std::pair<int, void*> > tss_slots;
DWORD key;
boost::once_flag once = BOOST_ONCE_INIT;
struct tss_slot_info
{
boost::function1<void, void*> cleanup;
int generation;
int next_free;
};
typedef std::vector<tss_slot_info> tss_slot_info_vector;
void init_cleanup_key()
{
key = TlsAlloc();
assert(key != 0xFFFFFFFF);
}
struct tss_data_t
{
boost::mutex mutex;
tss_slot_info_vector slot_info;
#if defined(BOOST_HAS_WINTHREADS)
DWORD native_key;
#elif defined(BOOST_HAS_PTHREADS)
pthread_key_t native_key;
#endif
int next_free;
};
void __cdecl cleanup()
{
cleanup_handlers* handlers = static_cast<cleanup_handlers*>(TlsGetValue(key));
for (cleanup_handlers::iterator it = handlers->begin(); it != handlers->end(); ++it)
{
cleanup_info info = it->second;
if (info.second)
info.first(info.second);
}
delete handlers;
}
tss_data_t* tss_data = 0;
boost::once_flag tss_once = BOOST_ONCE_INIT;
cleanup_handlers* get_handlers()
{
boost::call_once(&init_cleanup_key, once);
extern "C" void cleanup_slots(void* p)
{
tss_slots* slots = static_cast<tss_slots*>(p);
boost::mutex::scoped_lock lock(tss_data->mutex);
for (tss_slot_info_vector::size_type i = 0; i < tss_data->slot_info.size(); ++i)
{
int generation = (*slots)[i].first;
void *& data = (*slots)[i].second;
if (generation == tss_data->slot_info[i].generation && data != 0)
{
tss_data->slot_info[i].cleanup(data);
data = 0;
}
}
}
cleanup_handlers* handlers = static_cast<cleanup_handlers*>(TlsGetValue(key));
if (!handlers)
{
try
{
handlers = new cleanup_handlers;
}
catch (...)
{
return 0;
}
int res = 0;
res = TlsSetValue(key, handlers);
assert(res);
res = on_thread_exit(&cleanup);
assert(res == 0);
}
#if defined(BOOST_HAS_WINTHREADS)
void __cdecl tss_thread_exit()
{
tss_slots* slots = static_cast<tss_slots*>(TlsGetValue(tss_data->native_key));
if (slots)
cleanup_slots(slots);
}
#endif
return handlers;
}
void init_tss_data()
{
// Intentional memory "leak"
// This is the only way to insure the mutex in the global data structure
// is available when cleanup handlers are run, since the execution order
// of cleanup handlers is unspecified on any platform with regards to
// C++ destructor ordering rules.
tss_data = new tss_data_t;
#if defined(BOOST_HAS_WINTHREADS)
tss_data->native_key = TlsAlloc();
assert(tss_data->native_key != 0xFFFFFFFF);
#elif defined(BOOST_HAS_PTHREADS)
int res = 0;
res = pthread_key_create(&tss_data->native_key, &cleanup_slots);
assert(res == 0);
#endif
tss_data->next_free = -1;
}
tss_slots* get_slots(bool alloc)
{
tss_slots* slots = 0;
#if defined(BOOST_HAS_WINTHREADS)
slots = static_cast<tss_slots*>(TlsGetValue(tss_data->native_key));
#elif defined(BOOST_HAS_PTHREADS)
slots = static_cast<tss_slots*>(pthread_getspecific(tss_data->native_key));
#endif
if (slots == 0 && alloc)
{
std::auto_ptr<tss_slots> temp(new tss_slots);
#if defined(BOOST_HAS_WINTHREADS)
if (!TlsSetValue(tss_data->native_key, temp.get()))
return 0;
on_thread_exit(&tss_thread_exit);
#elif defined(BOOST_HAS_PTHREADS)
if (pthread_setspecific(tss_data->native_key, temp.get()) != 0)
return 0;
#endif
slots = temp.release();
}
return slots;
}
} // namespace
namespace boost {
namespace detail {
tss_ref::tss_ref()
{
boost::call_once(&init_tss_data, tss_once);
}
tss::tss(boost::function1<void, void*> cleanup)
{
boost::mutex::scoped_lock lock(tss_data->mutex);
m_slot = tss_data->next_free;
if (m_slot == -1)
{
tss_slot_info info;
info.generation = 0;
info.next_free = -1;
try
{
tss_data->slot_info.push_back(info);
}
catch (...)
{
throw boost::thread_resource_error();
}
m_slot = tss_data->slot_info.size() - 1;
}
tss_data->next_free = tss_data->slot_info[m_slot].next_free;
tss_data->slot_info[m_slot].next_free = -1;
tss_data->slot_info[m_slot].cleanup = cleanup;
// Record the current slots "generation", which is used to insure
// we don't access a pointer that was set in a previous incarnation
// of a reused slot which has been deallocated. Recording this here
// is an optimization that allows us to have lock free access to
// TSS data.
m_generation = tss_data->slot_info[m_slot].generation;
}
tss::~tss()
{
boost::mutex::scoped_lock lock(tss_data->mutex);
// Increment the "generation" here. We do this here in the destructor
// instead of the constructor specifically to "leak" data stored in
// an thread's TSS immediately, rather then later, which may give
// users a false sense that their code isn't flawed.
tss_data->slot_info[m_slot].generation++;
tss_data->slot_info[m_slot].next_free = tss_data->next_free;
tss_data->next_free = m_slot;
}
void* tss::get() const
{
tss_slots* slots = get_slots(false);
if (!slots)
return 0;
if (m_slot >= slots->size())
return 0;
if ((*slots)[m_slot].first == m_generation)
return (*slots)[m_slot].second;
return 0;
}
void tss::set(void* value)
{
tss_slots* slots = get_slots(true);
if (!slots)
throw boost::thread_resource_error();
if (m_slot >= slots->size())
{
try
{
slots->resize(m_slot + 1);
}
catch (...)
{
throw boost::thread_resource_error();
}
}
(*slots)[m_slot].first = m_generation;
(*slots)[m_slot].second = value;
}
void tss::cleanup(void* value)
{
boost::mutex::scoped_lock lock(tss_data->mutex);
tss_data->slot_info[m_slot].cleanup(value);
}
} // namespace detail
} // namespace boost
/*
#if defined(BOOST_HAS_WINTHREADS)
namespace {
typedef std::vector<std::pair<boost::detail::tss*, int> > key_type;
typedef std::vector<void*> slots_type;
DWORD key;
boost::once_flag once = BOOST_ONCE_INIT;
boost::mutex* pmutex;
key_type* pkeys;
int next_key;
void __cdecl cleanup_tss_data();
void init_tss()
{
// static boost::mutex mutex;
// static key_type keys;
// pmutex = &mutex;
// pkeys = &keys;
pmutex = new boost::mutex;
pkeys = new key_type;
key = TlsAlloc();
assert(key != 0xFFFFFFFF);
next_key = 0;
}
int alloc_key(boost::detail::tss* ptss)
{
boost::call_once(&init_tss, once);
boost::mutex::scoped_lock lock(*pmutex);
int key = next_key;
if (key >= pkeys->size())
{
pkeys->resize(key+1);
(*pkeys)[key].second = pkeys->size();
}
next_key = (*pkeys)[key].second;
(*pkeys)[key].first = ptss;
return key;
}
void free_key(int key)
{
boost::call_once(&init_tss, once);
boost::mutex::scoped_lock lock(*pmutex);
assert(key >= 0 && key < pkeys->size());
(*pkeys)[key].first = 0;
(*pkeys)[key].second = next_key;
next_key = key;
}
slots_type* get_tss_data()
{
boost::call_once(&init_tss, once);
if (key == 0xFFFFFFFF)
return 0;
slots_type* pdata = (slots_type*)TlsGetValue(key);
if (pdata == 0)
{
std::auto_ptr<slots_type> slots(new(std::nothrow) slots_type);
if (!TlsSetValue(key, slots.get()))
return 0;
on_thread_exit(&cleanup_tss_data);
pdata = slots.release();
}
return pdata;
}
void __cdecl cleanup_tss_data()
{
slots_type* pdata = get_tss_data();
if (pdata)
{
boost::mutex::scoped_lock lock(*pmutex);
for (int key = 0; key < pdata->size(); ++key)
{
void* pvalue = (*pdata)[key];
boost::detail::tss* ptss = pkeys && key < pkeys->size() ? (*pkeys)[key].first : 0;
if (ptss && pvalue)
ptss->cleanup(pvalue);
}
delete pdata;
}
}
}
#elif defined(BOOST_HAS_MPTASKS)
#include <map>
@@ -117,7 +353,6 @@ namespace boost {
namespace detail {
void thread_cleanup()
{
cleanup_handlers* handlers = reinterpret_cast<cleanup_handlers*>(MPGetTaskStorageValue(key));
@@ -143,39 +378,53 @@ void thread_cleanup()
namespace boost { namespace detail {
#if defined(BOOST_HAS_WINTHREADS)
tss::tss(void (*cleanup)(void*))
tss::tss(boost::function1<void, void*> cleanup)
{
m_key = TlsAlloc();
if (m_key == 0xFFFFFFFF)
throw thread_resource_error();
m_cleanup = cleanup;
m_key = alloc_key(this);
m_clean = cleanup;
m_module = (void*)LoadLibrary("boostthreadmon.dll");
}
tss::~tss()
{
int res = 0;
res = TlsFree(m_key);
assert(res);
free_key(m_key);
FreeLibrary((HMODULE)m_module);
}
void* tss::get() const
{
return TlsGetValue(m_key);
slots_type* pdata = get_tss_data();
if (pdata)
{
if (m_key >= pdata->size())
return 0;
return (*pdata)[m_key];
}
return 0;
}
bool tss::set(void* value)
void tss::set(void* value)
{
if (value && m_cleanup)
{
cleanup_handlers* handlers = get_handlers();
assert(handlers);
if (!handlers)
return false;
cleanup_info info(m_cleanup, value);
(*handlers)[m_key] = info;
}
return !!TlsSetValue(m_key, value);
slots_type* pdata = get_tss_data();
if (!pdata)
throw thread_resource_error();
if (m_key >= pdata->size())
{
try
{
pdata->resize(m_key+1);
}
catch (...)
{
throw thread_resource_error();
}
}
(*pdata)[m_key] = value;
}
void tss::cleanup(void* value)
{
m_clean(value);
}
#elif defined(BOOST_HAS_PTHREADS)
tss::tss(void (*cleanup)(void*))
@@ -198,9 +447,12 @@ void* tss::get() const
return pthread_getspecific(m_key);
}
bool tss::set(void* value)
void tss::set(void* value)
{
return pthread_setspecific(m_key, value) == 0;
int res = pthread_setspecific(m_key, value) == 0;
assert(res == 0 || res = ENOMEM);
if (res == ENOMEM)
throw thread_resource_error();
}
#elif defined(BOOST_HAS_MPTASKS)
tss::tss(void (*cleanup)(void*))
@@ -224,9 +476,9 @@ void* tss::get() const
return(reinterpret_cast<void *>(ulValue));
}
bool tss::set(void* value)
void tss::set(void* value)
{
if (value && m_cleanup)
if (m_cleanup)
{
cleanup_handlers* handlers = get_handlers();
assert(handlers);
@@ -236,12 +488,15 @@ bool tss::set(void* value)
(*handlers)[m_key] = info;
}
OSStatus lStatus = MPSetTaskStorageValue(m_key, reinterpret_cast<TaskStorageValue>(value));
return(lStatus == noErr);
// return(lStatus == noErr);
}
#endif
} // namespace detail
} // namespace boost
*/
// Change Log:
// 6 Jun 01 WEKEMPF Initial version.
// 30 May 02 WEKEMPF Added interface to set specific cleanup handlers. Removed TLS slot limits
// from most implementations.

View File

@@ -23,18 +23,30 @@ subproject libs/thread/test ;
# Include threads.jam for Boost.Threads global build information.
# This greatly simplifies the Jam code needed to configure the build
# for the various Win32 build types.
SEARCH on <module@>threads.jam = $(BOOST_ROOT)/libs/thread/build ;
include <module@>threads.jam ;
SEARCH on threads.jam = $(BOOST_ROOT)/libs/thread/build ;
include threads.jam ;
# bring in rules for testing
SEARCH on testing.jam = $(BOOST_BUILD_PATH) ;
include testing.jam ;
sources = test.cpp test_thread.cpp test_mutex.cpp test_condition.cpp test_tss.cpp test_once.cpp ;
template test
## sources ##
: <template>thread_base <lib>../build/boost_thread <lib>../../test/build/unit_test_framework $(threadmon)
## requirements ##
:
## default build ##
: debug release <runtime-link>static/dynamic
;
#######################
# Declare the Boost.Threads unit test program test_thread.
unit-test test_thread
: test_thread.cpp
<lib>../build/boost_thread
$(threadmon)
: <include>$(BOOST_ROOT)
$(pthreads-win32)
<threading>multi
: debug release <runtime-link>static/dynamic
;
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 ;

Binary file not shown.

39
test/test_barrier.cpp Normal file
View File

@@ -0,0 +1,39 @@
#include <boost/thread/thread.hpp>
#include <boost/thread/barrier.hpp>
#include <boost/test/test_tools.hpp>
namespace {
// Shared variables for generation barrier test
const int N_THREADS=10;
boost::barrier gen_barrier(N_THREADS);
boost::mutex mutex;
long global_parameter;
void barrier_thread()
{
for (int i = 0; i < 5; ++i)
{
if (gen_barrier.wait())
{
boost::mutex::scoped_lock lock(mutex);
global_parameter++;
}
}
}
} // namespace
void test_barrier()
{
boost::thread_group g;
global_parameter = 0;
for (int i = 0; i < N_THREADS; ++i)
g.create_thread(&barrier_thread);
g.join_all();
BOOST_TEST(global_parameter == 5);
}

30
test/test_call_once.cpp Normal file
View File

@@ -0,0 +1,30 @@
#include <boost/thread/thread.hpp>
#include <boost/thread/once.hpp>
#include <boost/test/test_tools.hpp>
namespace {
int once_value = 0;
boost::once_flag once = BOOST_ONCE_INIT;
void init_once_value()
{
once_value++;
}
void test_once_thread()
{
boost::call_once(&init_once_value, once);
}
} // namespace
void test_call_once()
{
const int NUMTHREADS=5;
boost::thread_group threads;
for (int i=0; i<NUMTHREADS; ++i)
threads.create_thread(&test_once_thread);
threads.join_all();
BOOST_TEST(once_value == 1);
}

202
test/test_condition.cpp Normal file
View File

@@ -0,0 +1,202 @@
#include <boost/thread/condition.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/xtime.hpp>
#include <boost/test/unit_test.hpp>
namespace
{
struct condition_test_data
{
condition_test_data() : notified(0), awoken(0) { }
boost::mutex mutex;
boost::condition condition;
int notified;
int awoken;
};
void condition_test_thread(void* param)
{
condition_test_data* data = static_cast<condition_test_data*>(param);
boost::mutex::scoped_lock lock(data->mutex);
BOOST_CHECK(lock ? true : false);
while (!(data->notified > 0))
data->condition.wait(lock);
BOOST_CHECK(lock ? true : false);
data->awoken++;
}
class thread_adapter
{
public:
thread_adapter(void (*func)(void*), void* param) : _func(func), _param(param) { }
void operator()() const { _func(_param); }
private:
void (*_func)(void*);
void* _param;
};
struct cond_predicate
{
cond_predicate(int& var, int val) : _var(var), _val(val) { }
bool operator()() { return _var == _val; }
int& _var;
int _val;
};
void condition_test_waits(void* param)
{
condition_test_data* data = static_cast<condition_test_data*>(param);
boost::mutex::scoped_lock lock(data->mutex);
BOOST_CHECK(lock ? true : false);
// Test wait.
while (data->notified != 1)
data->condition.wait(lock);
BOOST_CHECK(lock ? true : false);
BOOST_CHECK_EQUAL(data->notified, 1);
data->awoken++;
data->condition.notify_one();
// Test predicate wait.
data->condition.wait(lock, cond_predicate(data->notified, 2));
BOOST_CHECK(lock ? true : false);
BOOST_CHECK_EQUAL(data->notified, 2);
data->awoken++;
data->condition.notify_one();
// Test timed_wait.
boost::xtime xt;
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
xt.sec += 10;
while (data->notified != 3)
data->condition.timed_wait(lock, xt);
BOOST_CHECK(lock ? true : false);
BOOST_CHECK_EQUAL(data->notified, 3);
data->awoken++;
data->condition.notify_one();
// Test predicate timed_wait.
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
xt.sec += 10;
cond_predicate pred(data->notified, 4);
BOOST_CHECK(data->condition.timed_wait(lock, xt, pred));
BOOST_CHECK(lock ? true : false);
BOOST_CHECK(pred());
BOOST_CHECK_EQUAL(data->notified, 4);
data->awoken++;
data->condition.notify_one();
}
}
void test_condition_notify_one()
{
condition_test_data data;
boost::thread thread(thread_adapter(&condition_test_thread, &data));
{
boost::mutex::scoped_lock lock(data.mutex);
BOOST_CHECK(lock ? true : false);
data.notified++;
data.condition.notify_one();
}
thread.join();
BOOST_CHECK_EQUAL(data.awoken, 1);
}
void test_condition_notify_all()
{
const int NUMTHREADS = 5;
boost::thread_group threads;
condition_test_data data;
for (int i = 0; i < NUMTHREADS; ++i)
threads.create_thread(thread_adapter(&condition_test_thread, &data));
{
boost::mutex::scoped_lock lock(data.mutex);
BOOST_CHECK(lock ? true : false);
data.notified++;
data.condition.notify_all();
}
threads.join_all();
BOOST_CHECK_EQUAL(data.awoken, NUMTHREADS);
}
void test_condition_waits()
{
condition_test_data data;
boost::thread thread(thread_adapter(&condition_test_waits, &data));
boost::xtime xt;
{
boost::mutex::scoped_lock lock(data.mutex);
BOOST_CHECK(lock ? true : false);
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
xt.sec += 1;
boost::thread::sleep(xt);
data.notified++;
data.condition.notify_one();
while (data.awoken != 1)
data.condition.wait(lock);
BOOST_CHECK(lock ? true : false);
BOOST_CHECK_EQUAL(data.awoken, 1);
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
xt.sec += 1;
boost::thread::sleep(xt);
data.notified++;
data.condition.notify_one();
while (data.awoken != 2)
data.condition.wait(lock);
BOOST_CHECK(lock ? true : false);
BOOST_CHECK_EQUAL(data.awoken, 2);
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
xt.sec += 1;
boost::thread::sleep(xt);
data.notified++;
data.condition.notify_one();
while (data.awoken != 3)
data.condition.wait(lock);
BOOST_CHECK(lock ? true : false);
BOOST_CHECK_EQUAL(data.awoken, 3);
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
xt.sec += 1;
boost::thread::sleep(xt);
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), static_cast<int>(boost::TIME_UTC));
xt.sec += 1;
boost::thread::sleep(xt);
thread.join();
BOOST_CHECK_EQUAL(data.awoken, 4);
}
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_all));
test->add(BOOST_TEST_CASE(&test_condition_waits));
return test;
}

53
test/test_harness.cpp Normal file
View File

@@ -0,0 +1,53 @@
#define BOOST_INCLUDE_MAIN
#include <boost/test/test_tools.hpp>
#include <iostream>
#include <process.h>
extern void test_xtime_get();
extern void test_thread();
extern void test_thread_group();
extern void test_mutex();
extern void test_try_mutex();
extern void test_timed_mutex();
extern void test_recursive_mutex();
extern void test_recursive_try_mutex();
extern void test_recursive_timed_mutex();
extern void test_condition();
extern void test_thread_specific_ptr();
extern void test_call_once();
extern void test_barrier();
extern void test_thread_pool();
extern void test_rw_mutex();
namespace {
void run_test(void (*func)())
{
// Indicate testing progress...
std::cout << '.' << std::flush;
(*func)();
}
} // namespace
int test_main(int, char*[])
{
run_test(&test_xtime_get);
run_test(&test_thread);
run_test(&test_thread_group);
run_test(&test_mutex);
run_test(&test_try_mutex);
run_test(&test_timed_mutex);
run_test(&test_recursive_mutex);
run_test(&test_recursive_try_mutex);
run_test(&test_recursive_timed_mutex);
run_test(&test_condition);
run_test(&test_thread_specific_ptr);
run_test(&test_call_once);
run_test(&test_barrier);
run_test(&test_thread_pool);
// run_test(&test_rw_mutex);
// _endthreadex(0);
return 0;
}

229
test/test_mutex.cpp Normal file
View File

@@ -0,0 +1,229 @@
#include <boost/thread/mutex.hpp>
#include <boost/thread/recursive_mutex.hpp>
#include <boost/thread/xtime.hpp>
#include <boost/thread/condition.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/test/unit_test_suite_ex.hpp>
namespace
{
inline bool xtime_in_range(boost::xtime& xt, int less_seconds, int greater_seconds)
{
boost::xtime cur;
BOOST_CHECK_EQUAL(boost::xtime_get(&cur, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
boost::xtime less = cur;
less.sec += less_seconds;
boost::xtime greater = cur;
greater.sec += greater_seconds;
return (boost::xtime_cmp(xt, less) >= 0) && (boost::xtime_cmp(xt, greater) <= 0);
}
}
template <typename M>
struct test_lock
{
typedef M mutex_type;
typedef typename M::scoped_lock lock_type;
void operator()()
{
mutex_type mutex;
boost::condition condition;
// Test the lock's constructors.
{
lock_type lock(mutex, false);
BOOST_CHECK(!lock);
}
lock_type lock(mutex);
BOOST_CHECK(lock ? true : false);
// Construct and initialize an xtime for a fast time out.
boost::xtime xt;
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
xt.nsec += 100000000;
// Test the lock and the mutex with condition variables.
// No one is going to notify this condition variable. We expect to
// time out.
BOOST_CHECK(!condition.timed_wait(lock, xt));
BOOST_CHECK(lock ? true : false);
// Test the lock and unlock methods.
lock.unlock();
BOOST_CHECK(!lock);
lock.lock();
BOOST_CHECK(lock ? true : false);
}
};
template <typename M>
struct test_trylock
{
typedef M mutex_type;
typedef typename M::scoped_try_lock try_lock_type;
void operator()()
{
mutex_type mutex;
boost::condition condition;
// Test the lock's constructors.
{
try_lock_type lock(mutex);
BOOST_CHECK(lock ? true : false);
}
{
try_lock_type lock(mutex, false);
BOOST_CHECK(!lock);
}
try_lock_type lock(mutex, true);
BOOST_CHECK(lock ? true : false);
// Construct and initialize an xtime for a fast time out.
boost::xtime xt;
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
xt.nsec += 100000000;
// Test the lock and the mutex with condition variables.
// No one is going to notify this condition variable. We expect to
// time out.
BOOST_CHECK(!condition.timed_wait(lock, xt));
BOOST_CHECK(lock ? true : false);
// Test the lock, unlock and trylock methods.
lock.unlock();
BOOST_CHECK(!lock);
lock.lock();
BOOST_CHECK(lock ? true : false);
lock.unlock();
BOOST_CHECK(!lock);
BOOST_CHECK(lock.try_lock());
BOOST_CHECK(lock ? true : false);
}
};
template <typename M>
struct test_timedlock
{
typedef M mutex_type;
typedef typename M::scoped_timed_lock timed_lock_type;
void operator()()
{
mutex_type mutex;
boost::condition condition;
// Test the lock's constructors.
{
// Construct and initialize an xtime for a fast time out.
boost::xtime xt;
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
xt.nsec += 100000000;
timed_lock_type lock(mutex, xt);
BOOST_CHECK(lock ? true : false);
}
{
timed_lock_type lock(mutex, false);
BOOST_CHECK(!lock);
}
timed_lock_type lock(mutex, true);
BOOST_CHECK(lock ? true : false);
// Construct and initialize an xtime for a fast time out.
boost::xtime xt;
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
xt.nsec += 100000000;
// Test the lock and the mutex with condition variables.
// No one is going to notify this condition variable. We expect to
// time out.
BOOST_CHECK(!condition.timed_wait(lock, xt));
BOOST_CHECK(lock ? true : false);
BOOST_CHECK(xtime_in_range(xt, -1, 0));
// Test the lock, unlock and timedlock methods.
lock.unlock();
BOOST_CHECK(!lock);
lock.lock();
BOOST_CHECK(lock ? true : false);
lock.unlock();
BOOST_CHECK(!lock);
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
xt.nsec += 100000000;
BOOST_CHECK(lock.timed_lock(xt));
BOOST_CHECK(lock ? true : false);
}
};
template <typename M>
struct test_recursive_lock
{
typedef M mutex_type;
typedef typename M::scoped_lock lock_type;
void operator()()
{
mutex_type mx;
lock_type lock1(mx);
lock_type lock2(mx);
}
};
void test_mutex()
{
test_lock<boost::mutex>()();
}
void test_try_mutex()
{
test_lock<boost::try_mutex>()();
test_trylock<boost::try_mutex>()();
}
void test_timed_mutex()
{
test_lock<boost::timed_mutex>()();
test_trylock<boost::timed_mutex>()();
test_timedlock<boost::timed_mutex>()();
}
void test_recursive_mutex()
{
test_lock<boost::recursive_mutex>()();
test_recursive_lock<boost::recursive_mutex>()();
}
void test_recursive_try_mutex()
{
test_lock<boost::recursive_try_mutex>()();
test_trylock<boost::recursive_try_mutex>()();
test_recursive_lock<boost::recursive_try_mutex>()();
}
void test_recursive_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>()();
}
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;
}

39
test/test_once.cpp Normal file
View File

@@ -0,0 +1,39 @@
#include <boost/thread/once.hpp>
#include <boost/thread/thread.hpp>
#include <boost/test/unit_test.hpp>
namespace
{
int once_value = 0;
boost::once_flag once = BOOST_ONCE_INIT;
void init_once_value()
{
once_value++;
}
void test_once_thread()
{
boost::call_once(init_once_value, once);
}
}
void test_once()
{
const int NUMTHREADS=5;
boost::thread_group threads;
for (int i=0; i<NUMTHREADS; ++i)
threads.create_thread(&test_once_thread);
threads.join_all();
BOOST_CHECK_EQUAL(once_value, 1);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test = BOOST_TEST_SUITE("Boost.Threads: once test suite");
test->add(BOOST_TEST_CASE(test_once));
return test;
}

309
test/test_rw_mutex.cpp Normal file
View File

@@ -0,0 +1,309 @@
#include <boost/thread/thread.hpp>
#include <boost/thread/xtime.hpp>
#include <boost/thread/rw_mutex.hpp>
#include <boost/test/test_tools.hpp>
#include <iostream>
namespace {
int shared_val = 0;
boost::xtime xsecs(int secs)
{
boost::xtime ret;
BOOST_TEST(boost::TIME_UTC == boost::xtime_get(&ret, boost::TIME_UTC));
ret.sec += secs;
return ret;
}
template <typename RW>
class thread_adapter
{
public:
thread_adapter(void (*func)(void*,RW &), void* param1,RW &param2)
: _func(func), _param1(param1) ,_param2(param2){ }
void operator()() const { _func(_param1, _param2); }
private:
void (*_func)(void*, RW &);
void* _param1;
RW& _param2;
};
template <typename RW>
struct data
{
data(int id, RW &m, int secs=0) : m_id(id), m_value(-1), m_secs(secs), m_rw_mutex(m) { }
int m_id;
int m_value;
int m_secs;
RW& m_rw_mutex; // Reader/Writer mutex
};
// plain_writer excercises the "infinite" lock for each
// RW_mutex type.
template<typename RW>
void plain_writer(void *arg,RW &rw)
{
data<RW> *pdata = (data<RW> *) arg;
// std::cout << "-->W" << pdata->m_id << "\n";
typename RW::scoped_rw_lock l(rw,boost::EXCL_LOCK);
boost::thread::sleep(xsecs(3));
shared_val += 10;
pdata->m_value = shared_val;
}
template<typename RW>
void plain_reader(void *arg,RW &rw)
{
data<RW> *pdata = (data<RW> *) arg;
typename RW::scoped_rw_lock l(rw,boost::SHARED_LOCK);
pdata->m_value = shared_val;
}
template<typename RW>
void try_writer(void *arg,RW &rw)
{
data<RW> *pdata = (data<RW> *) arg;
// std::cout << "-->W" << pdata->m_id << "\n";
typename RW::scoped_try_rw_lock l(rw,boost::NO_LOCK);
if(l.try_wrlock())
{
boost::thread::sleep(xsecs(3));
shared_val += 10;
pdata->m_value = shared_val;
}
}
template<typename RW>
void try_reader(void *arg,RW &rw)
{
data<RW> *pdata = (data<RW> *) arg;
typename RW::scoped_try_rw_lock l(rw);
if(l.try_rdlock())
{
pdata->m_value = shared_val;
}
}
template<typename RW>
void timed_writer(void *arg,RW &rw)
{
data<RW> *pdata = (data<RW> *) arg;
boost::xtime xt;
xt = xsecs(pdata->m_secs);
typename RW::scoped_timed_rw_lock l(rw,boost::NO_LOCK);
if(l.timed_wrlock(xt))
{
boost::thread::sleep(xsecs(3));
shared_val += 10;
pdata->m_value = shared_val;
}
}
template<typename RW>
void timed_reader(void *arg,RW &rw)
{
data<RW> *pdata = (data<RW> *) arg;
boost::xtime xt;
xt = xsecs(pdata->m_secs);
typename RW::scoped_timed_rw_lock l(rw,boost::NO_LOCK);
if(l.timed_rdlock(xt))
{
pdata->m_value = shared_val;
}
}
template<typename RW>
void dump_times(const char *prefix,data<RW> *pdata)
{
std::cout << " " << prefix << pdata->m_id <<
" In:" << pdata->m_start.LowPart <<
" Holding:" << pdata->m_holding.LowPart <<
" Out: " << pdata->m_end.LowPart << std::endl;
}
template<typename RW>
void test_plain_rw_mutex(RW &rw_mutex)
{
shared_val = 0;
data<RW> r1(1,rw_mutex);
data<RW> r2(2,rw_mutex);
data<RW> w1(1,rw_mutex);
data<RW> w2(2,rw_mutex);
// Writer one launches, holds the lock for 3 seconds.
boost::thread tw1(thread_adapter<RW>(plain_writer,&w1,rw_mutex));
// Writer two launches, tries to grab the lock, "clearly"
// after Writer one will already be holding it.
boost::thread::sleep(xsecs(1));
boost::thread tw2(thread_adapter<RW>(plain_writer,&w2,rw_mutex));
// Reader one launches, "clearly" after writer two, and "clearly"
// while writer 1 still holds the lock
boost::thread::sleep(xsecs(1));
boost::thread tr1(thread_adapter<RW>(plain_reader,&r1,rw_mutex));
boost::thread tr2(thread_adapter<RW>(plain_reader,&r2,rw_mutex));
tr2.join();
tr1.join();
tw2.join();
tw1.join();
if(rw_mutex.policy() == boost::sp_writer_priority)
{
BOOST_TEST(w1.m_value == 10);
BOOST_TEST(w2.m_value == 20);
BOOST_TEST(r1.m_value == 20); // Readers get in after 2nd writer
BOOST_TEST(r2.m_value == 20);
}
else if(rw_mutex.policy() == boost::sp_reader_priority)
{
BOOST_TEST(w1.m_value == 10);
BOOST_TEST(w2.m_value == 20);
BOOST_TEST(r1.m_value == 10); // Readers get in before 2nd writer
BOOST_TEST(r2.m_value == 10);
}
else if(rw_mutex.policy() == boost::sp_alternating_many_reads)
{
BOOST_TEST(w1.m_value == 10);
BOOST_TEST(w2.m_value == 20);
BOOST_TEST(r1.m_value == 10); // Readers get in before 2nd writer
BOOST_TEST(r2.m_value == 10);
}
else if(rw_mutex.policy() == boost::sp_alternating_single_reads)
{
BOOST_TEST(w1.m_value == 10);
BOOST_TEST(w2.m_value == 20);
// One Reader gets in before 2nd writer, but we can't tell
// which reader will "win", so just check their sum.
BOOST_TEST((r1.m_value + r2.m_value == 30));
}
}
template<typename RW>
void test_try_rw_mutex(RW &rw_mutex)
{
data<RW> r1(1,rw_mutex);
data<RW> w1(2,rw_mutex);
data<RW> w2(3,rw_mutex);
// We start with some specialized tests for "try" behavior
shared_val = 0;
// Writer one launches, holds the lock for 3 seconds.
boost::thread tw1(thread_adapter<RW>(try_writer,&w1,rw_mutex));
// Reader one launches, "clearly" after writer #1 holds the lock
// and before it releases the lock.
boost::thread::sleep(xsecs(1));
boost::thread tr1(thread_adapter<RW>(try_reader,&r1,rw_mutex));
// Writer two launches in the same timeframe.
boost::thread tw2(thread_adapter<RW>(try_writer,&w2,rw_mutex));
tw2.join();
tr1.join();
tw1.join();
BOOST_TEST(w1.m_value == 10);
BOOST_TEST(r1.m_value == -1); // Try would return w/o waiting
BOOST_TEST(w2.m_value == -1); // Try would return w/o waiting
// We finish by repeating the plain tests with the try lock
// This is important to verify that try locks are proper rw_mutexes as
// well.
test_plain_rw_mutex(rw_mutex);
}
template<typename RW>
void test_timed_rw_mutex(RW &rw_mutex)
{
data<RW> r1(1,rw_mutex,1);
data<RW> r2(2,rw_mutex,3);
data<RW> w1(3,rw_mutex,3);
data<RW> w2(4,rw_mutex,1);
// We begin with some specialized tests for "timed" behavior
shared_val = 0;
// Writer one will hold the lock for 3 seconds.
boost::thread tw1(thread_adapter<RW>(timed_writer,&w1,rw_mutex));
boost::thread::sleep(xsecs(1));
// Writer two will "clearly" try for the lock after the readers
// have tried for it. Writer will wait up 1 second for the lock. This write will fail.
boost::thread tw2(thread_adapter<RW>(timed_writer,&w2,rw_mutex));
// Readers one and two will "clearly" try for the lock after writer
// one already holds it. 1st reader will wait 1 second, and will fail
// to get the lock. 2nd reader will wait 3 seconds, and will get
// the lock.
boost::thread tr1(thread_adapter<RW>(timed_reader,&r1,rw_mutex));
boost::thread tr2(thread_adapter<RW>(timed_reader,&r2,rw_mutex));
tw1.join();
tr1.join();
tr2.join();
tw2.join();
BOOST_TEST(w1.m_value == 10);
BOOST_TEST(r1.m_value == -1);
BOOST_TEST(r2.m_value == 10);
BOOST_TEST(w2.m_value == -1);
// We follow by repeating the try tests with the timed lock.
// This is important to verify that timed locks are proper try locks as well
test_try_rw_mutex(rw_mutex);
}
} // namespace
void test_rw_mutex()
{
int i;
for(i = (int) boost::sp_writer_priority;
i <= (int) boost::sp_alternating_single_reads;
i++)
{
boost::rw_mutex plain_rw((boost::rw_scheduling_policy) i);
boost::try_rw_mutex try_rw((boost::rw_scheduling_policy) i);
boost::timed_rw_mutex timed_rw((boost::rw_scheduling_policy) i);
std::cout << "plain test, sp=" << i << "\n";
test_plain_rw_mutex(plain_rw);
std::cout << "try test, sp=" << i << "\n";
test_try_rw_mutex(try_rw);
std::cout << "timed test, sp=" << i << "\n";
test_timed_rw_mutex(timed_rw);
}
}

154
test/test_shared_memory.cpp Normal file
View File

@@ -0,0 +1,154 @@
#include <boost/thread/shared_memory.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/xtime.hpp>
#include <boost/test/test_tools.hpp>
#include <boost/bind.hpp>
namespace
{
struct test_struct
{
char buf[128];
double val;
test_struct(const char *msg="",double v=0.0)
{
strcpy(buf,msg);
val = v;
}
};
};
struct CreateDefault
{
test_struct *operator()(void *place,size_t)
{
return new(place) test_struct;
}
};
struct CreateSlow
{
test_struct *operator()(void *place,size_t)
{
boost::xtime xt;
boost::xtime_get(&xt,boost::TIME_UTC);
xt.sec++;
boost::thread::sleep(xt);
return new(place) test_struct;
}
};
struct CreateWithParams
{
CreateWithParams(const char *msg, double v) : m_p_msg(msg),m_v(v)
{}
test_struct *operator()(void *place,size_t)
{
return new(place) test_struct(m_p_msg,m_v);
}
const char *m_p_msg;
double m_v;
};
struct CreateSlowWithParams
{
CreateSlowWithParams(const char *msg, double v) : m_p_msg(msg),m_v(v)
{}
test_struct *operator()(void *place,size_t)
{
boost::xtime xt;
boost::xtime_get(&xt,boost::TIME_UTC);
xt.sec++;
boost::thread::sleep(xt);
return new(place) test_struct(m_p_msg,m_v);
}
const char *m_p_msg;
double m_v;
};
void test_default_ctor()
{
const char *shared_name = "TestStruct";
typedef boost::shared_memory so;
so creator(shared_name,sizeof(test_struct),CreateDefault());
test_struct *pts = (test_struct *)creator.get();
BOOST_TEST(pts->buf[0] == 0);
BOOST_TEST(pts->val == 0.0);
strcpy(pts->buf,shared_name);
pts->val = 7.0;
so user(shared_name,sizeof(test_struct));
test_struct *pts2 = (test_struct *)user.get();
BOOST_TEST(strcmp(pts->buf,shared_name)==0);
BOOST_TEST(pts->val == 7.0);
}
void test_slow_create_thread()
{
const char *shared_name = "SlowStruct";
boost::shared_memory creator(shared_name,sizeof(test_struct),CreateSlowWithParams(shared_name,8.0));
test_struct *pts = (test_struct *)creator.get();
BOOST_TEST(strcmp(pts->buf,shared_name)==0);
BOOST_TEST(pts->val == 8.0);
}
void test_slow_user_thread()
{
const char *shared_name = "SlowStruct";
boost::shared_memory user(shared_name,sizeof(test_struct));
test_struct *pts2 = (test_struct *)user.get();
BOOST_TEST(strcmp(pts2->buf,shared_name)==0);
BOOST_TEST(pts2->val == 8.0);
}
void test_slow_ctor()
{
boost::thread t1(&test_slow_create_thread);
// Give the creator a chance to get moving.
boost::xtime xt;
boost::xtime_get(&xt,boost::TIME_UTC);
xt.nsec += 250000000;
boost::thread::sleep(xt);
boost::thread t2(&test_slow_user_thread);
t2.join();
t1.join();
}
void test_shared_memory()
{
test_default_ctor();
test_slow_ctor();
}

View File

@@ -1,451 +1,89 @@
#include <list>
#include <boost/thread/mutex.hpp>
#include <boost/thread/recursive_mutex.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/tss.hpp>
#include <boost/thread/once.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/xtime.hpp>
//#include <boost/test/test_tools.hpp>
#include <boost/test/unit_test.hpp>
#define BOOST_INCLUDE_MAIN
#include <boost/test/test_tools.hpp>
#if defined(BOOST_HAS_WINTHREADS)
# include <windows.h>
#endif
template <typename M>
void test_lock(M* dummy=0)
namespace
{
typedef M mutex_type;
typedef typename M::scoped_lock lock_type;
mutex_type mutex;
boost::condition condition;
// Test the lock's constructors.
inline bool xtime_in_range(boost::xtime& xt, int less_seconds, int greater_seconds)
{
lock_type lock(mutex, false);
BOOST_TEST(!lock);
}
lock_type lock(mutex);
BOOST_TEST(lock);
boost::xtime cur;
BOOST_CHECK_EQUAL(boost::xtime_get(&cur, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
// Construct and initialize an xtime for a fast time out.
boost::xtime less = cur;
less.sec += less_seconds;
boost::xtime greater = cur;
greater.sec += greater_seconds;
return (boost::xtime_cmp(xt, less) >= 0) && (boost::xtime_cmp(xt, greater) <= 0);
}
int test_value;
void simple_thread()
{
test_value = 999;
}
struct thread_adapter
{
thread_adapter(void (*func)(boost::thread& parent), boost::thread& parent)
: func(func), parent(parent)
{
}
void operator()()
{
(*func)(parent);
}
void (*func)(boost::thread& parent);
boost::thread& parent;
};
void comparison_thread(boost::thread& parent)
{
boost::thread thrd;
BOOST_TEST(thrd != parent);
BOOST_TEST(thrd == boost::thread());
}
}
void test_sleep()
{
boost::xtime xt;
BOOST_TEST(boost::xtime_get(&xt, boost::TIME_UTC) == boost::TIME_UTC);
xt.nsec += 100000000;
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
xt.sec += 3;
// Test the lock and the mutex with condition variables.
// No one is going to notify this condition variable. We expect to
// time out.
BOOST_TEST(condition.timed_wait(lock, xt) == false);
BOOST_TEST(lock);
// Test the lock and unlock methods.
lock.unlock();
BOOST_TEST(!lock);
lock.lock();
BOOST_TEST(lock);
}
template <typename M>
void test_trylock(M* dummy=0)
{
typedef M mutex_type;
typedef typename M::scoped_try_lock try_lock_type;
mutex_type mutex;
boost::condition condition;
// Test the lock's constructors.
{
try_lock_type lock(mutex);
BOOST_TEST(lock);
}
{
try_lock_type lock(mutex, false);
BOOST_TEST(!lock);
}
try_lock_type lock(mutex, true);
BOOST_TEST(lock);
// Construct and initialize an xtime for a fast time out.
boost::xtime xt;
BOOST_TEST(boost::xtime_get(&xt, boost::TIME_UTC) == boost::TIME_UTC);
xt.nsec += 100000000;
// Test the lock and the mutex with condition variables.
// No one is going to notify this condition variable. We expect to
// time out.
BOOST_TEST(condition.timed_wait(lock, xt) == false);
BOOST_TEST(lock);
// Test the lock, unlock and trylock methods.
lock.unlock();
BOOST_TEST(!lock);
lock.lock();
BOOST_TEST(lock);
lock.unlock();
BOOST_TEST(!lock);
BOOST_TEST(lock.try_lock());
BOOST_TEST(lock);
}
template <typename M>
void test_timedlock(M* dummy=0)
{
typedef M mutex_type;
typedef typename M::scoped_timed_lock timed_lock_type;
mutex_type mutex;
boost::condition condition;
// Test the lock's constructors.
{
// Construct and initialize an xtime for a fast time out.
boost::xtime xt;
BOOST_TEST(boost::xtime_get(&xt, boost::TIME_UTC) == boost::TIME_UTC);
xt.nsec += 100000000;
timed_lock_type lock(mutex, xt);
BOOST_TEST(lock);
}
{
timed_lock_type lock(mutex, false);
BOOST_TEST(!lock);
}
timed_lock_type lock(mutex, true);
BOOST_TEST(lock);
// Construct and initialize an xtime for a fast time out.
boost::xtime xt;
BOOST_TEST(boost::xtime_get(&xt, boost::TIME_UTC) == boost::TIME_UTC);
xt.nsec += 100000000;
// Test the lock and the mutex with condition variables.
// No one is going to notify this condition variable. We expect to
// time out.
BOOST_TEST(condition.timed_wait(lock, xt) == false);
BOOST_TEST(lock);
// Test the lock, unlock and timedlock methods.
lock.unlock();
BOOST_TEST(!lock);
lock.lock();
BOOST_TEST(lock);
lock.unlock();
BOOST_TEST(!lock);
BOOST_TEST(boost::xtime_get(&xt, boost::TIME_UTC) == boost::TIME_UTC);
xt.nsec += 100000000;
BOOST_TEST(lock.timed_lock(xt));
}
void test_mutex()
{
typedef boost::mutex mutex;
test_lock<mutex>();
}
void test_try_mutex()
{
typedef boost::try_mutex mutex;
test_lock<mutex>();
test_trylock<mutex>();
}
void test_timed_mutex()
{
typedef boost::timed_mutex mutex;
test_lock<mutex>();
test_trylock<mutex>();
test_timedlock<mutex>();
}
void test_recursive_mutex()
{
typedef boost::recursive_mutex mutex;
test_lock<mutex>();
mutex mx;
mutex::scoped_lock lock1(mx);
mutex::scoped_lock lock2(mx);
}
void test_recursive_try_mutex()
{
typedef boost::recursive_try_mutex mutex;
test_lock<mutex>();
test_trylock<mutex>();
mutex mx;
mutex::scoped_lock lock1(mx);
mutex::scoped_lock lock2(mx);
}
void test_recursive_timed_mutex()
{
typedef boost::recursive_timed_mutex mutex;
test_lock<mutex>();
test_trylock<mutex>();
test_timedlock<mutex>();
mutex mx;
mutex::scoped_lock lock1(mx);
mutex::scoped_lock lock2(mx);
}
struct condition_test_data
{
condition_test_data() : notified(0), awoken(0) { }
boost::mutex mutex;
boost::condition condition;
int notified;
int awoken;
};
void condition_test_thread(void* param)
{
condition_test_data* data = static_cast<condition_test_data*>(param);
boost::mutex::scoped_lock lock(data->mutex);
BOOST_TEST(lock);
while (!(data->notified > 0))
data->condition.wait(lock);
BOOST_TEST(lock);
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;
};
void test_condition_notify_one()
{
condition_test_data data;
boost::thread thread(thread_adapter(&condition_test_thread, &data));
{
boost::mutex::scoped_lock lock(data.mutex);
BOOST_TEST(lock);
data.notified++;
data.condition.notify_one();
}
thread.join();
BOOST_TEST(data.awoken == 1);
}
void test_condition_notify_all()
{
const int NUMTHREADS = 5;
boost::thread_group threads;
condition_test_data data;
for (int i = 0; i < NUMTHREADS; ++i)
threads.create_thread(thread_adapter(&condition_test_thread, &data));
{
boost::mutex::scoped_lock lock(data.mutex);
BOOST_TEST(lock);
data.notified++;
data.condition.notify_all();
}
threads.join_all();
BOOST_TEST(data.awoken == NUMTHREADS);
}
struct cond_predicate
{
cond_predicate(int& var, int val) : _var(var), _val(val) { }
bool operator()() { return _var == _val; }
int& _var;
int _val;
};
void condition_test_waits(void* param)
{
condition_test_data* data = static_cast<condition_test_data*>(param);
boost::mutex::scoped_lock lock(data->mutex);
BOOST_TEST(lock);
// Test wait.
while (data->notified != 1)
data->condition.wait(lock);
BOOST_TEST(lock);
BOOST_TEST(data->notified == 1);
data->awoken++;
data->condition.notify_one();
// Test predicate wait.
data->condition.wait(lock, cond_predicate(data->notified, 2));
BOOST_TEST(lock);
BOOST_TEST(data->notified == 2);
data->awoken++;
data->condition.notify_one();
// Test timed_wait.
boost::xtime xt;
BOOST_TEST(boost::xtime_get(&xt, boost::TIME_UTC) == boost::TIME_UTC);
xt.nsec += 100000000;
while (data->notified != 3)
data->condition.timed_wait(lock, xt);
BOOST_TEST(lock);
BOOST_TEST(data->notified == 3);
data->awoken++;
data->condition.notify_one();
// Test predicate timed_wait.
BOOST_TEST(boost::xtime_get(&xt, boost::TIME_UTC) == boost::TIME_UTC);
xt.sec += 2;
BOOST_TEST(data->condition.timed_wait(lock, xt, cond_predicate(data->notified, 4)));
BOOST_TEST(lock);
BOOST_TEST(data->notified == 4);
data->awoken++;
}
void test_condition_waits()
{
condition_test_data data;
boost::thread thread(thread_adapter(&condition_test_waits, &data));
boost::xtime xt;
{
boost::mutex::scoped_lock lock(data.mutex);
BOOST_TEST(lock);
BOOST_TEST(boost::xtime_get(&xt, boost::TIME_UTC) == boost::TIME_UTC);
xt.sec += 1;
boost::thread::sleep(xt);
data.notified++;
data.condition.notify_one();
while (data.awoken != 1)
data.condition.wait(lock);
BOOST_TEST(data.awoken == 1);
BOOST_TEST(boost::xtime_get(&xt, boost::TIME_UTC) == boost::TIME_UTC);
xt.sec += 1;
boost::thread::sleep(xt);
data.notified++;
data.condition.notify_one();
while (data.awoken != 2)
data.condition.wait(lock);
BOOST_TEST(data.awoken == 2);
BOOST_TEST(boost::xtime_get(&xt, boost::TIME_UTC) == boost::TIME_UTC);
xt.sec += 1;
boost::thread::sleep(xt);
data.notified++;
data.condition.notify_one();
while (data.awoken != 3)
data.condition.wait(lock);
BOOST_TEST(data.awoken == 3);
}
BOOST_TEST(boost::xtime_get(&xt, boost::TIME_UTC) == boost::TIME_UTC);
xt.sec += 1;
boost::thread::sleep(xt);
data.notified++;
data.condition.notify_one();
BOOST_TEST(boost::xtime_get(&xt, boost::TIME_UTC) == boost::TIME_UTC);
xt.sec += 1;
boost::thread::sleep(xt);
thread.join();
BOOST_TEST(data.awoken == 4);
// Insure it's in a range instead of checking actual equality due to time lapse
BOOST_CHECK(xtime_in_range(xt, -1, 0));
}
void test_condition()
void test_creation()
{
test_condition_notify_one();
test_condition_notify_all();
test_condition_waits();
test_value = 0;
boost::thread thrd(&simple_thread);
thrd.join();
BOOST_CHECK_EQUAL(test_value, 999);
}
boost::mutex tss_mutex;
int tss_instances = 0;
struct tss_value_t
void test_comparison()
{
tss_value_t()
{
boost::mutex::scoped_lock lock(tss_mutex);
++tss_instances;
value = 0;
}
~tss_value_t()
{
boost::mutex::scoped_lock lock(tss_mutex);
--tss_instances;
}
int value;
};
boost::thread_specific_ptr<tss_value_t> tss_value;
void test_tss_thread()
{
tss_value.reset(new tss_value_t());
for (int i=0; i<1000; ++i)
{
int& n = tss_value->value;
BOOST_TEST(n == i);
++n;
}
boost::thread self;
boost::thread thrd(thread_adapter(comparison_thread, self));
thrd.join();
}
void test_tss()
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
const int NUMTHREADS=5;
boost::thread_group threads;
for (int i=0; i<NUMTHREADS; ++i)
threads.create_thread(&test_tss_thread);
threads.join_all();
BOOST_TEST(tss_instances == 0);
}
boost::unit_test_framework::test_suite* test = BOOST_TEST_SUITE("Boost.Threads: thread test suite");
int once_value = 0;
boost::once_flag once = BOOST_ONCE_INIT;
test->add(BOOST_TEST_CASE(test_sleep));
test->add(BOOST_TEST_CASE(test_creation));
test->add(BOOST_TEST_CASE(test_comparison));
void init_once_value()
{
once_value++;
}
void test_once_thread()
{
boost::call_once(&init_once_value, once);
}
void test_once()
{
const int NUMTHREADS=5;
boost::thread_group threads;
for (int i=0; i<NUMTHREADS; ++i)
threads.create_thread(&test_once_thread);
threads.join_all();
BOOST_TEST(once_value == 1);
}
int test_main(int, char*[])
{
test_mutex();
test_try_mutex();
test_timed_mutex();
test_recursive_mutex();
test_recursive_try_mutex();
test_recursive_timed_mutex();
test_condition();
test_tss();
test_once();
return 0;
return test;
}

View File

@@ -0,0 +1,44 @@
#include <boost/thread/thread.hpp>
#include <boost/thread/xtime.hpp>
#include <boost/test/test_tools.hpp>
#include <utils.inl>
namespace {
int test_value;
void simple_thread()
{
test_value = 999;
}
void test_create_thread()
{
test_value = 0;
boost::thread_group thrds;
BOOST_TEST(thrds.create_thread(&simple_thread) != 0);
thrds.join_all();
BOOST_TEST(test_value == 999);
}
void test_add_find_remove()
{
test_value = 0;
boost::thread_group thrds;
boost::thread* pthread = new boost::thread(&simple_thread);
thrds.add_thread(pthread);
BOOST_TEST(thrds.find(*pthread) == pthread);
thrds.remove_thread(pthread);
BOOST_TEST(thrds.find(*pthread) == 0);
pthread->join();
BOOST_TEST(test_value == 999);
}
} // namespace
void test_thread_group()
{
test_create_thread();
test_add_find_remove();
}

258
test/test_thread_pool.cpp Normal file
View File

@@ -0,0 +1,258 @@
#include <boost/thread/thread.hpp>
#include <boost/thread/xtime.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/thread_pool.hpp>
#include <boost/test/test_tools.hpp>
const int MAX_POOL_THREADS=8;
const int MIN_POOL_THREADS=2;
const int POOL_TIMEOUT = 2; // seconds
const int ITERATIONS=25;
boost::mutex detach_prot;
boost::condition detached;
boost::condition waiting_for_detach;
int at_detach=0;
bool pool_detached=false;
const int DETACH_THREADS=2;
// Constant to cause the cpubound thread to take approx 0.5 seconds
// to complete. Doesn't have to be exact, but should take "a while"
const double SQRT_PER_SECOND=3000000.0;
enum
{
CHATTY_WORKER,
FAST_WORKER,
SLOW_WORKER,
CPUBOUND_WORKER,
WORKER_TYPE_COUNT
};
int work_counts[WORKER_TYPE_COUNT];
class job_adapter
{
public:
job_adapter(void (*func)(void*), void* param)
: _func(func), _param(param){ }
void operator()() const { _func(_param); }
private:
void (*_func)(void*);
void* _param;
};
void chatty_worker()
{
work_counts[CHATTY_WORKER]++;
}
void fast_worker()
{
work_counts[FAST_WORKER]++;
}
void slow_worker()
{
boost::xtime xt;
boost::xtime_get(&xt,boost::TIME_UTC);
xt.sec++;
boost::thread::sleep(xt);
work_counts[SLOW_WORKER]++;
}
void cpubound_worker()
{
double d;
double limit = SQRT_PER_SECOND/2.0;
for(d = 1.0; d < limit; d+=1.0)
{
sqrt(d);
}
work_counts[CPUBOUND_WORKER]++;
}
struct recursive_args
{
boost::thread_pool *ptp;
int count;
};
void recursive_worker(void *arg)
{
recursive_args *pargs = static_cast<recursive_args *>(arg);
if(--pargs->count > 0)
pargs->ptp->add(job_adapter(recursive_worker,pargs));
}
void detach_worker(void *arg)
{
int detach_threads = reinterpret_cast<int>(arg);
boost::mutex::scoped_lock l(detach_prot);
// If we are the Nth thread to reach this, notify
// our caller that everyone is ready to detach!
if(++at_detach==detach_threads)
waiting_for_detach.notify_all();
while(!pool_detached)
detached.wait(l);
// Call slow worker to do a bit of work after this...
slow_worker();
}
// Test a thread_pool with all different sorts of workers
void test_heterogeneous()
{
memset(work_counts,0,sizeof(work_counts));
boost::thread_pool tp(MAX_POOL_THREADS,MIN_POOL_THREADS,POOL_TIMEOUT);
for(int i = 0; i < ITERATIONS; i++)
{
tp.add(&chatty_worker);
tp.add(&fast_worker);
tp.add(&slow_worker);
tp.add(&cpubound_worker);
}
tp.join();
BOOST_TEST(work_counts[CHATTY_WORKER] == ITERATIONS);
BOOST_TEST(work_counts[FAST_WORKER] == ITERATIONS);
BOOST_TEST(work_counts[SLOW_WORKER] == ITERATIONS);
BOOST_TEST(work_counts[CPUBOUND_WORKER] == ITERATIONS);
}
void test_recursive()
{
recursive_args ra;
boost::thread_pool tp;
ra.ptp = &tp;
ra.count = ITERATIONS;
// Recursive_worker will add another job to the queue before returning
tp.add(job_adapter(recursive_worker,static_cast<void *>(&ra)));
// busy wait for bottom to be reached.
while(ra.count > 0)
boost::thread::yield();
tp.join();
BOOST_TEST(ra.count == 0);
}
// Test cancellation of thread_pool operations.
void test_cancel()
{
int wc_after_cancel[WORKER_TYPE_COUNT];
memset(work_counts,0,sizeof(work_counts));
boost::thread_pool tp(MAX_POOL_THREADS,MIN_POOL_THREADS,POOL_TIMEOUT);
for(int i = 0; i < ITERATIONS; i++)
{
tp.add(&chatty_worker);
tp.add(&fast_worker);
tp.add(&slow_worker);
tp.add(&cpubound_worker);
}
tp.cancel();
// Save our worker counts
memcpy(wc_after_cancel,work_counts,sizeof(wc_after_cancel));
// Do a bit more work to prove we can continue after a cancel
tp.add(&chatty_worker);
tp.add(&fast_worker);
tp.add(&slow_worker);
tp.add(&cpubound_worker);
tp.join();
// Check our counts
// As long as ITERATIONS is decently sized, there is no way
// these tasks could have completed before the cancel...
BOOST_TEST(wc_after_cancel[SLOW_WORKER] < ITERATIONS);
BOOST_TEST(wc_after_cancel[CPUBOUND_WORKER] < ITERATIONS);
// Since they could not have completed, if we are processing jobs
// in a FIFO order, the others can't have completed either.
BOOST_TEST(wc_after_cancel[CHATTY_WORKER] < ITERATIONS);
BOOST_TEST(wc_after_cancel[FAST_WORKER] < ITERATIONS);
// Check to see that more work was accomplished after the cancel.
BOOST_TEST(wc_after_cancel[SLOW_WORKER] < work_counts[SLOW_WORKER]);
BOOST_TEST(wc_after_cancel[CPUBOUND_WORKER] < work_counts[CPUBOUND_WORKER]);
BOOST_TEST(wc_after_cancel[CHATTY_WORKER] < work_counts[CHATTY_WORKER]);
BOOST_TEST(wc_after_cancel[FAST_WORKER] < work_counts[FAST_WORKER]);
}
void test_detach()
{
int wc_after_detach;
memset(work_counts,0,sizeof(work_counts));
{
boost::mutex::scoped_lock l(detach_prot);
// For detach testing, we want a known size thread pool so that we can make a better guess
// at when the detached process will finish
boost::thread_pool tp(DETACH_THREADS,0);
for(int i = 0; i < DETACH_THREADS; i++)
{
tp.add(job_adapter(detach_worker,reinterpret_cast<void *>(DETACH_THREADS)));
}
// Wait for all of the threads to reach a known point
waiting_for_detach.wait(l);
tp.detach();
wc_after_detach = work_counts[SLOW_WORKER];
// Let our threads know we've detached.
pool_detached = true;
detached.notify_all();
}
// Our detached threads should finish approx 1 sec after this.
// We could reliably sync. with the exit of detach_worker, but we
// can't reliably sync. with the cleanup of the thread_pool harness,
// so for the purposes of this test, we'll sleep 3 secs, and check some values.
boost::xtime xt;
boost::xtime_get(&xt,boost::TIME_UTC);
xt.sec += 3;
boost::thread::sleep(xt);
// Work should still complete after detach
BOOST_TEST(work_counts[SLOW_WORKER] == DETACH_THREADS);
// None of the work should have occurred before attach.
BOOST_TEST(0 == wc_after_detach);
}
void test_thread_pool()
{
test_heterogeneous();
test_recursive();
test_cancel();
test_detach();
}

59
test/test_tss.cpp Normal file
View File

@@ -0,0 +1,59 @@
#include <boost/thread/tss.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include <boost/test/unit_test.hpp>
namespace
{
boost::mutex tss_mutex;
int tss_instances = 0;
struct tss_value_t
{
tss_value_t()
{
boost::mutex::scoped_lock lock(tss_mutex);
++tss_instances;
value = 0;
}
~tss_value_t()
{
boost::mutex::scoped_lock lock(tss_mutex);
--tss_instances;
}
int value;
};
boost::thread_specific_ptr<tss_value_t> tss_value;
void test_tss_thread()
{
tss_value.reset(new tss_value_t());
for (int i=0; i<1000; ++i)
{
int& n = tss_value->value;
BOOST_CHECK_EQUAL(n, i);
++n;
}
}
}
void test_tss()
{
const int NUMTHREADS=5;
boost::thread_group threads;
for (int i=0; i<NUMTHREADS; ++i)
threads.create_thread(&test_tss_thread);
threads.join_all();
BOOST_CHECK_EQUAL(tss_instances, 0);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test = BOOST_TEST_SUITE("Boost.Threads: tss test suite");
test->add(BOOST_TEST_CASE(test_tss));
return test;
}

50
test/test_xtime.cpp Normal file
View File

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

37
test/utils.inl Normal file
View File

@@ -0,0 +1,37 @@
#include <boost/thread/xtime.hpp>
namespace {
#if defined(BOOST_NO_INT64_T)
typedef boost::int_fast32_t sec_type;
#else
typedef boost::int_fast64_t sec_type;
#endif
typedef boost::int_fast32_t nsec_type;
static void xtime_get(boost::xtime& xt, sec_type secs, nsec_type nsecs=0)
{
boost::xtime_get(&xt, boost::TIME_UTC);
xt.sec += secs;
xt.nsec += nsecs;
}
static int xtime_cmp(const boost::xtime& xt1, const boost::xtime& xt2)
{
int cmp = (int)(xt1.sec - xt2.sec);
if (cmp == 0)
cmp = (int)(xt1.nsec - xt2.nsec);
return cmp;
}
static bool xtime_in_range(const boost::xtime& xt, sec_type min, sec_type max)
{
boost::xtime xt_min, xt_max;
boost::xtime_get(&xt_min, boost::TIME_UTC);
xt_max = xt_min;
xt_min.sec += min;
xt_max.sec += max;
return (xtime_cmp(xt, xt_min) >= 0) && (xtime_cmp(xt, xt_max) <= 0);
}
} // namespace

2
tutorial/.cvsignore Normal file
View File

@@ -0,0 +1,2 @@
bin
*.pdb

30
tutorial/Jamfile Normal file
View File

@@ -0,0 +1,30 @@
# (C) Copyright William E. Kempf 2001. Permission to copy, use, modify, sell and
# distribute this software is granted provided this copyright notice appears
# in all copies. This software is provided "as is" without express or implied
# warranty, and with no claim as to its suitability for any purpose.
#
# Declare the location of this subproject relative to the root.
subproject libs/thread/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 <lib>../build/boost_thread <lib>../../test/build/unit_test_framework $(threadmon)
## requirements ##
:
## default build ##
: release <runtime-link>static
;
exe helloworld : <template>tutorial helloworld.cpp ;
exe helloworld2 : <template>tutorial helloworld2.cpp ;
exe helloworld3 : <template>tutorial helloworld3.cpp ;
exe factorial : <template>tutorial factorial.cpp ;
exe factorial2 : <template>tutorial factorial2.cpp ;

26
tutorial/factorial.cpp Normal file
View File

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

26
tutorial/factorial2.cpp Normal file
View File

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

13
tutorial/helloworld.cpp Normal file
View File

@@ -0,0 +1,13 @@
#include <boost/thread/thread.hpp>
#include <iostream>
void helloworld()
{
std::cout << "Hello World!" << std::endl;
}
int main()
{
boost::thread thrd(&helloworld);
thrd.join();
}

15
tutorial/helloworld2.cpp Normal file
View File

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

14
tutorial/helloworld3.cpp Normal file
View File

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