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

Compare commits

..

1 Commits

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

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

View File

@@ -1,11 +1,17 @@
# (C) Copyright William E. Kempf 2001. Permission to copy, use, modify, # (C) Copyright William E. Kempf 2001. Permission to copy, use, modify, sell and
# sell and distribute this software is granted provided this copyright # distribute this software is granted provided this copyright notice appears
# notice appears in all copies. This software is provided "as is" without # in all copies. This software is provided "as is" without express or implied
# express or implied warranty, and with no claim as to its suitability for # warranty, and with no claim as to its suitability for any purpose.
# any purpose.
# #
# Boost.Threads build Jamfile # Boost.Threads build Jamfile
# #
# Declares the following targets:
# 1. libboost_thread, a static link library.
# 1a. On Win32 (when PTW32 is not defined), a dynamic link library
# boost_threadmon, which must be used in conjunction with
# libboost_thread. Note that this DLL *must* be used through static
# linking to the import library. Dynamic loading will cause undefined
# behavior.
# Additional configuration variables used: # Additional configuration variables used:
# 1. PTW32 may be used on Win32 platforms to specify that the pthreads-win32 # 1. PTW32 may be used on Win32 platforms to specify that the pthreads-win32
# library should be used instead of "native" threads. This feature is # library should be used instead of "native" threads. This feature is
@@ -25,29 +31,40 @@ subproject libs/thread/build ;
SEARCH on <module@>threads.jam = $(SUBDIR) ; SEARCH on <module@>threads.jam = $(SUBDIR) ;
include <module@>threads.jam ; include <module@>threads.jam ;
#######################
# Conditionally declare the Boost.Threads dynamic link library boost_threadmon.
if $(NT) && ! $(PTW32)
{ {
template thread_libs dll boost_threadmon
## sources ## : ../src/threadmon.cpp
: <template>thread_base : <sysinclude>$(BOOST_ROOT)
## requirements ## <threading>multi
: : debug release <runtime-link>static/dynamic
## default build ##
: debug release
;
# Base names of the source files for libboost_thread.
CPP_SOURCES = condition mutex recursive_mutex thread tss xtime once
exceptions threadmon ;
dll boost_thread
: <template>thread_libs ../src/$(CPP_SOURCES).cpp
: <define>BOOST_THREAD_BUILD_DLL=1
;
stage bin-stage
: <dll>boost_thread
: #<tag><runtime-link-static>"s"
<tag><debug>"d"
: debug release
; ;
} }
#######################
# Declare the Boost.Threads static link library libboost_thread.
# Base names of the source files for libboost_thread.
CPP_SOURCES =
condition mutex recursive_mutex thread tss xtime once exceptions ;
lib boost_thread
: ../src/$(CPP_SOURCES).cpp
: <sysinclude>$(BOOST_ROOT)
<threading>multi
$(pthreads-win32)
: debug release <runtime-link>static/dynamic
;
#######################
# Stage the generated targets.
#stage bin-stage
# : <lib>boost_thread $(threadmon)
# : <tag><runtime-link-static>"s"
# <tag><debug>"d"
# : debug release <runtime-link>static/dynamic
#;

View File

@@ -1,12 +0,0 @@
# Declare the uses system library
lib pthread : : <name>pthread ;
project boost/thread
: source-location ../src
: usage-requirements <library>pthread
;
CPP_SOURCES = condition mutex recursive_mutex thread tss xtime once exceptions ;
lib boost_thread : $(CPP_SOURCES).cpp ;

View File

@@ -1,29 +1,23 @@
# Do some OS-specific setup # Do some OS-specific setup
threadmon = ;
pthreads-win32 = ;
if $(NT)
{ {
pthreads-win32 = ; if $(PTW32)
if $(NT)
{ {
if $(PTW32) local install-path = $(PTW32[1]) ;
{ local lib = $(PTW32[2]) ;
local install-path = $(PTW32[1]) ; pthreads-win32 =
local lib = $(PTW32[2]) ; <define>BOOST_HAS_PTHREADS
pthreads-win32 = <define>PtW32NoCatchWarn
<define>BOOST_HAS_PTHREADS <include>$(install-path)/pre-built/include
<define>PtW32NoCatchWarn <library-file>$(install-path)/pre-built/lib/$(lib)
<include>$(install-path)/pre-built/include ;
<library-file>$(install-path)/pre-built/lib/$(lib)
;
}
} }
else
template thread_base {
## sources ## threadmon = <dll>../build/boost_threadmon ;
: }
## requirements ## }
: <sysinclude>$(BOOST_ROOT) <threading>multi $(pthreads-win32)
<borland><*><cxxflags>-w-8004
## default build ##
:
;
}

Binary file not shown.

View File

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

View File

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

View File

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

View File

@@ -7,11 +7,11 @@
<body link="#0000ff" vlink="#800080"> <body link="#0000ff" vlink="#800080">
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary= <table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
"header"> "header">
<tr> <tr>
<td valign="top" width="300"> <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> <h3><a href="../../../index.htm"><img height="86" width="277" alt="C++ Boost" src="../../../c++boost.gif" border="0"></a></h3>
</td> </td>
<td valign="top"> <td valign="top">
<h1 align="center">Boost.Threads</h1> <h1 align="center">Boost.Threads</h1>
<h2 align="center">Header &lt;<a href="../../../boost/thread/condition.hpp">boost/thread/condition.hpp</a>&gt;</h2> <h2 align="center">Header &lt;<a href="../../../boost/thread/condition.hpp">boost/thread/condition.hpp</a>&gt;</h2>
</td> </td>
@@ -19,16 +19,16 @@
</table> </table>
<hr> <hr>
<h2>Contents</h2> <h2>Contents</h2>
<dl class="page-index"> <dl class="page-index">
<dt><a href="#introduction">Introduction</a></dt> <dt><a href="#introduction">Introduction</a></dt>
<dt><a href="#classes">Classes</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> <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-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> 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> functions</a></dt>
</dl> </dl>
</dl> </dl>
@@ -36,34 +36,35 @@
</dl> </dl>
<hr> <hr>
<h2><a name="introduction"></a>Introduction</h2> <h2><a name="introduction"></a>Introduction</h2>
<p>Include the header &lt;<a href="../../../boost/thread/condition.hpp">boost/thread/condition.hpp</a>&gt; <p>Include the header &lt;<a href="../../../boost/thread/condition.hpp">boost/thread/condition.hpp</a>&gt;
to define the class condition.</p> to define the class condition.</p>
<h2><a name="classes"></a>Classes</h2> <h2><a name="classes"></a>Classes</h2>
<h3><a name="class-condition"></a>Class <code>condition</code></h3> <h3><a name="class-condition"></a>Class <code>condition</code></h3>
<p>An object of class <code>condition</code> is a synchronization primitive used <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) 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 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> 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 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 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 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> 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 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 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 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> is performed automatically by the <code> condition</code> object&#39;s <code>wait</code>
functions.</p> functions.</p>
<p>The <code>condition</code> type is often used to implement the <i> Monitor <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 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 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> 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 <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>. states <a href="definitions.html#state"> blocked</a> and <a href="definitions.html#state">ready</a>.
Note that &quot;waiting&quot; is a synonym for blocked.</p> Note that &quot;waiting&quot; is a synonym for blocked.</p>
<h4><a name="class-condition-synopsis"></a>Class <code>condition</code> synopsis</h4> <h4><a name="class-condition-synopsis"></a>Class <code>condition</code> synopsis</h4>
<pre>namespace boost <pre>
namespace boost
{ {
class condition : private <a href="../../utility/utility.htm#Class_noncopyable">boost::noncopyable</a> // Exposition only. class condition : private <a href="../../utility/utility.htm#Class noncopyable">boost::noncopyable</a> // Exposition only.
// Class condition meets the <a href="overview.html#non-copyable">NonCopyable</a> requirement. // Class condition meets the <a href="overview.html#non-copyable">NonCopyable</a> requirement.
{ {
public: public:
@@ -83,94 +84,103 @@
}; };
}; };
</pre> </pre>
<h4><a name="class-condition-ctors"></a>Class <code>condition</code> constructors <h4><a name="class-condition-ctors"></a>Class <code>condition</code> constructors
and destructor</h4> and destructor</h4>
<pre>condition(); <pre>
condition();
</pre> </pre>
<dl class="function-semantics"> <dl class="function-semantics">
<dt><b>Effects:</b> Constructs a <code>condition</code> object.</dt> <dt><b>Effects:</b> Constructs a <code>condition</code> object.</dt>
</dl> </dl>
<pre>~condition(); <pre>
~condition();
</pre> </pre>
<dl class="function-semantics"> <dl class="function-semantics">
<dt><b>Effects:</b> Destroys <code>*this</code>.</dt> <dt><b>Effects:</b> Destroys <code>*this</code>.</dt>
</dl> </dl>
<h4><a name="class-condition-modifiers"></a>Class <code>condition</code> modifier <h4><a name="class-condition-modifiers"></a>Class <code>condition</code> modifier
functions</h4> functions</h4>
<pre>void notify_one(); <pre>
void notify_one();
</pre> </pre>
<dl class="function-semantics"> <dl class="function-semantics">
<dt><b>Effects:</b> If there is a thread waiting on <code>*this</code>, change <dt><b>Effects:</b> If there is a thread waiting on <code>*this</code>, change
that thread&#39;s state to ready. Otherwise there is no effect.</dt> 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 <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 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 thread must still acquire the mutex again (which occurs within the call to
one of the <code>condition</code> object's wait functions).</dt> one of the <code>condition</code> object's wait functions).</dt>
</dl> </dl>
<pre>void notify_all(); <pre>
void notify_all();
</pre> </pre>
<dl class="function-semantics"> <dl class="function-semantics">
<dt><b>Effects:</b> Change the state of all threads waiting on <code> *this</code> <dt><b>Effects:</b> Change the state of all threads waiting on <code> *this</code>
to ready. If there are no waiting threads, <code> notify_all()</code> has to ready. If there are no waiting threads, <code> notify_all()</code> has
no effect.</dt> no effect.</dt>
</dl> </dl>
<pre>template &lt;typename ScopedLock&gt; <pre>
template &lt;typename ScopedLock&gt;
void wait(ScopedLock&amp; lock); void wait(ScopedLock&amp; lock);
</pre> </pre>
<dl class="function-semantics"> <dl class="function-semantics">
<dt><b>Requires:</b> <code>ScopedLock</code> meets the <a href="lock_concept.html#ScopedLock">ScopedLock</a> <dt><b>Requires:</b> <code>ScopedLock</code> meets the <a href="lock_concept.html#ScopedLock">ScopedLock</a>
requirements.</dt> requirements.</dt>
<dt><b>Effects:</b> Releases the lock on the <a href="mutex_concept.html">mutex <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 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 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> <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> if <code>!lock.locked()</code></dt>
<dt><b>Danger:</b> This version should always be used within a loop checking <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 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 true. Without the loop, race conditions can ensue due to possible &quot;spurious
wake ups&quot;. The second version encapsulates this loop idiom internally wake ups&quot;. The second version encapsulates this loop idiom internally
and is generally the preferred method.</dt> and is generally the preferred method.</dt>
</dl> </dl>
<pre>Template&lt;typename ScopedLock, typename Pr&gt; <pre>
Template&lt;typename ScopedLock, typename Pr&gt;
void wait(ScopedLock&amp; lock, Pr pred); void wait(ScopedLock&amp; lock, Pr pred);
</pre> </pre>
<dl class="function-semantics"> <dl class="function-semantics">
<dt><b>Requires:</b> <code>ScopedLock</code> meets the <a href="lock_concept.html#ScopedLock">ScopedLock</a> <dt><b>Requires:</b> <code>ScopedLock</code> meets the <a href="lock_concept.html#ScopedLock">ScopedLock</a>
requirements, return from <code>pred()</code> convertible to bool.</dt> requirements, return from <code>pred()</code> convertible to bool.</dt>
<dt><b>Effects:</b> As if: <code>while (!pred()) wait(lock)</code></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> if <code>!lock.locked()</code></dt>
</dl> </dl>
<pre>template &lt;typename ScopedLock&gt; <pre>
template &lt;typename ScopedLock&gt;
bool timed_wait(ScopedLock&amp; lock, const <a href="xtime.html">xtime</a>&amp; XT); bool timed_wait(ScopedLock&amp; lock, const <a href="xtime.html">xtime</a>&amp; XT);
</pre> </pre>
<dl class="function-semantics"> <dl class="function-semantics">
<dt><b>Requires:</b> <code>ScopedLock</code> meets the <a href="lock_concept.html#ScopedLock">ScopedLock</a> <dt><b>Requires:</b> <code>ScopedLock</code> meets the <a href="lock_concept.html#ScopedLock">ScopedLock</a>
requirements.</dt> requirements.</dt>
<dt><b>Effects:</b> Releases the lock on the <a href="mutex_concept.html">mutex <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 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> 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 or <code> this-&gt;notify_all()</code>, or until <code>XT</code>, and then
reacquires the lock.</dt> 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> <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> if <code>!lock.locked()</code></dt>
<dt><b>Danger:</b> This version should always be used within a loop checking <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 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 true. Without the loop, race conditions can ensue due to &quot;spurious wake
ups&quot;. The second version encapsulates this loop idiom internally and ups&quot;. The second version encapsulates this loop idiom internally and
is generally the preferred method.</dt> is generally the preferred method.</dt>
</dl> </dl>
<pre>Template&lt;typename ScopedLock, typename Pr&gt; <pre>
Template&lt;typename ScopedLock, typename Pr&gt;
bool timed_wait(ScopedLock&amp; lock, const <a href="xtime.html">xtime</a>&amp; XT, Pr pred); bool timed_wait(ScopedLock&amp; lock, const <a href="xtime.html">xtime</a>&amp; XT, Pr pred);
</pre> </pre>
<dl class="function-semantics"> <dl class="function-semantics">
<dt><b>Requires:</b> <code>ScopedLock</code> meets the <a href="lock_concept.html#ScopedLock">ScopedLock</a> <dt><b>Requires:</b> <code>ScopedLock</code> meets the <a href="lock_concept.html#ScopedLock">ScopedLock</a>
requirements, return from <code>pred()</code> convertible to bool.</dt> requirements, return from <code>pred()</code> convertible to bool.</dt>
<dt><b>Effects:</b> As if:<br> <dt><b>Effects:</b> As if:<br>
<pre>while (!pred()) <pre>
while (!pred())
{ {
if (!timed_wait(lock, XT)) if (!timed_wait(lock, XT))
return false; return false;
@@ -178,15 +188,85 @@
return true; return true;
</pre> </pre>
</dt> </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> <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> if <code>!lock.locked()</code></dt>
</dl> </dl>
<h2><a name="examples"></a>Example(s)</h2> <h2><a name="examples"></a>Example(s)</h2>
<p><a href="../example/condition.cpp">libs/thread/example/condition.cpp</a></p> <pre>
#include &lt;iostream&gt;
#include &lt;vector&gt;
#include <a href="../../../boost/utility.hpp">&lt;boost/utility.hpp&gt;</a>
#include <a href="../../../boost/thread/condition.hpp">&lt;boost/thread/condition.hpp&gt;</a>
#include <a href="../../../boost/thread/thread.hpp">&lt;boost/thread/thread.hpp&gt;</a>
class bounded_buffer : private boost::noncopyable
{
public:
typedef boost::mutex::scoped_lock lock;
bounded_buffer(int n) : begin(0), end(0), buffered(0), circular_buf(n) { }
void send (int m) {
lock lk(monitor);
while (buffered == circular_buf.size())
buffer_not_full.wait(lk);
circular_buf[end] = m;
end = (end+1) % circular_buf.size();
++buffered;
buffer_not_empty.notify_one();
}
int receive() {
lock lk(monitor);
while (buffered == 0)
buffer_not_empty.wait(lk);
int i = circular_buf[begin];
begin = (begin+1) % circular_buf.size();
--buffered;
buffer_not_full.notify_one();
return i;
}
private:
int begin, end, buffered;
std::vector&lt;int&gt; circular_buf;
boost::condition buffer_not_full, buffer_not_empty;
boost::mutex monitor;
};
bounded_buffer buf(2);
void sender() {
int n = 0;
while (n &lt; 100) {
buf.send(n);
std::cout &lt;&lt; &quot;sent: &quot; &lt;&lt; n &lt;&lt; std::endl;
++n;
}
buf.send(-1);
}
void receiver() {
int n;
do {
n = buf.receive();
std::cout &lt;&lt; &quot;received: &quot; &lt;&lt; n &lt;&lt; std::endl;
} while (n != -1); // -1 indicates end of buffer
}
int main(int, char*[])
{
boost::thread thrd1(&amp;sender);
boost::thread thrd2(&amp;receiver);
thrd1.join();
thrd2.join();
return 0;
}
</pre>
<p>Typical output (dependent on scheduling policies) is:</p> <p>Typical output (dependent on scheduling policies) is:</p>
<pre>sent: 0 <pre>
sent: 0
sent: 1 sent: 1
received: 0 received: 0
received: 1 received: 1
@@ -197,16 +277,18 @@ received: 3
sent: 4 sent: 4
received: 4 received: 4
</pre> </pre>
<p>Revised <p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->09 January, 2003<!--webbot bot="Timestamp" endspan i-checksum="38582" --> <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
05 November, 2001
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p> </p>
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002. <p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
All Rights Reserved.</i></p> All Rights Reserved.</i></p>
<p>Permission to use, copy, modify, distribute and sell this software and its <p>Permission to use, copy, modify, distribute and sell this software and its
documentation for any purpose is hereby granted without fee, provided that the documentation for any purpose is hereby granted without fee, provided that the
above copyright notice appear in all copies and that both that copyright notice above copyright notice appear in all copies and that both that copyright notice
and this permission notice appear in supporting documentation. William E. Kempf and this permission notice appear in supporting documentation. William E. Kempf
makes no representations about the suitability of this software for any purpose. 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> It is provided &quot;as is&quot; without express or implied warranty.</p>
</body> </body>
</html> </html>

View File

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

View File

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

View File

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

View File

@@ -7,86 +7,87 @@
<body link="#0000ff" vlink="#800080"> <body link="#0000ff" vlink="#800080">
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary= <table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
"header"> "header">
<tr> <tr>
<td valign="top" width="300"> <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> <h3><a href="../../../index.htm"><img height="86" width="277" alt="C++ Boost" src="../../../c++boost.gif" border="0"></a></h3>
</td> </td>
<td valign="top"> <td valign="top">
<h1 align="center">Boost.Threads</h1> <h1 align="center">Boost.Threads</h1>
<h2 align="center">Frequently Asked Questions (FAQs)</h2> <h2 align="center">Frequently Asked Questions (FAQs)</h2>
</td> </td>
</tr> </tr>
</table> </table>
<hr> <hr>
<dl class="page-index"> <dl class="page-index">
<dt><a href="#question1">1. Are lock objects thread safe?</a></dt> <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> 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> (specific library name)?</a></dt>
<dt><a href="#question3">3. Why do mutexes have noncopyable semantics?</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> 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> 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> 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> variables?</a></dt>
<dt><a href="#question8">8. Why isn't thread cancellation or termination provided?</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> duration (stack) objects via pointers or references?</a></dt>
<dt><a href="#question10">10. Why has class semaphore disappeared?</a></dt> <dt><a href="#question10">10. Why has class semaphore disappeared?</a></dt>
</dl> </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> thread safe</a>?</h2>
<p><b>No!</b> Lock objects are not meant to be shared between threads. They are <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. 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 Any other usage is just likely to lead to errors and won&#39;t really be of
actual benefit any way. Share <a href= actual benefit any way. Share <a href=
"mutex_concept.html">mutexes</a>, not locks. For more information see "mutex_concept.html">mutexes</a>, not locks. For more information see
the <a href="rationale.html#lock_objects">rationale</a> behind the design for the <a href="rationale.html#lock_objects">rationale</a> behind the design for
lock objects.</p> 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> library name)?</h2>
<p>It wasn&#39;t. Boost.Threads was designed from scratch. Extensive design discussions <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 involved numerous people representing a wide range of experience across many
platforms. To ensure portability, the initial implements were done in parallel platforms. To ensure portability, the initial implements were done in parallel
using POSIX Threads and the Win32 threading API. But the Boost.Threads design 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> 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> library name)?</h2>
<p>Existing C++ libraries either seemed dangerous (often failing to take advantage <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 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, 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 and were also missing certain features. For instance, the WIN32 thread API lacks
condition variables, even though these are critical for the important Monitor condition variables, even though these are critical for the important Monitor
pattern <a href="bibliography.html#Schmidt-00">[Schmidt 00]</a>.</p> 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> have noncopyable semantics?</h2>
<p>To ensure that <a href="definitions.html#Deadlock">deadlocks</a> don&#39;t <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 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. 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 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 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 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 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> 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> 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 <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 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> 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> 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 <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 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 <b>good thing</b>, however, since the compiler generated operations would not
be <a href= be <a href=
"definitions.html#Thread-safe">thread-safe</a>. The following is a simple "definitions.html#Thread-safe">thread-safe</a>. The following is a simple
example of a class with copyable semantics and internal synchronization through example of a class with copyable semantics and internal synchronization through
a mutex member.</p> a mutex member.</p>
<pre>class counter <pre>
class counter
{ {
public: public:
// Doesn't need synchronization since there can be no references to *this // Doesn't need synchronization since there can be no references to *this
@@ -95,7 +96,7 @@ public:
: m_value(initial_value) : m_value(initial_value)
{ {
} }
// We only need to synchronize other for the same reason we don't have to // We only need to synchronize other for the same reason we don't have to
// synchronize on construction! // synchronize on construction!
counter(const counter&amp; other) counter(const counter&amp; other)
@@ -103,20 +104,20 @@ public:
boost::mutex::scoped_lock scoped_lock(other.m_mutex); boost::mutex::scoped_lock scoped_lock(other.m_mutex);
m_value = other.m_value; m_value = other.m_value;
} }
// For assignment we need to synchronize both objects! // For assignment we need to synchronize both objects!
const counter&amp; operator=(const counter&amp; other) const counter&amp; operator=(const counter&amp; other)
{ {
if (this == &amp;other) if (this == &amp;other)
return *this; return *this;
boost::mutex::scoped_lock lock1(&amp;m_mutex &lt; &amp;other.m_mutex ? m_mutex : other.m_mutex); 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); boost::mutex::scoped_lock lock2(&amp;m_mutex &gt; &amp;other.m_mutex ? m_mutex : other.m_mutex);
m_value = other.m_value; m_value = other.m_value;
return *this; return *this;
} }
int value() const int value() const
{ {
boost::mutex::scoped_lock scoped_lock(m_mutex); boost::mutex::scoped_lock scoped_lock(m_mutex);
@@ -127,54 +128,56 @@ public:
boost::mutex::scoped_lock scoped_lock(m_mutex); boost::mutex::scoped_lock scoped_lock(m_mutex);
return ++m_value; return ++m_value;
} }
private: private:
mutable boost::mutex m_mutex; mutable boost::mutex m_mutex;
int m_value; int m_value;
}; };
</pre> </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> 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 <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 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 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 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 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 mutex clearly differs from the logical state of an unlocked mutex). Declaring
a mutex member as mutable clearly documents the intended semantics.</p> a mutex member as mutable clearly documents the intended semantics.</p>
<h2><a name="question7"></a>7. Why supply <a href="condition.html">condition variables</a> <h2><a name="question7"></a>7. Why supply <a href="condition.html">condition variables</a>
rather than <a href="rationale.html#Events">event variables</a>?</h2> rather than <a href="rationale.html#Events">event variables</a>?</h2>
<p>Condition variables result in user code much less prone to <p>Condition variables result in user code much less prone to <a href=
<a href="definitions.html#definition-race-condition">race conditions</a> than event variables. "definitions.html#Race condition">race conditions</a> than event variables.
See <a href="rationale.html#Events">Rationale</a> for analysis. Also see <a href="bibliography.html#Hoare-74">[Hoare See <a href="rationale.html#Events">Rationale</a> for analysis. Also see <a href="bibliography.html#Hoare-74">[Hoare
74]</a> and <a href="bibliography.html#Schmidt-00">[Schmidt 00]</a>.</p> 74]</a> and <a href="bibliography.html#Schmidt-00">[Schmidt 00]</a>.</p>
<h2><a name="question8"></a>8. Why isn&#39;t thread cancellation or termination <h2><a name="question8"></a>8. Why isn&#39;t thread cancellation or termination
provided?</h2> provided?</h2>
<p>There&#39;s a valid need for thread termination, so at some point Boost.Threads <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) probably will include it, but only after we can find a truly safe (and portable)
mechanism for this concept.</p> 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> duration (stack) objects via pointers or references?</h2>
<p>Only if you can guarantee that the lifetime of the stack object will not end <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 while other threads might still access the object. Thus the safest practice
is to avoid sharing stack objects, particularly in designs where threads are is to avoid sharing stack objects, particularly in designs where threads are
created and destroyed dynamically. Restrict sharing of stack objects to simple created and destroyed dynamically. Restrict sharing of stack objects to simple
designs with very clear and unchanging function and thread lifetimes. (Suggested designs with very clear and unchanging function and thread lifetimes. (Suggested
by Darryl Green).</p> by Darryl Green).</p>
<h2><a name="question10"></a>10. Why has class semaphore disappeared?</h2> <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> greater safety by the combination of a mutex and a condition variable.</p>
<hr> <hr>
<p>Revised <p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->09 January, 2003<!--webbot bot="Timestamp" endspan i-checksum="38582" --> <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
05 November, 2001
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p> </p>
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002. <p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
All Rights Reserved.</i></p> All Rights Reserved.</i></p>
<p>Permission to use, copy, modify, distribute and sell this software and its <p>Permission to use, copy, modify, distribute and sell this software and its
documentation for any purpose is hereby granted without fee, provided that the documentation for any purpose is hereby granted without fee, provided that the
above copyright notice appear in all copies and that both that copyright notice above copyright notice appear in all copies and that both that copyright notice
and this permission notice appear in supporting documentation. William E. Kempf and this permission notice appear in supporting documentation. William E. Kempf
makes no representations about the suitability of this software for any purpose. 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> It is provided &quot;as is&quot; without express or implied warranty.</p>
</body> </body>
</html> </html>

View File

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

View File

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

View File

@@ -7,21 +7,21 @@
<body link="#0000ff" vlink="#800080"> <body link="#0000ff" vlink="#800080">
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary= <table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
"header"> "header">
<tr> <tr>
<td valign="top" width="300"> <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> <h3><a href="../../../index.htm"><img height="86" width="277" alt="C++ Boost" src="../../../c++boost.gif" border="0"></a></h3>
</td> </td>
<td valign="top"> <td valign="top">
<h1 align="center">Boost.Threads</h1> <h1 align="center">Boost.Threads</h1>
<h2 align="center">ScopedLock Concept</h2> <h2 align="center">ScopedLock Concept</h2>
</td> </td>
</tr> </tr>
</table> </table>
<hr> <hr>
<dl class="page-index"> <dl class="page-index">
<dt><a href="#introduction">Introduction</a></dt> <dt><a href="#introduction">Introduction</a></dt>
<dt><a href="#concept-requirements">Concept Requirements</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="#Lock-concept">Lock Concept</a></dt>
<dt><a href="#ScopedLock-concept">ScopedLock Concept</a></dt> <dt><a href="#ScopedLock-concept">ScopedLock Concept</a></dt>
<dt><a href="#ScopedTryLock-concept">ScopedTryLock Concept</a></dt> <dt><a href="#ScopedTryLock-concept">ScopedTryLock Concept</a></dt>
@@ -29,166 +29,166 @@
</dl> </dl>
</dl> </dl>
<h2><a name="introduction"></a>Introduction</h2> <h2><a name="introduction"></a>Introduction</h2>
<p>A lock object provides a safe means for locking and unlocking a mutex object <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 (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 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. 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> The <a href="#ScopedLock-concept">ScopedLock</a> concept, with <a href="#ScopedTryLock-concept">ScopedTryLock</a>
and <a href="#ScopedTimedLock-concept">ScopedTimedLock</a> refinements, formalize and <a href="#ScopedTimedLock-concept">ScopedTimedLock</a> refinements, formalize
the requirements.</p> the requirements.</p>
<p>Lock objects are constructed with a reference to a mutex object and typically <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 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 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 functions to query the lock status and to manually lock and unlock the mutex
object.</p> object.</p>
<p>Lock objects are meant to be short lived, expected to be used at block scope <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>. 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 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 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> this reason a lock object should never be shared between multiple threads.</p>
<h2><a name="concept-requirements"></a>Concept Requirements</h2> <h2><a name="concept-requirements"></a>Concept Requirements</h2>
<h3><a name="Lock-concept"></a>Lock Concept</h3> <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 <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 <code>clk</code> of that type, the following expressions must be well-formed
and have the indicated effects.</p> and have the indicated effects.</p>
<table summary="Lock expressions" border="1" cellpadding="5"> <table summary="Lock expressions" border="1" cellpadding="5">
<tr> <tr>
<td><b>Expression</b></td> <td><b>Expression</b></td>
<td><b>Effects</b></td> <td><b>Effects</b></td>
</tr> </tr>
<tr> <tr>
<td valign="top"><code>(&amp;lk)-&gt;~L();</code></td> <td valign="top"><code>(&amp;lk)-&gt;~L();</code></td>
<td><code>if (locked()) unlock();</code></td> <td><code>if (locked()) unlock();</code></td>
</tr> </tr>
<tr> <tr>
<td valign="top"><code>(&amp;clk)-&gt;operator const void*()</code></td> <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> locked by <code>clk</code>, otherwise 0.</td>
</tr> </tr>
<tr> <tr>
<td valign="top"><code>clk.locked()</code></td> <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> != 0</code></td>
</tr> </tr>
<tr> <tr>
<td valign="top"><code>lk.lock()</code></td> <td valign="top"><code>lk.lock()</code></td>
<td>Throws <code>lock_error</code> if <code>locked()</code>. If the associated <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 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 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 associated mutex is unlocked, after which the current thread is placed in
the <a href="definitions.html#State"> Ready</a> state, eventually to be 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 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 associated mutex object is already locked by the same thread the behavior
is dependent on the <a href="mutex_concept.html#locking-strategies">locking is dependent on the <a href="mutex_concept.html#locking-strategies">locking
strategy</a> of the associated mutex object.<br> strategy</a> of the associated mutex object.<br>
Postcondition: <code>locked() == true</code></td> Postcondition: <code>locked() == true</code></td>
</tr> </tr>
<tr> <tr>
<td valign="top"><code>lk.unlock()</code></td> <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> the associated mutex.<br>
Postcondition: <code>!locked()</code></td> Postcondition: <code>!locked()</code></td>
</tr> </tr>
</table> </table>
<h3><a name="ScopedLock-concept"></a>ScopedLock Concept</h3> <h3><a name="ScopedLock-concept"></a>ScopedLock Concept</h3>
<p>A ScopedLock is a refinement of <a href="#Lock">Lock</a>. For a ScopedLock <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 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> <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 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> expressions must be well-formed and have the indicated effects.</p>
<table summary="ScopedLock expressions" border="1" cellpadding="5"> <table summary="ScopedLock expressions" border="1" cellpadding="5">
<tr> <tr>
<td><b>Expression</b></td> <td><b>Expression</b></td>
<td><b>Effects</b></td> <td><b>Effects</b></td>
</tr> </tr>
<tr> <tr>
<td valign="top"><code>L lk(m);</code></td> <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> with it, then calls <code>lock()</code></td>
</tr> </tr>
<tr> <tr>
<td valign="top"><code>L lk(m,b);</code></td> <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> with it, then if <code>b</code>, calls <code>lock()</code></td>
</tr> </tr>
</table> </table>
<h3><a name="ScopedTryLock-concept"></a>ScopedTryLock Concept</h3> <h3><a name="ScopedTryLock-concept"></a>ScopedTryLock Concept</h3>
<p>A ScopedTryLock is a refinement of <a href="#Lock-concept">Lock</a>. For a <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, 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> 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 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> expressions must be well-formed and have the indicated effects.</p>
<table summary="ScopedTryLock expressions" border="1" cellpadding="5"> <table summary="ScopedTryLock expressions" border="1" cellpadding="5">
<tr> <tr>
<td><b>Expression</b></td> <td><b>Expression</b></td>
<td><b>Effects</b></td> <td><b>Effects</b></td>
</tr> </tr>
<tr> <tr>
<td valign="top"><code>L lk(m);</code></td> <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> with it, then calls <code>try_lock()</code></td>
</tr> </tr>
<tr> <tr>
<td valign="top"><code>L lk(m,b);</code></td> <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> with it, then if <code>b</code>, calls <code> lock()</code></td>
</tr> </tr>
<tr> <tr>
<td valign="top"><code>lk.try_lock()</code></td> <td valign="top"><code>lk.try_lock()</code></td>
<td>If locked(), throws <code>lock_error</code>. Makes a non-blocking attempt <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 to lock the associated mutex object, returning <code>true</code> if the
lock attempt is successful, otherwise <code>false</code>. If the associated lock attempt is successful, otherwise <code>false</code>. If the associated
mutex object is already locked by the same thread the behavior is dependent 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> on the <a href="mutex_concept.html#locking-strategies">locking strategy</a>
of the associated mutex object.</td> of the associated mutex object.</td>
</tr> </tr>
</table> </table>
<h3><a name="ScopedTimedLock-concept"></a>ScopedTimedLock Concept</h3> <h3><a name="ScopedTimedLock-concept"></a>ScopedTimedLock Concept</h3>
<p>A ScopedTimedLock is a refinement of <a href="#Lock">Lock</a>. For a ScopedTimedLock <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 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> <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 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>, 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> the following expressions must be well-formed and have the indicated effects.</p>
<table summary="ScopedTimedLock expressions" border="1" cellpadding= <table summary="ScopedTimedLock expressions" border="1" cellpadding=
"5"> "5">
<tr> <tr>
<td><b>Expression</b></td> <td><b>Expression</b></td>
<td><b>Effects</b></td> <td><b>Effects</b></td>
</tr> </tr>
<tr> <tr>
<td valign="top"><code>L lk(m,t);</code></td> <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> with it, then calls <code> timed_lock(t)</code></td>
</tr> </tr>
<tr> <tr>
<td valign="top"><code>L lk(m,b);</code></td> <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> with it, then if <code>b</code>, calls <code> lock()</code></td>
</tr> </tr>
<tr> <tr>
<td valign="top"><code>lk.timed_lock(t)</code></td> <td valign="top"><code>lk.timed_lock(t)</code></td>
<td>If locked(), throws lock_error. Makes a blocking attempt to lock the associated <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 mutex object, and returns <code>true</code> if successful within the specified
time <code>t</code>, otherwise <code>false</code>. If the associated mutex 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 object is already locked by the same thread the behavior is dependent on
the <a href="mutex_concept.html#locking-strategies">locking strategy</a> the <a href="mutex_concept.html#locking-strategies">locking strategy</a>
of the associated mutex object.</td> of the associated mutex object.</td>
</tr> </tr>
</table> </table>
<hr> <hr>
<p>Revised <p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
05 November, 2001 05 November, 2001
<!--webbot bot="Timestamp" endspan i-checksum="39359" --> <!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p> </p>
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002. <p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
All Rights Reserved.</i></p> All Rights Reserved.</i></p>
<p>Permission to use, copy, modify, distribute and sell this software and its <p>Permission to use, copy, modify, distribute and sell this software and its
documentation for any purpose is hereby granted without fee, provided that the documentation for any purpose is hereby granted without fee, provided that the
above copyright notice appear in all copies and that both that copyright notice above copyright notice appear in all copies and that both that copyright notice
and this permission notice appear in supporting documentation. William E. Kempf and this permission notice appear in supporting documentation. William E. Kempf
makes no representations about the suitability of this software for any purpose. 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> It is provided &quot;as is&quot; without express or implied warranty.</p>
</body> </body>
</html> </html>

View File

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

View File

@@ -7,33 +7,33 @@
<body link="#0000ff" vlink="#800080"> <body link="#0000ff" vlink="#800080">
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary= <table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
"header"> "header">
<tr> <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 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>
<td valign="top"> <td valign="top">
<h1 align="center">Boost.Threads</h1> <h1 align="center">Boost.Threads</h1>
<h2 align="center">Mutex Concept</h2> <h2 align="center">Mutex Concept</h2>
</td> </td>
</tr> </tr>
</table> </table>
<hr> <hr>
<dl class="page-index"> <dl class="page-index">
<dt><a href="#introduction">Introduction</a></dt> <dt><a href="#introduction">Introduction</a></dt>
<dt><a href="#locking-strategies">Locking Strategies</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-recursive">Recursive</a></dt>
<dt><a href="#locking-strategy-checked">Checked</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-unchecked">Unchecked</a></dt>
<dt><a href="#locking-strategy-unspecified">Unspecified</a></dt> <dt><a href="#locking-strategy-unspecified">Unspecified</a></dt>
</dl> </dl>
<dt><a href="#scheduling-policies">Scheduling Policies</a></dt> <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-FIFO">FIFO</a></dt>
<dt><a href="#scheduling-policy-priority-driven">Priority Driven</a></dt> <dt><a href="#scheduling-policy-priority-driven">Priority Driven</a></dt>
<dt><a href="#scheduling-policy-unspecified">Unspecified</a></dt> <dt><a href="#scheduling-policy-unspecified">Unspecified</a></dt>
</dl> </dl>
<dt><a href="#concept-requirements">Concept Requirements</a></dt> <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="#Mutex-concept">Mutex Concept</a></dt>
<dt><a href="#TryMutex-concept">TryMutex Concept</a></dt> <dt><a href="#TryMutex-concept">TryMutex Concept</a></dt>
<dt><a href="#TimedMutex-concept">TimedMutex Concept</a></dt> <dt><a href="#TimedMutex-concept">TimedMutex Concept</a></dt>
@@ -41,155 +41,155 @@
<dt><a href="#models">Models</a></dt> <dt><a href="#models">Models</a></dt>
</dl> </dl>
<h2><a name="introduction"></a>Introduction</h2> <h2><a name="introduction"></a>Introduction</h2>
<p>A mutex (short for mutual-exclusion) object is used to serializes access to <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, 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> with <a href="#TryMutex">TryMutex</a> and <a href="#TimedMutex">TimedMutex</a>
refinements, formalize the requirements. A model that implements Mutex and its refinements, formalize the requirements. A model that implements Mutex and its
refinements has two states: <b>locked</b> and <b>unlocked</b>. Before using 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 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 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> refinements), insuring <a href="definitions.html#thread-safe">thread-safe</a>
access to the shared resource. When use of the shared resource is complete, 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 the thread unlocks the mutex object, allowing another thread to acquire the
lock and use the shared resource.</p> lock and use the shared resource.</p>
<p>Traditional C thread APIs, like POSIX threads or the Windows thread APIs, expose <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 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, 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 with multiple return points, the likelihood of forgetting to unlock a mutex
object would become even greater. When exceptions are thrown, it becomes nearly 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 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> 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 <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 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 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 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> 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 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 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, by any <b>Boost.Threads</b> mutex objects. This helps to ensure safe usage patterns,
especially when code throws exceptions.</p> especially when code throws exceptions.</p>
<h2><a name="locking-strategies"></a>Locking Strategies</h2> <h2><a name="locking-strategies"></a>Locking Strategies</h2>
<p>Every mutex object follows one of several locking strategies. These strategies <p>Every mutex object follows one of several locking strategies. These strategies
define the semantics for the locking operation when the calling thread already define the semantics for the locking operation when the calling thread already
owns a lock on the mutex object.</p> owns a lock on the mutex object.</p>
<h3><a name="locking-strategy-recursive"></a>Recursive</h3> <h3><a name="locking-strategy-recursive"></a>Recursive</h3>
<p>With a recursive locking strategy when a thread attempts to acquire a lock <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. 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 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 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 object cannot have any of its lock functions called multiple times without first
calling unlock.</p> calling unlock.</p>
<p>Internally a lock count is maintained and the owning thread must unlock the <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 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> 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 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 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 to eliminate a whole set of errors typically found in traditional C style thread
APIs.</p> APIs.</p>
<p>Classes <a href="recursive_mutex.html#class-recursive_mutex">recursive_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> <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> and <a href="recursive_mutex.html#class-recursive_timed_mutex">recursive_timed_mutex</a>
use this locking strategy.</p> use this locking strategy.</p>
<h3><a name="locking-strategy-checked"></a>Checked</h3> <h3><a name="locking-strategy-checked"></a>Checked</h3>
<p>With a checked locking strategy when a thread attempts to acquire a lock on <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 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 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 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"> 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> 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> this strategy.</p>
<h3><a name="locking-strategy-unchecked"></a>Unchecked</h3> <h3><a name="locking-strategy-unchecked"></a>Unchecked</h3>
<p>With an unchecked locking strategy when a thread attempts to acquire a lock <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 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 <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 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> 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> this strategy.</p>
<h3><a name="locking-strategy-unspecified"></a>Unspecified</h3> <h3><a name="locking-strategy-unspecified"></a>Unspecified</h3>
<p>With an unspecified locking strategy, when a thread attempts to acquire a lock <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 on a mutex object for which the thread already owns a lock the operation results
in <b>undefined behavior</b>.</p> in <b>undefined behavior</b>.</p>
<p>In general a mutex object with an unspecified locking strategy is unsafe, and <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, 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 this strategy allows an implementation to be as fast as possible with no restrictions
on its implementation. This is especially true for portable implementations on its implementation. This is especially true for portable implementations
that wrap the native threading support of a platform. For this reason, the classes 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> <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 and <a href="mutex.html#class-timed_mutex">timed_mutex</a> use this locking
strategy despite the lack of safety.</p> strategy despite the lack of safety.</p>
<h2><a name="scheduling-policies"></a>Scheduling Policies</h2> <h2><a name="scheduling-policies"></a>Scheduling Policies</h2>
<p>Every mutex object follows one of several scheduling policies. These policies <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 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 one thread waiting to acquire a lock. In other words, the policy defines which
waiting thread shall acquire the lock.</p> waiting thread shall acquire the lock.</p>
<h3><a name="scheduling-policy-FIFO"></a>FIFO</h3> <h3><a name="scheduling-policy-FIFO"></a>FIFO</h3>
<p>With a FIFO scheduling policy, threads waiting for the lock will acquire it <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 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 a high priority thread from starving lower priority threads that are also waiting
on the mutex object's lock.</p> on the mutex object's lock.</p>
<h3><a name="scheduling-policy-priority-driven"></a>Priority Driven</h3> <h3><a name="scheduling-policy-priority-driven"></a>Priority Driven</h3>
<p>With a Priority Driven scheduling policy, the thread with the highest priority <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 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 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. 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 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 lock one of the other scheduling priorities will determine which thread shall
acquire the lock.</p> acquire the lock.</p>
<h3><a name="scheduling-policy-unspecified"></a>Unspecified</h3> <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> all <b>Boost.Threads</b> mutex models use an unspecified scheduling policy.</p>
<h2><a name="concept-requirements"></a>Concept Requirements</h2> <h2><a name="concept-requirements"></a>Concept Requirements</h2>
<h3><a name="Mutex-concept"></a>Mutex Concept</h3> <h3><a name="Mutex-concept"></a>Mutex Concept</h3>
<p>A Mutex object has two states: locked and unlocked. Mutex object state can <p>A Mutex object has two states: locked and unlocked. Mutex object state can
only be determined by an object meeting the <a href="lock_concept.html#ScopedLock">ScopedLock</a> only be determined by an object meeting the <a href="lock_concept.html#ScopedLock">ScopedLock</a>
requirements and constructed for the Mutex object.</p> requirements and constructed for the Mutex object.</p>
<p>A Mutex is <a href="../../utility/utility.htm#Class_noncopyable">NonCopyable</a>.</p> <p>A Mutex is <a href="../../utility/utility.htm#Class noncopyable">NonCopyable</a>.</p>
<p>For a Mutex type M and an object m of that type, the following expressions <p>For a Mutex type M and an object m of that type, the following expressions
must be well-formed and have the indicated effects.</p> must be well-formed and have the indicated effects.</p>
<table summary="Mutex expressions" border="1" cellpadding="5"> <table summary="Mutex expressions" border="1" cellpadding="5">
<tr> <tr>
<td><b>Expression</b></td> <td><b>Expression</b></td>
<td><b>Effects</b></td> <td><b>Effects</b></td>
</tr> </tr>
<tr> <tr>
<td><code>M m;</code></td> <td><code>M m;</code></td>
<td>Constructs a mutex object m. Post-condition: m is unlocked.</td> <td>Constructs a mutex object m. Post-condition: m is unlocked.</td>
</tr> </tr>
<tr> <tr>
<td><code>(&amp;m)-&gt;~M();</code></td> <td><code>(&amp;m)-&gt;~M();</code></td>
<td>Precondition: m is unlocked. Destroys a mutex object m.</td> <td>Precondition: m is unlocked. Destroys a mutex object m.</td>
</tr> </tr>
<tr> <tr>
<td><code>M::scoped_lock</code></td> <td><code>M::scoped_lock</code></td>
<td>A model of <a href="lock_concept.html#ScopedLock">ScopedLock</a>.</td> <td>A model of <a href="lock_concept.html#ScopedLock">ScopedLock</a>.</td>
</tr> </tr>
</table> </table>
<h3><a name="TryMutex-concept"></a>TryMutex Concept</h3> <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 <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 type M and an object m of that type, the following expressions must be well-formed
and have the indicated effects.</p> and have the indicated effects.</p>
<table summary="TryMutex expressions" border="1" cellpadding="5"> <table summary="TryMutex expressions" border="1" cellpadding="5">
<tr> <tr>
<td><b>Expression</b></td> <td><b>Expression</b></td>
<td><b>Effects</b></td> <td><b>Effects</b></td>
</tr> </tr>
<tr> <tr>
<td><code>M::scoped_try_lock</code></td> <td><code>M::scoped_try_lock</code></td>
<td>A model of <a href="lock_concept.html#ScopedTryLock">ScopedTryLock</a>.</td> <td>A model of <a href="lock_concept.html#ScopedTryLock">ScopedTryLock</a>.</td>
</tr> </tr>
</table> </table>
<h3><a name="TimedMutex-concept"></a>TimedMutex Concept</h3> <h3><a name="TimedMutex-concept"></a>TimedMutex Concept</h3>
<p>A TimedMutex is a refinement of <a href="#TryMutex-concept">TryMutex</a>. For <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 a TimedMutex type M and an object m of that type, the following expressions
must be well-formed and have the indicated effects.</p> must be well-formed and have the indicated effects.</p>
<table summary="TimedMutex expressions" border="1" cellpadding="5"> <table summary="TimedMutex expressions" border="1" cellpadding="5">
<tr> <tr>
<td><b>Expression</b></td> <td><b>Expression</b></td>
<td><b>Effects</b></td> <td><b>Effects</b></td>
</tr> </tr>
<tr> <tr>
<td><code>M::scoped_timed_lock</code></td> <td><code>M::scoped_timed_lock</code></td>
<td>A model of <a href="lock_concept.html#ScopedTimedLock">ScopedTimedLock</a>.</td> <td>A model of <a href="lock_concept.html#ScopedTimedLock">ScopedTimedLock</a>.</td>
</tr> </tr>
@@ -197,24 +197,24 @@
<h2><a name="models"></a>Models</h2> <h2><a name="models"></a>Models</h2>
<p><b>Boost.Threads</b> currently supplies six models of Mutex.</p> <p><b>Boost.Threads</b> currently supplies six models of Mutex.</p>
<table summary="Mutex concept classes" border="1" cellpadding="5"> <table summary="Mutex concept classes" border="1" cellpadding="5">
<tr> <tr>
<td><b>Concept</b></td> <td><b>Concept</b></td>
<td><b>Refines</b></td> <td><b>Refines</b></td>
<td><b>Models</b></td> <td><b>Models</b></td>
</tr> </tr>
<tr> <tr>
<td valign="top"><a href="#Mutex-concept">Mutex</a></td> <td valign="top"><a href="#Mutex-concept">Mutex</a></td>
<td valign="top">&nbsp;</td> <td valign="top">&nbsp;</td>
<td><a href="mutex.html">mutex</a><br> <td><a href="mutex.html">mutex</a><br>
<a href="recursive_mutex.html">recursive_mutex</a></td> <a href="recursive_mutex.html">recursive_mutex</a></td>
</tr> </tr>
<tr> <tr>
<td valign="top"><a href="#TryMutex-concept">TryMutex</a></td> <td valign="top"><a href="#TryMutex-concept">TryMutex</a></td>
<td valign="top"><a href="#Mutex-concept">Mutex</a></td> <td valign="top"><a href="#Mutex-concept">Mutex</a></td>
<td><a href="mutex.html">try_mutex<br> <td><a href="mutex.html">try_mutex<br>
</a> <a href="recursive_mutex.html">recursive_try_mutex</a> </td> </a> <a href="recursive_mutex.html">recursive_try_mutex</a> </td>
</tr> </tr>
<tr> <tr>
<td valign="top"><a href="#TimedMutex-concept">TimedMutex</a></td> <td valign="top"><a href="#TimedMutex-concept">TimedMutex</a></td>
<td valign="top"><a href="#TryMutex-concept">TryMutex</a></td> <td valign="top"><a href="#TryMutex-concept">TryMutex</a></td>
<td><a href="mutex.html">timed_mutex<br> <td><a href="mutex.html">timed_mutex<br>
@@ -222,16 +222,18 @@
</tr> </tr>
</table> </table>
<hr> <hr>
<p>Revised <p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->09 January, 2003<!--webbot bot="Timestamp" endspan i-checksum="38582" --> <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
05 November, 2001
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p> </p>
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002. <p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
All Rights Reserved.</i></p> All Rights Reserved.</i></p>
<p>Permission to use, copy, modify, distribute and sell this software and its <p>Permission to use, copy, modify, distribute and sell this software and its
documentation for any purpose is hereby granted without fee, provided that the documentation for any purpose is hereby granted without fee, provided that the
above copyright notice appear in all copies and that both that copyright notice above copyright notice appear in all copies and that both that copyright notice
and this permission notice appear in supporting documentation. William E. Kempf and this permission notice appear in supporting documentation. William E. Kempf
makes no representations about the suitability of this software for any purpose. 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> It is provided &quot;as is&quot; without express or implied warranty.</p>
</body> </body>
</html> </html>

View File

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

View File

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

View File

@@ -7,164 +7,168 @@
<body link="#0000ff" vlink="#800080"> <body link="#0000ff" vlink="#800080">
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary= <table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
"header"> "header">
<tr> <tr>
<td valign="top" width="300"> <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> <h3><a href="../../../index.htm"><img height="86" width="277" alt="C++ Boost" src="../../../c++boost.gif" border="0"></a></h3>
</td> </td>
<td valign="top"> <td valign="top">
<h1 align="center">Boost.Threads</h1> <h1 align="center">Boost.Threads</h1>
<h2 align="center">Rationale</h2> <h2 align="center">Rationale</h2>
</td> </td>
</tr> </tr>
</table> </table>
<hr> <hr>
<dl class="index"> <dl class="index">
<dt><a href="#introduction">Introduction</a></dt> <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="#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> <b>Boost.Threads</b></a></dt>
<dt><a href="#lock_objects">Rationale for the Lock Design</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="#non-copyable">Rationale for NonCopyable Thread Type</a></dt>
<dt><a href="#events">Rationale for not providing <i>Event Variables</i></a></dt> <dt><a href="#events">Rationale for not providing <i>Event Variables</i></a></dt>
</dl> </dl>
<h2><a name="introduction"></a>Introduction</h2> <h2><a name="introduction"></a>Introduction</h2>
<p>This page explains the rationale behind various design decisions in the <b>Boost.Threads</b> <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 library. Having the rationale documented here should explain how we arrived
at the current design as well as prevent future rehashing of discussions and 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 thought processes that have already occurred. It can also give users a lot of
insight into the design process required for this library.</p> 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> <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 <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 often be more intuitive to design systems with this in mind. Further, these
parallel processes can result in more responsive programs. The benefits for parallel processes can result in more responsive programs. The benefits for
multithreaded programming are quite well known to most modern programmers, yet multithreaded programming are quite well known to most modern programmers, yet
the C++ language doesn&#39;t directly support this concept.</p> the C++ language doesn&#39;t directly support this concept.</p>
<p>Many platforms support multithreaded programming despite the fact that the <p>Many platforms support multithreaded programming despite the fact that the
language doesn&#39;t support it. They do this through external libraries, which language doesn&#39;t support it. They do this through external libraries, which
are, unfortunately, platform specific. POSIX has tried to address this problem are, unfortunately, platform specific. POSIX has tried to address this problem
through the standardization of a &quot;pthread&quot; library. However, this through the standardization of a &quot;pthread&quot; library. However, this
is a standard only on POSIX platforms, so its portability is limited.</p> 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 <p>Another problem with POSIX and other platform specific thread libraries is
that they are almost universally C based libraries. This leaves several C++ that they are almost universally C based libraries. This leaves several C++
specific issues unresolved, such as what happens when an exception is thrown 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 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> 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++ <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 standards committee needs existing practice or a good proposal as a starting
point for adding this to the standard.</p> point for adding this to the standard.</p>
<p>The <b>Boost.Threads</b> library was developed to provide a C++ developer with <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. 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 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> 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> in <b>Boost.Threads</b></h2>
<p>The <b>Boost.Threads</b> library supplies a set of low level primitives for <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 writing multithreaded programs, such as mutexes and condition variables. In
fact, the first release of <b>Boost.Threads</b> supports only these low level 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 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 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 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 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 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> these processes must be coded using higher level abstractions. So why does <b>Boost.Threads</b>
support the lower level concepts?</p> support the lower level concepts?</p>
<p>The reason is simple: the higher level concepts need to be implemented using <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 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 makes it easier to develop the higher level concepts and will allow researchers
to experiment with various techniques.</p> to experiment with various techniques.</p>
<p>Beyond this theoretical application of higher level concepts, however, the <p>Beyond this theoretical application of higher level concepts, however, the
fact remains that many multithreaded programs are written using only the lower 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 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 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 these lower level concepts but be unfamiliar with any of the higher level concepts
there&#39;s also an argument for accessibility.</p> there&#39;s also an argument for accessibility.</p>
<h2><a name="lock_objects"></a>Rationale for the Lock Design</h2> <h2><a name="lock_objects"></a>Rationale for the Lock Design</h2>
<p>Programmers who are used to multithreaded programming issues will quickly note <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> 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 (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 design flaw. Why have a multithreading primitive that&#39;s not thread-safe
itself?</p> itself?</p>
<p>A lock object is not a synchronization primitive. A lock object&#39;s sole <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 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 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 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 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 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 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 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 usage (in fact, to do so would likely be an error). Nor are there any cases
when such usage would be required.</p> when such usage would be required.</p>
<p>Lock objects must maintain some state information. In order to allow a program <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 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. 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 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 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 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 only by a call after construction we&#39;d have a race condition if the lock
object were shared between threads.</p> object were shared between threads.</p>
<p>So, to avoid the overhead of synchronizing access to the state information <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 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 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 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 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> 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> <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 <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>. 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 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 them within user code. However, careful comparison of C designs to C++ designs
shows a flaw in this logic.</p> shows a flaw in this logic.</p>
<p>All C types are copyable. It is, in fact, not possible to make a noncopyable <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 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 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 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 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 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 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 manage the lifetime of the actual resource through the acquisition and release
APIs.</p> APIs.</p>
<p>C++ designs recognize that the acquisition and release APIs are error prone <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 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 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* 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 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 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 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 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 and easy to understand design that&#39;s consistent with other C++ standard
types.</p> types.</p>
<p>During the design of boost::thread it was pointed out that it would be possible <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; 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 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 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 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 as well. It was also thought that implementations could provide more efficient
reference management than wrappers (such as boost::shared_ptr) around a noncopyable 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 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 appear to bear them out. To illustrate the analysis we&#39;ll first provide
pseudo-code illustrating the six typical usage patterns of a thread object.</p> pseudo-code illustrating the six typical usage patterns of a thread object.</p>
<h3>1. Simple creation of a thread.</h3> <h3>1. Simple creation of a thread.</h3>
<pre>void foo() <pre>
void foo()
{ {
create_thread(&amp;bar); create_thread(&amp;bar);
} }
</pre> </pre>
<h3>2. Creation of a thread that's later joined.</h3> <h3>2. Creation of a thread that's later joined.</h3>
<pre>Void foo() <pre>
Void foo()
{ {
thread = create_thread(&amp;bar); thread = create_thread(&amp;bar);
join(thread); join(thread);
} }
</pre> </pre>
<h3>3. Simple creation of several threads in a loop.</h3> <h3>3. Simple creation of several threads in a loop.</h3>
<pre>Void foo() <pre>
Void foo()
{ {
for (int i=0; i&lt;NUM_THREADS; ++i) for (int i=0; i&lt;NUM_THREADS; ++i)
create_thread(&amp;bar); create_thread(&amp;bar);
} }
</pre> </pre>
<h3>4. Creation of several threads in a loop which are later joined.</h3> <h3>4. Creation of several threads in a loop which are later joined.</h3>
<pre>Void foo() <pre>
Void foo()
{ {
for (int i=0; i&lt;NUM_THREADS; ++i) for (int i=0; i&lt;NUM_THREADS; ++i)
threads[i] = create_thread(&amp;bar); threads[i] = create_thread(&amp;bar);
@@ -173,39 +177,42 @@
} }
</pre> </pre>
<h3>5. Creation of a thread whose ownership is passed to another object/method.</h3> <h3>5. Creation of a thread whose ownership is passed to another object/method.</h3>
<pre>Void foo() <pre>
Void foo()
{ {
thread = create_thread(&amp;bar); thread = create_thread(&amp;bar);
manager.owns(thread); manager.owns(thread);
} }
</pre> </pre>
<h3>6. Creation of a thread whose ownership is shared between multiple objects.</h3> <h3>6. Creation of a thread whose ownership is shared between multiple objects.</h3>
<pre>Void foo() <pre>
Void foo()
{ {
thread = create_thread(&amp;bar); thread = create_thread(&amp;bar);
manager1.add(thread); manager1.add(thread);
manager2.add(thread); manager2.add(thread);
} }
</pre> </pre>
<p>Of these usage patterns there&#39;s only one that requires reference management <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 (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 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> 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 <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 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> 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 <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 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. 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, 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 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> 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 <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 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 for any of the usage patterns there would be a good argument for choosing the
other design. So we&#39;ll code all six usage patterns using both designs.</p> other design. So we&#39;ll code all six usage patterns using both designs.</p>
<h3>1.</h3> <h3>1.</h3>
<pre>void foo() <pre>
void foo()
{ {
thread thrd(&amp;bar); thread thrd(&amp;bar);
} }
@@ -216,7 +223,8 @@ void foo()
} }
</pre> </pre>
<h3>2.</h3> <h3>2.</h3>
<pre>void foo() <pre>
void foo()
{ {
thread thrd(&amp;bar); thread thrd(&amp;bar);
thrd.join(); thrd.join();
@@ -224,12 +232,13 @@ void foo()
void foo() void foo()
{ {
thread_ref thrd = thread_ref thrd =
create_thread(&amp;bar);thrd-&gt;join(); create_thread(&amp;bar);thrd-&gt;join();
} }
</pre> </pre>
<h3>3.</h3> <h3>3.</h3>
<pre>void foo() <pre>
void foo()
{ {
for (int i=0; i&lt;NUM_THREADS; ++i) for (int i=0; i&lt;NUM_THREADS; ++i)
thread thrd(&amp;bar); thread thrd(&amp;bar);
@@ -242,7 +251,8 @@ void foo()
} }
</pre> </pre>
<h3>4.</h3> <h3>4.</h3>
<pre>void foo() <pre>
void foo()
{ {
std::auto_ptr&lt;thread&gt; threads[NUM_THREADS]; std::auto_ptr&lt;thread&gt; threads[NUM_THREADS];
for (int i=0; i&lt;NUM_THREADS; ++i) for (int i=0; i&lt;NUM_THREADS; ++i)
@@ -257,11 +267,12 @@ void foo()
for (int i=0; i&lt;NUM_THREADS; ++i) for (int i=0; i&lt;NUM_THREADS; ++i)
threads[i] = create_thread(&amp;bar); threads[i] = create_thread(&amp;bar);
for (int i= 0; i&lt;NUM_THREADS; for (int i= 0; i&lt;NUM_THREADS;
++i)threads[i]-&gt;join(); ++i)threads[i]-&gt;join();
} }
</pre> </pre>
<h3>5.</h3> <h3>5.</h3>
<pre>void foo() <pre>
void foo()
{ {
thread thrd* = new thread(&amp;bar); thread thrd* = new thread(&amp;bar);
manager.owns(thread); manager.owns(thread);
@@ -274,7 +285,8 @@ void foo()
} }
</pre> </pre>
<h3>6.</h3> <h3>6.</h3>
<pre>void foo() <pre>
void foo()
{ {
boost::shared_ptr&lt;thread&gt; thrd(new thread(&amp;bar)); boost::shared_ptr&lt;thread&gt; thrd(new thread(&amp;bar));
manager1.add(thrd); manager1.add(thrd);
@@ -288,15 +300,16 @@ void foo()
manager2.add(thrd); manager2.add(thrd);
} }
</pre> </pre>
<p>This shows the usage patterns being nearly identical in complexity for both <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 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 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, (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 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 the presence of operator new in user code, but this can be eliminated by proper
design of higher level concepts, such as the boost::thread_group class that design of higher level concepts, such as the boost::thread_group class that
simplifies example (4) down to:</p> simplifies example (4) down to:</p>
<pre>void foo() <pre>
void foo()
{ {
thread_group threads; thread_group threads;
for (int i=0; i&lt;NUM_THREADS; ++i) for (int i=0; i&lt;NUM_THREADS; ++i)
@@ -305,79 +318,82 @@ void foo()
} }
</pre> </pre>
<p>So ease of use is really a wash and not much help in picking a design.</p> <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 <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 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, 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 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 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 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 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 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 find that theoretically at least the thread_ref may perform faster since the
thread design requires dynamic memory allocation/deallocation. However, in practice 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 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 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 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 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 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 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 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 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 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 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 but this time we favor thread_ref slightly. Given all of this it&#39;s a narrow
margin, but the thread design prevails.</p> margin, but the thread design prevails.</p>
<p>Given this analysis, and the fact that noncopyable objects for system resources <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> 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> library has gone with a noncopyable design.</p>
<h2><a name="events"></a>Rationale for not providing <i>Event Variables</i></h2> <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= <p><i>Event variables</i> are simply far too error-prone. <a href=
"condition.html">Condition variables</a> are a much safer alternative.</p> "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> 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> still used today, for example, in the native Windows multithreading API.</p>
<p>Yet both respected computer science researchers and experienced multithreading <p>Yet both respected computer science researchers and experienced multithreading
practitioners believe event variables are so inherently error-prone that they 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> 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 <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] 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 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> speeds of the sending and receiving processes</i>&quot;. His summary:</p>
<blockquote> <blockquote>
<p>We must therefore conclude that event variables of the previous type are <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 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> processes must be independent of the speed at which it is carried out.</i></p>
</blockquote> </blockquote>
<p>Experienced programmers using the Windows platform today report that event <p>Experienced programmers using the Windows platform today report that event
variables are a continuing source of errors, even after previous bad experiences variables are a continuing source of errors, even after previous bad experiences
caused them to be very careful in their use of event variables. Overt problems caused them to be very careful in their use of event variables. Overt problems
can be avoided, for example, by teaming the event variable with a mutex, but can be avoided, for example, by teaming the event variable with a mutex, but
that may just convert a <a href="definitions.html#definition-race-condition">race condition</a> into another problem, that may just convert a <a href=
such as excessive resource use. One of the most distressing aspects of the experience "definitions.html#Race condition">race condition</a> into another problem,
reports is the claim that many defects are latent. That is, the programs appear such as excessive resource use. One of the most distressing aspects of the experience
to work correctly, but contain hidden timing dependencies which will cause them reports is the claim that many defects are latent. That is, the programs appear
to fail when environmental factors or usage patterns change, altering relative 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> thread timings.</p>
<p>The decision to exclude event variables from <b>Boost.Threads</b> has been <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 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 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 &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 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, all programs using alternatives will be easier to write, debug, read, maintain,
and be less likely to contain latent defects.</p> and be less likely to contain latent defects.</p>
<p>[Rationale provided by Beman Dawes]</p> <p>[Rationale provided by Beman Dawes]</p>
<hr> <hr>
<p>Revised <p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->09 January, 2003<!--webbot bot="Timestamp" endspan i-checksum="38582" --> <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
05 November, 2001
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p> </p>
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002. <p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
All Rights Reserved.</i></p> All Rights Reserved.</i></p>
<p>Permission to use, copy, modify, distribute and sell this software and its <p>Permission to use, copy, modify, distribute and sell this software and its
documentation for any purpose is hereby granted without fee, provided that the documentation for any purpose is hereby granted without fee, provided that the
above copyright notice appear in all copies and that both that copyright notice above copyright notice appear in all copies and that both that copyright notice
and this permission notice appear in supporting documentation. William E. Kempf and this permission notice appear in supporting documentation. William E. Kempf
makes no representations about the suitability of this software for any purpose. 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> It is provided &quot;as is&quot; without express or implied warranty.</p>
</body> </body>
</html> </html>

View File

@@ -7,40 +7,40 @@
<body link="#0000ff" vlink="#800080"> <body link="#0000ff" vlink="#800080">
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary= <table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
"header"> "header">
<tr> <tr>
<td valign="top" width="300"> <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> <h3><a href="../../../index.htm"><img height="86" width="277" alt="C++ Boost" src="../../../c++boost.gif" border="0"></a></h3>
</td> </td>
<td valign="top"> <td valign="top">
<h1 align="center">Boost.Threads</h1> <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> <h2 align="center">Header &lt;<a href="../../../boost/thread/recursive_mutex.hpp">boost/thread/recursive_mutex.hpp</a>&gt;</h2> </td>
</tr> </tr>
</table> </table>
<hr> <hr>
<h2>Contents</h2> <h2>Contents</h2>
<dl class="page-index"> <dl class="page-index">
<dt><a href="#introduction">Introduction</a></dt> <dt><a href="#introduction">Introduction</a></dt>
<dt><a href="#classes">Classes</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> <dt><a href="#class-recursive_mutex">Class <code>recursive_mutex</code></a></dt>
<dl class="page-index"> <dl class="page-index">
<dt><a href="#class-recursive_mutex-synopsis">Class <code>recursive_mutex</code> <dt><a href="#class-recursive_mutex-synopsis">Class <code>recursive_mutex</code>
synopsis</a></dt> 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> constructors and destructor</a></dt>
</dl> </dl>
<dt><a href="#class-recursive_try_mutex">Class <code>recursive_try_mutex</code></a></dt> <dt><a href="#class-recursive_try_mutex">Class <code>recursive_try_mutex</code></a></dt>
<dl class="page-index"> <dl class="page-index">
<dt><a href="#class-recursive_try_mutex-synopsis">Class <code>recursive_try_mutex</code> <dt><a href="#class-recursive_try_mutex-synopsis">Class <code>recursive_try_mutex</code>
synopsis</a></dt> 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> constructors and destructor</a></dt>
</dl> </dl>
<dt><a href="#class-recursive_timed_mutex">Class <code>recursive_timed_mutex</code></a></dt> <dt><a href="#class-recursive_timed_mutex">Class <code>recursive_timed_mutex</code></a></dt>
<dl class="page-index"> <dl class="page-index">
<dt><a href="#class-recursive_timed_mutex-synopsis">Class <code>recursive_timed_mutex</code> <dt><a href="#class-recursive_timed_mutex-synopsis">Class <code>recursive_timed_mutex</code>
synopsis</a></dt> 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> constructors and destructor</a></dt>
</dl> </dl>
</dl> </dl>
@@ -48,43 +48,43 @@
</dl> </dl>
<hr> <hr>
<h2><a name="introduction"></a>Introduction</h2> <h2><a name="introduction"></a>Introduction</h2>
<p>Include the header &lt;<a href="../../../boost/thread/recursive_mutex.hpp">boost/thread/recursive_mutex.hpp</a>&gt; <p>Include the header &lt;<a href="../../../boost/thread/recursive_mutex.hpp">boost/thread/recursive_mutex.hpp</a>&gt;
to define the <a href="#class-recursive_mutex">recursive_mutex</a>, <a href="#class-recursive_try_mutex">recursive_try_mutex</a> to define the <a href="#class-recursive_mutex">recursive_mutex</a>, <a href="#class-recursive_try_mutex">recursive_try_mutex</a>
and <a href="#class-recursive_timed_mutex">recursive_timed_mutex</a> classes.</p> and <a href="#class-recursive_timed_mutex">recursive_timed_mutex</a> classes.</p>
<p>The <a href="#class-recursive_mutex">recursive_mutex</a>, <a href="#class-recursive_try_mutex">recursive_try_mutex</a> <p>The <a href="#class-recursive_mutex">recursive_mutex</a>, <a href="#class-recursive_try_mutex">recursive_try_mutex</a>
and <a href="#class-recursive_timed_mutex">recursive_timed_mutex</a> classes and <a href="#class-recursive_timed_mutex">recursive_timed_mutex</a> classes
are models of <a href="mutex_concept.html#Mutex-concept">Mutex</a>, <a href="mutex_concept.html#TryMutex-concept">TryMutex</a>, 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. and <a href="mutex_concept.html#TimedMutex-concept">TimedMutex</a> respectively.
These types should be used to synchronize access to shared resources when recursive These types should be used to synchronize access to shared resources when recursive
locking by a single thread is likely to occur. A good example for this is when locking by a single thread is likely to occur. A good example for this is when
a class supplies &quot;internal synchronization&quot; to ensure <a href="definitions.html#Thread-safe"> a class supplies &quot;internal synchronization&quot; to ensure <a href="definitions.html#Thread-safe">
thread-safety</a> and a function of the class may have to call other functions thread-safety</a> and a function of the class may have to call other functions
of the class which also attempt to lock the mutex. For recursive locking mechanics, of the class which also attempt to lock the mutex. For recursive locking mechanics,
see <a href="mutex.html">mutexes</a>.</p> see <a href="mutex.html">mutexes</a>.</p>
<p>Each class supplies one or more typedefs for lock types which model matching <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 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> that supports the minimum set of lock types that you need.</p>
<table summary="lock types" border="1" cellpadding="5"> <table summary="lock types" border="1" cellpadding="5">
<tr> <tr>
<td><b>Mutex Class</b></td> <td><b>Mutex Class</b></td>
<td><b>Lock name</b></td> <td><b>Lock name</b></td>
<td><b>Lock Concept</b></td> <td><b>Lock Concept</b></td>
</tr> </tr>
<tr> <tr>
<td valign="top"><a href="#recursive_mutex Synopsis"><code> recursive_mutex</code></a></td> <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"><code>scoped_lock</code></td>
<td valign="middle"><a href="lock_concept.html#ScopedLock"> ScopedLock</a></td> <td valign="middle"><a href="lock_concept.html#ScopedLock"> ScopedLock</a></td>
</tr> </tr>
<tr> <tr>
<td valign="top"><code><a href="#recursive_try_mutex Synopsis"> recursive_try_mutex</a></code></td> <td valign="top"><code><a href="#recursive_try_mutex Synopsis"> recursive_try_mutex</a></code></td>
<td valign="middle"><code>scoped_lock<br> <td valign="middle"><code>scoped_lock<br>
scoped_try_lock</code></td> scoped_try_lock</code></td>
<td valign="middle"><a href="lock_concept.html#ScopedLock"> ScopedLock</a><br> <td valign="middle"><a href="lock_concept.html#ScopedLock"> ScopedLock</a><br>
<a href="lock_concept.html#ScopedTryLock"> ScopedTryLock</a></td> <a href="lock_concept.html#ScopedTryLock"> ScopedTryLock</a></td>
</tr> </tr>
<tr> <tr>
<td valign="top"><code><a href= <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>
<td valign="middle"><code>scoped_lock<br> <td valign="middle"><code>scoped_lock<br>
scoped_try_lock<br> scoped_try_lock<br>
@@ -94,23 +94,23 @@
<a href="lock_concept.html#ScopedTimedLock"> ScopedTimedLock</a></td> <a href="lock_concept.html#ScopedTimedLock"> ScopedTimedLock</a></td>
</tr> </tr>
</table> </table>
<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>
employ a <code>Recursive</code> <a href="mutex_concept.html#LockingStrategies">locking 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 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 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> 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= leave the <a href=
"mutex_concept.html#SchedulingPolicies">scheduling policy</a> as <code> "mutex_concept.html#SchedulingPolicies">scheduling policy</a> as <code>
Unspecified</code>. Programmers should assume that threads waiting for a lock 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 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> specific behavior for a given platform may be different.</p>
<h2><a name="classes"></a>Classes</h2> <h2><a name="classes"></a>Classes</h2>
<h3><a name="class-recursive_mutex"></a>Class <code>recursive_mutex</code></h3> <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> <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 and <a href="overview.html#non-copyable">NonCopyable</a>, and provides no additional
facilities beyond the requirements of these concepts.</p> 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> synopsis</h4>
<pre> <pre>
namespace boost namespace boost
@@ -120,33 +120,33 @@ namespace boost
{ {
public: public:
typedef [implementation defined; see Introduction] scoped_lock; typedef [implementation defined; see Introduction] scoped_lock;
recursive_mutex(); recursive_mutex();
~recursive_mutex(); ~recursive_mutex();
}; };
}; };
</pre> </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> constructors and destructor</h4>
<pre> <pre>
recursive_mutex(); recursive_mutex();
</pre> </pre>
<dl class="function-semantics"> <dl class="function-semantics">
<dt><b>Postconditions:</b> <code>*this</code> is in an unlocked state.</dt> <dt><b>Postconditions:</b> <code>*this</code> is in an unlocked state.</dt>
</dl> </dl>
<pre> <pre>
~recursive_mutex(); ~recursive_mutex();
</pre> </pre>
<dl class="function-semantics"> <dl class="function-semantics">
<dt><b>Requires:</b> <code>*this</code> is in an unlocked sate.</dt> <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> resulting in undefined behavior such as a program crash.</dt>
</dl> </dl>
<h3><a name="class-recursive_try_mutex"></a>Class <code>recursive_try_mutex</code></h3> <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> <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 and <a href="overview.html#non-copyable">NonCopyable</a>, and provides no additional
facilities beyond the requirements of these concepts.</p> 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> synopsis</h4>
<pre> <pre>
namespace boost namespace boost
@@ -157,33 +157,33 @@ namespace boost
Public: Public:
typedef [implementation defined; see Introduction] scoped_lock; typedef [implementation defined; see Introduction] scoped_lock;
typedef [implementation defined; see Introduction] scoped_try_lock; typedef [implementation defined; see Introduction] scoped_try_lock;
recursive_try_mutex(); recursive_try_mutex();
~recursive_try_mutex(); ~recursive_try_mutex();
}; };
}; };
</pre> </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> constructors and destructor</h4>
<pre> <pre>
recursive_try_mutex(); recursive_try_mutex();
</pre> </pre>
<dl class="function-semantics"> <dl class="function-semantics">
<dt><b>Postconditions:</b> <code>*this</code> is in an unlocked state.</dt> <dt><b>Postconditions:</b> <code>*this</code> is in an unlocked state.</dt>
</dl> </dl>
<pre> <pre>
~recursive_try_mutex(); ~recursive_try_mutex();
</pre> </pre>
<dl class="function-semantics"> <dl class="function-semantics">
<dt><b>Requires:</b> <code>*this</code> is in an unlocked sate.</dt> <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> resulting in undefined behavior such as a program crash.</dt>
</dl> </dl>
<h3><a name="class-recursive_timed_mutex"></a>Class <code>recursive_timed_mutex</code></h3> <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> <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 and <a href="overview.html#non-copyable">NonCopyable</a>, and provides no additional
facilities beyond the requirements of these concepts.</p> 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> synopsis</h4>
<pre> <pre>
namespace boost namespace boost
@@ -195,30 +195,74 @@ namespace boost
typedef [implementation defined; see Introduction] scoped_lock; typedef [implementation defined; see Introduction] scoped_lock;
typedef [implementation defined; see Introduction] scoped_try_lock; typedef [implementation defined; see Introduction] scoped_try_lock;
typedef [implementation defined; see Introduction] scoped_timed_lock; typedef [implementation defined; see Introduction] scoped_timed_lock;
recursive_timed_mutex(); recursive_timed_mutex();
~recursive_timed_mutex(); ~recursive_timed_mutex();
}; };
}; };
</pre> </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> constructors and destructor</h4>
<pre> <pre>
recursive_timed_mutex(); recursive_timed_mutex();
</pre> </pre>
<dl class="function-semantics"> <dl class="function-semantics">
<dt><b>Postconditions:</b> <code>*this</code> is in an unlocked state.</dt> <dt><b>Postconditions:</b> <code>*this</code> is in an unlocked state.</dt>
</dl> </dl>
<pre> <pre>
~recursive_timed_mutex(); ~recursive_timed_mutex();
</pre> </pre>
<dl class="function-semantics"> <dl class="function-semantics">
<dt><b>Requires:</b> <code>*this</code> is in an unlocked sate.</dt> <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> resulting in undefined behavior such as a program crash.</dt>
</dl> </dl>
<h2><a name="examples"></a>Example(s)</h2> <h2><a name="examples"></a>Example(s)</h2>
<p><a href="../example/recursive_mutex.cpp">libs/thread/example/recursive_mutex.cpp</a></p> <pre>
#include <a href="../../../boost/thread/recursive_mutex.hpp">&lt;boost/thread/recursive_mutex.hpp&gt;</a>
#include <a href="../../../boost/thread/thread.hpp">&lt;boost/thread/thread.hpp&gt;</a>
#include &lt;iostream&gt;
class counter
{
public:
counter() : count(0) { }
int add(int val) {
boost::recursive_mutex::scoped_lock scoped_lock(mutex);
count += val;
return count;
}
int increment() {
boost::recursive_mutex::scoped_lock scoped_lock(mutex);
return add(1);
}
private:
boost::recursive_mutex mutex;
int count;
};
counter c;
void change_count(void*)
{
std::cout &lt;&lt; &quot;count == &quot; &lt;&lt; c.increment() &lt;&lt; std::endl;
}
int main(int, char*[])
{
const int num_threads=4;
boost::thread_group threads;
for (int i=0; i &lt; num_threads; ++i)
threads.create_thread(&amp;change_count, 0);
threads.join_all();
return 0;
}
</pre>
<p>The output is:</p> <p>The output is:</p>
<pre> <pre>
count == 1 count == 1
@@ -227,18 +271,18 @@ count == 3
count == 4 count == 4
</pre> </pre>
<hr> <hr>
<p>Revised <p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
05 November, 2001 05 November, 2001
<!--webbot bot="Timestamp" endspan i-checksum="39359" --> <!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p> </p>
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002. <p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
All Rights Reserved.</i></p> All Rights Reserved.</i></p>
<p>Permission to use, copy, modify, distribute and sell this software and its <p>Permission to use, copy, modify, distribute and sell this software and its
documentation for any purpose is hereby granted without fee, provided that the documentation for any purpose is hereby granted without fee, provided that the
above copyright notice appear in all copies and that both that copyright notice above copyright notice appear in all copies and that both that copyright notice
and this permission notice appear in supporting documentation. William E. Kempf and this permission notice appear in supporting documentation. William E. Kempf
makes no representations about the suitability of this software for any purpose. 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> It is provided &quot;as is&quot; without express or implied warranty.</p>
</body> </body>
</html> </html>

View File

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

View File

@@ -7,11 +7,11 @@
<body link="#0000ff" vlink="#800080"> <body link="#0000ff" vlink="#800080">
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary= <table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
"header"> "header">
<tr> <tr>
<td valign="top" width="300"> <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> <h3><a href="../../../index.htm"><img height="86" width="277" alt="C++ Boost" src="../../../c++boost.gif" border="0"></a></h3>
</td> </td>
<td valign="top"> <td valign="top">
<h1 align="center">Boost.Threads</h1> <h1 align="center">Boost.Threads</h1>
<h2 align="center">Header &lt;<a href="../../../boost/thread/tss.hpp">boost/thread/tss.hpp</a>&gt;</h2> <h2 align="center">Header &lt;<a href="../../../boost/thread/tss.hpp">boost/thread/tss.hpp</a>&gt;</h2>
</td> </td>
@@ -19,19 +19,19 @@
</table> </table>
<hr> <hr>
<h2>Contents</h2> <h2>Contents</h2>
<dl class="page-index"> <dl class="page-index">
<dt><a href="#introduction">Introduction</a></dt> <dt><a href="#introduction">Introduction</a></dt>
<dt><a href="#classes">Classes</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> <dt><a href="#class-thread_specific_ptr">Class <code>thread_specific_ptr</code></a></dt>
<dl class="page-index"> <dl class="page-index">
<dt><a href="#class-thread_specific_ptr-synopsis">Class <code>thread_specific_ptr</code> <dt><a href="#class-thread_specific_ptr-synopsis">Class <code>thread_specific_ptr</code>
synopsis</a></dt> 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> 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> 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> observer functions</a></dt>
</dl> </dl>
</dl> </dl>
@@ -39,28 +39,28 @@
</dl> </dl>
<hr> <hr>
<h2><a name="introduction"></a>Introduction</h2> <h2><a name="introduction"></a>Introduction</h2>
<p>The header &lt;<a href="../../../boost/thread/tss.hpp">boost/thread/tss.hpp</a>&gt; <p>The header &lt;<a href="../../../boost/thread/tss.hpp">boost/thread/tss.hpp</a>&gt;
defines the class <a href="#class-thread_specific_ptr">thread_specific_ptr</a> defines the class <a href="#class-thread_specific_ptr">thread_specific_ptr</a>
which is used to manage data associated with specific thread instances.</p> which is used to manage data associated with specific thread instances.</p>
<h2><a name="classes"></a>Classes</h2> <h2><a name="classes"></a>Classes</h2>
<h3><a name="class-thread_specific_ptr"></a>Class <code>thread_specific_ptr</code></h3> <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 <p>The <code>thread_specific_ptr</code> class defines an interface for using thread
specific storage. Thread specific storage is data associated with individual 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> threads and is often used to make operations <a href="definitions.html#Thread-safe">thread-safe</a>
that rely on global data.</p> that rely on global data.</p>
<p>Template <code>thread_specific_ptr</code> stores a pointer to an object obtained <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 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 pointer when the thread terminates. Each thread initially stores the null pointer
in each <code> thread_specific_ptr</code> instance.</p> in each <code> thread_specific_ptr</code> instance.</p>
<p>The template <code>thread_specific_ptr</code> is useful in the following cases:</p> <p>The template <code>thread_specific_ptr</code> is useful in the following cases:</p>
<ul> <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> and is being ported to a multithreaded environment.</li>
<li>Each thread of control invokes sequences of methods that share data that <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 must be logically accessed through a globally visible access point, but are
physically unique for each thread, instead of being explicitly passed.</li> physically unique for each thread, instead of being explicitly passed.</li>
</ul> </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> synopsis</h4>
<pre> <pre>
namespace boost namespace boost
@@ -81,89 +81,120 @@ namespace boost
}; };
}; };
</pre> </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> constructors and destructor</h4>
<pre> <pre>
thread_specific_ptr(); thread_specific_ptr();
</pre> </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>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 <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 by <code>*this</code> in all threads, with each thread initially storing a
null pointer.</dt> null pointer.</dt>
<dt><b>Throws:</b> <code>boost::thread_resource_error</code> if the necessary <dt><b>Throws:</b> <code>boost::thread_resource_error</code> if the necessary
resources can not be obtained.</dt> resources can not be obtained.</dt>
<dt><b>Note:</b> There is an implementation specific limit to the number of <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 thread specific storage objects that can be created, and this limit may be
small.</dt> small.</dt>
</dl> </dl>
<pre> <pre>
~thread_specific_ptr(); ~thread_specific_ptr();
</pre> </pre>
<dl class="function-semantics"> <dl class="function-semantics">
<dt><b>Note:</b> Does not destroy any data that may be stored in any thread&#39;s <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> 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 object until you are certain there are no threads running that have made use
of its thread specific storage.</dt> of its thread specific storage.</dt>
</dl> </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> modifier functions</h4>
<pre> <pre>
T* release(); T* release();
</pre> </pre>
<dl class="function-semantics"> <dl class="function-semantics">
<dt><b>Postconditions:</b> <code>*this</code> holds the null pointer for the <dt><b>Postconditions:</b> <code>*this</code> holds the null pointer for the
current thread.</dt> current thread.</dt>
<dt><b>Returns:</b> <code>this-&gt;get()</code> prior to the call.</dt> <dt><b>Returns:</b> <code>this-&gt;get()</code> prior to the call.</dt>
</dl> </dl>
<pre> <pre>
void reset(T* p=0); void reset(T* p=0);
</pre> </pre>
<dl class="function-semantics"> <dl class="function-semantics">
<dt><b>Effects:</b> If <code>this-&gt;get()!= p</code> then <code>delete this-&gt;get()</code>. <dt><b>Effects:</b> If <code>this-&gt;get()!= p</code> then <code>delete this-&gt;get()</code>.
</dt> </dt>
<dt><b>Postconditions:</b> <code>*this</code> holds the pointer <code> p</code> <dt><b>Postconditions:</b> <code>*this</code> holds the pointer <code> p</code>
for the current thread.</dt> for the current thread.</dt>
<dt><b>Note:</b> The pointer will be deleted when the thread terminates.</dt> <dt><b>Note:</b> The pointer will be deleted when the thread terminates.</dt>
</dl> </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> observer functions</h4>
<pre> <pre>
T* get() const; T* get() const;
</pre> </pre>
<dl class="function-semantics"> <dl class="function-semantics">
<dt><b>Returns:</b> The object stored in thread specific storage for the current <dt><b>Returns:</b> The object stored in thread specific storage for the current
thread for <code>*this</code>.</dt> thread for <code>*this</code>.</dt>
<dt><b>Note:</b> Each thread initially returns 0.</dt> <dt><b>Note:</b> Each thread initially returns 0.</dt>
</dl> </dl>
<pre> <pre>
T* operator-&gt;() const; T* operator-&gt;() const;
</pre> </pre>
<dl class="function-semantics"> <dl class="function-semantics">
<dt><b>Returns:</b> <code>this-&lt;get()</code>.</dt> <dt><b>Returns:</b> <code>this-&lt;get()</code>.</dt>
</dl> </dl>
<pre> <pre>
T& operator*() const; T& operator*() const;
</pre> </pre>
<dl class="function-semantics"> <dl class="function-semantics">
<dt><b>Requires:</b> <code>this-&lt;get() != 0</code></dt> <dt><b>Requires:</b> <code>this-&lt;get() != 0</code></dt>
<dt><b>Returns:</b> <code>this-&lt;get()</code>.</dt> <dt><b>Returns:</b> <code>this-&lt;get()</code>.</dt>
</dl> </dl>
<h2><a name="examples"></a>Example(s)</h2> <h2><a name="examples"></a>Example(s)</h2>
<p><a href="../example/tss.cpp">libs/thread/example/tss.cpp</a></p> <pre>
#include <a href="../../../boost/thread/thread.hpp">&lt;boost/thread/thread.hpp&gt;</a>
#include <a href="../../../boost/thread/tss.hpp">&lt;boost/thread/tss.hpp&gt;</a>
#include &lt;cassert&gt;
boost::thread_specific_ptr&lt;int&gt; value;
void increment()
{
int* p = value.get();
++*p;
}
void thread_proc()
{
value.reset(new int(0)); // initialize the thread&#39;s storage
for (int i=0; i&lt;10; ++i)
{
increment();
int* p = value.get();
assert(*p == i+1);
}
}
int main(int argc, char* argv[])
{
boost::thread_group threads;
for (int i=0; i&lt;5; ++i)
threads.create_thread(&amp;thread_proc);
threads.join_all();
}
</pre>
<hr> <hr>
<p>Revised <p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
05 November, 2001 05 November, 2001
<!--webbot bot="Timestamp" endspan i-checksum="39359" --> <!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p> </p>
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002. <p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
All Rights Reserved.</i></p> All Rights Reserved.</i></p>
<p>Permission to use, copy, modify, distribute and sell this software and its <p>Permission to use, copy, modify, distribute and sell this software and its
documentation for any purpose is hereby granted without fee, provided that the documentation for any purpose is hereby granted without fee, provided that the
above copyright notice appear in all copies and that both that copyright notice above copyright notice appear in all copies and that both that copyright notice
and this permission notice appear in supporting documentation. William E. Kempf and this permission notice appear in supporting documentation. William E. Kempf
makes no representations about the suitability of this software for any purpose. 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> It is provided &quot;as is&quot; without express or implied warranty.</p>
</body> </body>
</html> </html>

View File

@@ -7,11 +7,11 @@
<body link="#0000ff" vlink="#800080"> <body link="#0000ff" vlink="#800080">
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary= <table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
"header"> "header">
<tr> <tr>
<td valign="top" width="300"> <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> <h3><a href="../../../index.htm"><img height="86" width="277" alt="C++ Boost" src="../../../c++boost.gif" border="0"></a></h3>
</td> </td>
<td valign="top"> <td valign="top">
<h1 align="center">Boost.Threads</h1> <h1 align="center">Boost.Threads</h1>
<h2 align="center">Header &lt;<a href="../../../boost/thread/xtime.hpp">boost/thread/xtime.hpp</a>&gt;</h2> <h2 align="center">Header &lt;<a href="../../../boost/thread/xtime.hpp">boost/thread/xtime.hpp</a>&gt;</h2>
</td> </td>
@@ -19,30 +19,30 @@
</table> </table>
<hr> <hr>
<h2>Contents</h2> <h2>Contents</h2>
<dl class="page-index"> <dl class="page-index">
<dt><a href="#introduction">Introduction</a></dt> <dt><a href="#introduction">Introduction</a></dt>
<dt><a href="#values">Values</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> <dt><a href="#value-spec">TIME_UTC</a></dt>
</dl> </dl>
<dt><a href="#classes">Classes</a></dt> <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> <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> <dt><a href="#class-xtime-synopsis">Struct <code>xtime</code> synopsis</a></dt>
</dl> </dl>
</dl> </dl>
<dt><a href="#functions">Functions</a></dt> <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> <dt><a href="#function-xtime_get"><code>xtime_get</code></a></dt>
</dl> </dl>
<dt><a href="#examples">Example(s)</a></dt> <dt><a href="#examples">Example(s)</a></dt>
</dl> </dl>
<hr> <hr>
<h2><a name="introduction"></a>Introduction</h2> <h2><a name="introduction"></a>Introduction</h2>
<p>The header &lt;<a href="../../../boost/thread/xtime.hpp">boost/thread/xtime.hpp</a>&gt; <p>The header &lt;<a href="../../../boost/thread/xtime.hpp">boost/thread/xtime.hpp</a>&gt;
defines functions and data types used to perform high-resolution time operations. defines functions and data types used to perform high-resolution time operations.
This is a temporary solution that will be replaced by a more robust time library This is a temporary solution that will be replaced by a more robust time library
once available in Boost.</p> once available in Boost.</p>
<h2><a name="values"></a>Values</h2> <h2><a name="values"></a>Values</h2>
<pre><a name="value-spec"></a> <pre><a name="value-spec"></a>
@@ -51,15 +51,15 @@ enum
TIME_UTC TIME_UTC
} }
</pre> </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> 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> <h2><a name="classes"></a>Classes</h2>
<h3><a name="class-xtime"></a>Struct <code>xtime</code></h3> <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 <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 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 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 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> library) will be provided in Boost as a separate library, at which time <b>Boost.Threads</b>
will deprecate its implementation.</p> will deprecate its implementation.</p>
<h4><a name="class-xtime-synopsis"></a>Struct <code>xtime</code> synopsis</h4> <h4><a name="class-xtime-synopsis"></a>Struct <code>xtime</code> synopsis</h4>
<pre> <pre>
@@ -80,31 +80,42 @@ namespace boost
<pre> <pre>
<a name="function-xtime_get"></a>int xtime_get(struct xtime* xtp, int clock_type); <a name="function-xtime_get"></a>int xtime_get(struct xtime* xtp, int clock_type);
</pre> </pre>
<dl class="function-semantics"> <dl class="function-semantics">
<dt><b>Postconditions:</b> <code>xtp</code> represents the current point in <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> 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>Returns:</b> <code>clock_type</code> if successful, otherwise 0.</dt>
<dt><b>Note:</b> The resolution is implementation specific. For many implementations <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 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> 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 may be significant. For maximum portability, avoid durations of less than
one second.</dt> one second.</dt>
</dl> </dl>
<h2><a name="examples"></a>Example(s)</h2> <h2><a name="examples"></a>Example(s)</h2>
<p><a href="../example/xtime.cpp">libs/thread/example/xtime.cpp</a></p> <pre>
#include <a href="../../../boost/thread/thread.hpp">&lt;boost/thread/thread.hpp&gt;</a>
#include <a href="../../../boost/thread/tss.hpp">&lt;boost/thread/xtime.hpp&gt;</a>
int main(int argc, char* argv[])
{
boost::xtime xt;
boost::xtime_get(&amp;XT, boost::TIME_UTC);
xt.sec += 1;
boost::thread::sleep(XT); // Sleep for 1 second
}
</pre>
<hr> <hr>
<p>Revised <p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
05 November, 2001 05 November, 2001
<!--webbot bot="Timestamp" endspan i-checksum="39359" --> <!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p> </p>
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002. <p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
All Rights Reserved.</i></p> All Rights Reserved.</i></p>
<p>Permission to use, copy, modify, distribute and sell this software and its <p>Permission to use, copy, modify, distribute and sell this software and its
documentation for any purpose is hereby granted without fee, provided that the documentation for any purpose is hereby granted without fee, provided that the
above copyright notice appear in all copies and that both that copyright notice above copyright notice appear in all copies and that both that copyright notice
and this permission notice appear in supporting documentation. William E. Kempf and this permission notice appear in supporting documentation. William E. Kempf
makes no representations about the suitability of this software for any purpose. 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> It is provided &quot;as is&quot; without express or implied warranty.</p>
</body> </body>
</html> </html>

View File

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

View File

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

View File

@@ -1,79 +0,0 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <iostream>
#include <vector>
#include <boost/utility.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/thread.hpp>
class bounded_buffer : private boost::noncopyable
{
public:
typedef boost::mutex::scoped_lock lock;
bounded_buffer(int n) : begin(0), end(0), buffered(0), circular_buf(n) { }
void send (int m) {
lock lk(monitor);
while (buffered == circular_buf.size())
buffer_not_full.wait(lk);
circular_buf[end] = m;
end = (end+1) % circular_buf.size();
++buffered;
buffer_not_empty.notify_one();
}
int receive() {
lock lk(monitor);
while (buffered == 0)
buffer_not_empty.wait(lk);
int i = circular_buf[begin];
begin = (begin+1) % circular_buf.size();
--buffered;
buffer_not_full.notify_one();
return i;
}
private:
int begin, end, buffered;
std::vector<int> circular_buf;
boost::condition buffer_not_full, buffer_not_empty;
boost::mutex monitor;
};
bounded_buffer buf(2);
void sender() {
int n = 0;
while (n < 100) {
buf.send(n);
std::cout << "sent: " << n << std::endl;
++n;
}
buf.send(-1);
}
void receiver() {
int n;
do {
n = buf.receive();
std::cout << "received: " << n << std::endl;
} while (n != -1); // -1 indicates end of buffer
}
int main(int, char*[])
{
boost::thread thrd1(&sender);
boost::thread thrd2(&receiver);
thrd1.join();
thrd2.join();
return 0;
}

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

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

View File

@@ -1,14 +1,3 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <vector> #include <vector>
#include <iostream> #include <iostream>
#include <boost/thread/condition.hpp> #include <boost/thread/condition.hpp>
@@ -17,11 +6,9 @@
#include <boost/thread/thread.hpp> #include <boost/thread/thread.hpp>
namespace { namespace {
const int ITERS = 100;
const int ITERS = 100; boost::mutex io_mutex;
boost::mutex io_mutex; }
} // namespace
template <typename M> template <typename M>
class buffer_t class buffer_t

BIN
example/monitor/monitor.mcp Normal file

Binary file not shown.

View File

@@ -1,52 +0,0 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include <iostream>
boost::mutex io_mutex; // The iostreams are not guaranteed to be thread-safe!
class counter
{
public:
counter() : count(0) { }
int increment() {
boost::mutex::scoped_lock scoped_lock(mutex);
return ++count;
}
private:
boost::mutex mutex;
int count;
};
counter c;
void change_count()
{
int i = c.increment();
boost::mutex::scoped_lock scoped_lock(io_mutex);
std::cout << "count == " << i << std::endl;
}
int main(int, char*[])
{
const int num_threads = 4;
boost::thread_group thrds;
for (int i=0; i < num_threads; ++i)
thrds.create_thread(&change_count);
thrds.join_all();
return 0;
}

View File

@@ -1,36 +0,0 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/thread.hpp>
#include <boost/thread/once.hpp>
#include <cassert>
int value=0;
boost::once_flag once = BOOST_ONCE_INIT;
void init()
{
++value;
}
void thread_proc()
{
boost::call_once(&init, once);
}
int main(int argc, char* argv[])
{
boost::thread_group threads;
for (int i=0; i<5; ++i)
threads.create_thread(&thread_proc);
threads.join_all();
assert(value == 1);
}

View File

@@ -1,54 +0,0 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/recursive_mutex.hpp>
#include <boost/thread/thread.hpp>
#include <iostream>
class counter
{
public:
counter() : count(0) { }
int add(int val) {
boost::recursive_mutex::scoped_lock scoped_lock(mutex);
count += val;
return count;
}
int increment() {
boost::recursive_mutex::scoped_lock scoped_lock(mutex);
return add(1);
}
private:
boost::recursive_mutex mutex;
int count;
};
counter c;
void change_count()
{
std::cout << "count == " << c.increment() << std::endl;
}
int main(int, char*[])
{
const int num_threads=4;
boost::thread_group threads;
for (int i=0; i < num_threads; ++i)
threads.create_thread(&change_count);
threads.join_all();
return 0;
}

View File

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

View File

@@ -1,14 +1,3 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/mutex.hpp> #include <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp> #include <boost/thread/condition.hpp>
#include <boost/thread/thread.hpp> #include <boost/thread/thread.hpp>
@@ -16,10 +5,9 @@
#include <iostream> #include <iostream>
#include <time.h> #include <time.h>
namespace { namespace
{
boost::mutex iomx; boost::mutex iomx;
} }
class canteen class canteen
@@ -51,9 +39,8 @@ public:
boost::mutex::scoped_lock lock(m_mutex); boost::mutex::scoped_lock lock(m_mutex);
{ {
boost::mutex::scoped_lock lock(iomx); boost::mutex::scoped_lock lock(iomx);
std::cout << "(" << clock() std::cout << "(" << clock() <<
<< ") Chef: ouch ... make room ... this dish is " ") Chef: ouch ... make room ... this dish is very hot ..." << std::endl;
<< "very hot ..." << std::endl;
} }
boost::xtime xt; boost::xtime xt;
boost::xtime_get(&xt, boost::TIME_UTC); boost::xtime_get(&xt, boost::TIME_UTC);
@@ -97,7 +84,7 @@ void chef()
{ {
boost::mutex::scoped_lock lock(iomx); boost::mutex::scoped_lock lock(iomx);
std::cout << "(" << clock() << ") Chef: " << chickens std::cout << "(" << clock() << ") Chef: " << chickens
<< " chickens, ready-to-go ..." << std::endl; << " chickens, ready-to-go ..." << std::endl;
} }
g_canteen.put(chickens); g_canteen.put(chickens);
} }
@@ -109,8 +96,7 @@ struct phil
void run() { void run() {
{ {
boost::mutex::scoped_lock lock(iomx); boost::mutex::scoped_lock lock(iomx);
std::cout << "(" << clock() << ") Phil" << m_id std::cout << "(" << clock() << ") Phil" << m_id << ": starting ..." << std::endl;
<< ": starting ..." << std::endl;
} }
for (;;) for (;;)
{ {
@@ -124,13 +110,13 @@ struct phil
{ {
boost::mutex::scoped_lock lock(iomx); boost::mutex::scoped_lock lock(iomx);
std::cout << "(" << clock() << ") Phil" << m_id std::cout << "(" << clock() << ") Phil" << m_id
<< ": gotta eat ..." << std::endl; << ": gotta eat ..." << std::endl;
} }
g_canteen.get(m_id); g_canteen.get(m_id);
{ {
boost::mutex::scoped_lock lock(iomx); boost::mutex::scoped_lock lock(iomx);
std::cout << "(" << clock() << ") Phil" << m_id std::cout << "(" << clock() << ") Phil" << m_id
<< ": mmm ... that's good ..." << std::endl; << ": mmm ... that's good ..." << std::endl;
} }
} }
} }
@@ -143,10 +129,7 @@ struct phil
struct thread_adapt struct thread_adapt
{ {
thread_adapt(void (*func)(void*), void* param) thread_adapt(void (*func)(void*), void* param) : _func(func), _param(param) { }
: _func(func), _param(param)
{
}
int operator()() const int operator()() const
{ {
_func(_param); _func(_param);
@@ -160,10 +143,7 @@ struct thread_adapt
class thread_adapter class thread_adapter
{ {
public: public:
thread_adapter(void (*func)(void*), void* param) thread_adapter(void (*func)(void*), void* param) : _func(func), _param(param) { }
: _func(func), _param(param)
{
}
void operator()() const { _func(_param); } void operator()() const { _func(_param); }
private: private:
void (*_func)(void*); void (*_func)(void*);

Binary file not shown.

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

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

View File

@@ -1,14 +1,3 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/mutex.hpp> #include <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp> #include <boost/thread/condition.hpp>
#include <boost/thread/thread.hpp> #include <boost/thread/thread.hpp>
@@ -60,8 +49,7 @@ void player(void* param)
{ {
cond.wait(lock); cond.wait(lock);
if (state == other) if (state == other)
std::cout << "---" << player_name(active) std::cout << "---" << player_name(active) << ": Spurious wakeup!" << std::endl;
<< ": Spurious wakeup!" << std::endl;
} while (state == other); } while (state == other);
} }
@@ -72,10 +60,7 @@ void player(void* param)
struct thread_adapt struct thread_adapt
{ {
thread_adapt(void (*func)(void*), void* param) thread_adapt(void (*func)(void*), void* param) : _func(func), _param(param) { }
: _func(func), _param(param)
{
}
int operator()() const int operator()() const
{ {
_func(_param); _func(_param);
@@ -89,10 +74,7 @@ struct thread_adapt
class thread_adapter class thread_adapter
{ {
public: public:
thread_adapter(void (*func)(void*), void* param) thread_adapter(void (*func)(void*), void* param) : _func(func), _param(param) { }
: _func(func), _param(param)
{
}
void operator()() const { _func(_param); } void operator()() const { _func(_param); }
private: private:
void (*_func)(void*); void (*_func)(void*);

BIN
example/tennis/tennis.mcp Normal file

Binary file not shown.

View File

@@ -1,40 +0,0 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/thread.hpp>
#include <boost/thread/xtime.hpp>
#include <iostream>
struct thread_alarm
{
thread_alarm(int secs) : m_secs(secs) { }
void operator()()
{
boost::xtime xt;
boost::xtime_get(&xt, boost::TIME_UTC);
xt.sec += m_secs;
boost::thread::sleep(xt);
std::cout << "alarm sounded..." << std::endl;
}
int m_secs;
};
int main(int argc, char* argv[])
{
int secs = 5;
std::cout << "setting alarm for 5 seconds..." << std::endl;
thread_alarm alarm(secs);
boost::thread thrd(alarm);
thrd.join();
}

View File

@@ -1,30 +0,0 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/thread.hpp>
#include <iostream>
int count = 0;
boost::mutex mutex;
void increment_count()
{
boost::mutex::scoped_lock lock(mutex);
std::cout << "count = " << ++count << std::endl;
}
int main(int argc, char* argv[])
{
boost::thread_group threads;
for (int i = 0; i < 10; ++i)
threads.create_thread(&increment_count);
threads.join_all();
}

View File

@@ -1,41 +0,0 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/thread.hpp>
#include <boost/thread/tss.hpp>
#include <cassert>
boost::thread_specific_ptr<int> value;
void increment()
{
int* p = value.get();
++*p;
}
void thread_proc()
{
value.reset(new int(0)); // initialize the thread's storage
for (int i=0; i<10; ++i)
{
increment();
int* p = value.get();
assert(*p == i+1);
}
}
int main(int argc, char* argv[])
{
boost::thread_group threads;
for (int i=0; i<5; ++i)
threads.create_thread(&thread_proc);
threads.join_all();
}

View File

@@ -1,21 +0,0 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/thread.hpp>
#include <boost/thread/xtime.hpp>
int main(int argc, char* argv[])
{
boost::xtime xt;
boost::xtime_get(&xt, boost::TIME_UTC);
xt.sec += 1;
boost::thread::sleep(xt); // Sleep for 1 second
}

View File

@@ -1,24 +0,0 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#if !defined(BOOST_THREAD_WEK01082003_HPP)
#define BOOST_THREAD_WEK01082003_HPP
#include <boost/thread/thread.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/exceptions.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/once.hpp>
#include <boost/thread/recursive_mutex.hpp>
#include <boost/thread/tss.hpp>
#include <boost/thread/xtime.hpp>
#endif

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2001-2003 // Copyright (C) 2001
// William E. Kempf // William E. Kempf
// //
// Permission to use, copy, modify, distribute and sell this software // Permission to use, copy, modify, distribute and sell this software
@@ -20,7 +20,6 @@
#include <boost/thread/exceptions.hpp> #include <boost/thread/exceptions.hpp>
#include <boost/utility.hpp> #include <boost/utility.hpp>
#include <boost/thread/detail/lock.hpp> #include <boost/thread/detail/lock.hpp>
#include <boost/thread/detail/config.hpp>
#if defined(BOOST_HAS_PTHREADS) #if defined(BOOST_HAS_PTHREADS)
# include <pthread.h> # include <pthread.h>
@@ -32,60 +31,14 @@ namespace boost {
struct xtime; struct xtime;
namespace detail {
class BOOST_THREAD_DECL condition_impl : private noncopyable
{
friend class condition;
public:
condition_impl();
~condition_impl();
void notify_one();
void notify_all();
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
void enter_wait();
void do_wait();
bool do_timed_wait(const xtime& xt);
#elif defined(BOOST_HAS_PTHREADS)
void do_wait(pthread_mutex_t* pmutex);
bool do_timed_wait(const xtime& xt, pthread_mutex_t* pmutex);
#endif
#if defined(BOOST_HAS_WINTHREADS)
void* m_gate;
void* m_queue;
void* m_mutex;
unsigned m_gone; // # threads that timed out and never made it to m_queue
unsigned long m_blocked; // # threads blocked on the condition
unsigned m_waiting; // # threads no longer waiting for the condition but
// still waiting to be removed from m_queue
#elif defined(BOOST_HAS_PTHREADS)
pthread_cond_t m_condition;
#elif defined(BOOST_HAS_MPTASKS)
MPSemaphoreID m_gate;
MPSemaphoreID m_queue;
threads::mac::detail::scoped_critical_region m_mutex;
threads::mac::detail::scoped_critical_region m_mutex_mutex;
unsigned m_gone; // # threads that timed out and never made it to m_queue
unsigned long m_blocked; // # threads blocked on the condition
unsigned m_waiting; // # threads no longer waiting for the condition but
// still waiting to be removed from m_queue
#endif
};
} // namespace detail
class condition : private noncopyable class condition : private noncopyable
{ {
public: public:
condition() { } condition();
~condition() { } ~condition();
void notify_one() { m_impl.notify_one(); } void notify_one();
void notify_all() { m_impl.notify_all(); } void notify_all();
template <typename L> template <typename L>
void wait(L& lock) void wait(L& lock)
@@ -131,63 +84,79 @@ public:
} }
private: private:
detail::condition_impl m_impl;
template <typename M> template <typename M>
void do_wait(M& mutex) void do_wait(M& mutex)
{ {
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS)) #if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
m_impl.enter_wait(); enter_wait();
#endif #endif
typedef detail::thread::lock_ops<M> typedef typename detail::thread::lock_ops<M> lock_ops;
#if defined(__HP_aCC) && __HP_aCC <= 33900 && !defined(BOOST_STRICT_CONFIG)
# define lock_ops lock_ops_ // HP confuses lock_ops witht the template
#endif
lock_ops;
typename lock_ops::lock_state state; typename lock_ops::lock_state state;
lock_ops::unlock(mutex, state); lock_ops::unlock(mutex, state);
#if defined(BOOST_HAS_PTHREADS) #if defined(BOOST_HAS_PTHREADS)
m_impl.do_wait(state.pmutex); do_wait(state.pmutex);
#elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS)) #elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
m_impl.do_wait(); do_wait();
#endif #endif
lock_ops::lock(mutex, state); lock_ops::lock(mutex, state);
#undef lock_ops
} }
template <typename M> template <typename M>
bool do_timed_wait(M& mutex, const xtime& xt) bool do_timed_wait(M& mutex, const xtime& xt)
{ {
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS)) #if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
m_impl.enter_wait(); enter_wait();
#endif #endif
typedef detail::thread::lock_ops<M> typedef typename detail::thread::lock_ops<M> lock_ops;
#if defined(__HP_aCC) && __HP_aCC <= 33900 && !defined(BOOST_STRICT_CONFIG)
# define lock_ops lock_ops_ // HP confuses lock_ops witht the template
#endif
lock_ops;
typename lock_ops::lock_state state; typename lock_ops::lock_state state;
lock_ops::unlock(mutex, state); lock_ops::unlock(mutex, state);
bool ret = false; bool ret = false;
#if defined(BOOST_HAS_PTHREADS) #if defined(BOOST_HAS_PTHREADS)
ret = m_impl.do_timed_wait(xt, state.pmutex); ret = do_timed_wait(xt, state.pmutex);
#elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS)) #elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
ret = m_impl.do_timed_wait(xt); ret = do_timed_wait(xt);
#endif #endif
lock_ops::lock(mutex, state); lock_ops::lock(mutex, state);
#undef lock_ops
return ret; return ret;
} }
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
void enter_wait();
void do_wait();
bool do_timed_wait(const xtime& xt);
#elif defined(BOOST_HAS_PTHREADS)
void do_wait(pthread_mutex_t* pmutex);
bool do_timed_wait(const xtime& xt, pthread_mutex_t* pmutex);
#endif
#if defined(BOOST_HAS_WINTHREADS)
void* m_gate;
void* m_queue;
void* m_mutex;
unsigned m_gone; // # threads that timed out and never made it to the m_queue
unsigned long m_blocked; // # threads m_blocked m_waiting for the condition
unsigned m_waiting; // # threads m_waiting no longer m_waiting for the condition but still
// m_waiting to be removed from the m_queue
#elif defined(BOOST_HAS_PTHREADS)
pthread_cond_t m_condition;
#elif defined(BOOST_HAS_MPTASKS)
MPSemaphoreID m_gate;
MPSemaphoreID m_queue;
threads::mac::detail::scoped_critical_region m_mutex;
threads::mac::detail::scoped_critical_region m_mutex_mutex;
unsigned m_gone; // # threads that timed out and never made it to the m_queue
unsigned long m_blocked; // # threads m_blocked m_waiting for the condition
unsigned m_waiting; // # threads m_waiting no longer m_waiting for the condition but still
// m_waiting to be removed from the m_queue
#endif
}; };
} // namespace boost } // namespace boost
@@ -195,8 +164,7 @@ private:
// Change Log: // Change Log:
// 8 Feb 01 WEKEMPF Initial version. // 8 Feb 01 WEKEMPF Initial version.
// 22 May 01 WEKEMPF Modified to use xtime for time outs. // 22 May 01 WEKEMPF Modified to use xtime for time outs.
// 23 May 01 WEKEMPF Removed "duration" timed_waits, as they are too // 23 May 01 WEKEMPF Removed "duration" timed_waits, as they are too difficult
// difficult to use with spurious wakeups. // to use with spurious wakeups.
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
#endif // BOOST_CONDITION_WEK070601_HPP #endif // BOOST_CONDITION_WEK070601_HPP

View File

@@ -1,25 +0,0 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#ifndef BOOST_THREAD_CONFIG_WEK01032003_HPP
#define BOOST_THREAD_CONFIG_WEK01032003_HPP
#if defined(BOOST_HAS_WINTHREADS)
# if defined(BOOST_THREAD_BUILD_DLL)
# define BOOST_THREAD_DECL __declspec(dllexport)
# else
# define BOOST_THREAD_DECL __declspec(dllimport)
# endif
#else
# define BOOST_THREAD_DECL
#endif // BOOST_THREAD_SHARED_LIB
#endif // BOOST_THREAD_CONFIG_WEK1032003_HPP

View File

@@ -26,12 +26,12 @@ namespace thread {
// general case // general case
template<class Return_Type, class Argument_Type> template<class Return_Type, class Argument_Type>
inline Return_Type &force_cast(Argument_Type &rSrc) inline Return_Type &force_cast(Argument_Type &rSrc)
{ return(*reinterpret_cast<Return_Type *>(&rSrc)); } { return(*reinterpret_cast<Return_Type *>(&rSrc)); }
// specialization for const // specialization for const
template<class Return_Type, class Argument_Type> template<class Return_Type, class Argument_Type>
inline const Return_Type &force_cast(const Argument_Type &rSrc) inline const Return_Type &force_cast(const Argument_Type &rSrc)
{ return(*reinterpret_cast<const Return_Type *>(&rSrc)); } { return(*reinterpret_cast<const Return_Type *>(&rSrc)); }
} // namespace thread } // namespace thread

View File

@@ -20,182 +20,182 @@ namespace boost {
class condition; class condition;
struct xtime; struct xtime;
namespace detail { namespace thread { namespace detail { namespace thread {
template <typename Mutex> template <typename Mutex>
class lock_ops : private noncopyable class lock_ops : private noncopyable
{ {
private: private:
lock_ops() { } lock_ops() { }
public: public:
typedef typename Mutex::cv_state lock_state; typedef typename Mutex::cv_state lock_state;
static void lock(Mutex& m) static void lock(Mutex& m)
{ {
m.do_lock(); m.do_lock();
} }
static bool trylock(Mutex& m) static bool trylock(Mutex& m)
{ {
return m.do_trylock(); return m.do_trylock();
} }
static bool timedlock(Mutex& m, const xtime& xt) static bool timedlock(Mutex& m, const xtime& xt)
{ {
return m.do_timedlock(xt); return m.do_timedlock(xt);
} }
static void unlock(Mutex& m) static void unlock(Mutex& m)
{ {
m.do_unlock(); m.do_unlock();
} }
static void lock(Mutex& m, lock_state& state) static void lock(Mutex& m, lock_state& state)
{ {
m.do_lock(state); m.do_lock(state);
} }
static void unlock(Mutex& m, lock_state& state) static void unlock(Mutex& m, lock_state& state)
{ {
m.do_unlock(state); m.do_unlock(state);
} }
}; };
template <typename Mutex> template <typename Mutex>
class scoped_lock : private noncopyable class scoped_lock : private noncopyable
{
public:
typedef Mutex mutex_type;
explicit scoped_lock(Mutex& mx, bool initially_locked=true)
: m_mutex(mx), m_locked(false)
{ {
if (initially_locked) lock(); public:
} typedef Mutex mutex_type;
~scoped_lock()
explicit scoped_lock(Mutex& mx, bool initially_locked=true)
: m_mutex(mx), m_locked(false)
{
if (initially_locked) lock();
}
~scoped_lock()
{
if (m_locked) unlock();
}
void lock()
{
if (m_locked) throw lock_error();
lock_ops<Mutex>::lock(m_mutex);
m_locked = true;
}
void unlock()
{
if (!m_locked) throw lock_error();
lock_ops<Mutex>::unlock(m_mutex);
m_locked = false;
}
bool locked() const { return m_locked; }
operator const void*() const { return m_locked ? this : 0; }
private:
friend class boost::condition;
Mutex& m_mutex;
bool m_locked;
};
template <typename TryMutex>
class scoped_try_lock : private noncopyable
{ {
if (m_locked) unlock(); public:
} typedef TryMutex mutex_type;
void lock() explicit scoped_try_lock(TryMutex& mx)
: m_mutex(mx), m_locked(false)
{
try_lock();
}
scoped_try_lock(TryMutex& mx, bool initially_locked)
: m_mutex(mx), m_locked(false)
{
if (initially_locked) lock();
}
~scoped_try_lock()
{
if (m_locked) unlock();
}
void lock()
{
if (m_locked) throw lock_error();
lock_ops<TryMutex>::lock(m_mutex);
m_locked = true;
}
bool try_lock()
{
if (m_locked) throw lock_error();
return (m_locked = lock_ops<TryMutex>::trylock(m_mutex));
}
void unlock()
{
if (!m_locked) throw lock_error();
lock_ops<TryMutex>::unlock(m_mutex);
m_locked = false;
}
bool locked() const { return m_locked; }
operator const void*() const { return m_locked ? this : 0; }
private:
friend class boost::condition;
TryMutex& m_mutex;
bool m_locked;
};
template <typename TimedMutex>
class scoped_timed_lock : private noncopyable
{ {
if (m_locked) throw lock_error(); public:
lock_ops<Mutex>::lock(m_mutex); typedef TimedMutex mutex_type;
m_locked = true;
}
void unlock()
{
if (!m_locked) throw lock_error();
lock_ops<Mutex>::unlock(m_mutex);
m_locked = false;
}
bool locked() const { return m_locked; } scoped_timed_lock(TimedMutex& mx, const xtime& xt)
operator const void*() const { return m_locked ? this : 0; } : m_mutex(mx), m_locked(false)
{
timed_lock(xt);
}
scoped_timed_lock(TimedMutex& mx, bool initially_locked)
: m_mutex(mx), m_locked(false)
{
if (initially_locked) lock();
}
~scoped_timed_lock()
{
if (m_locked) unlock();
}
private: void lock()
friend class boost::condition; {
if (m_locked) throw lock_error();
lock_ops<TimedMutex>::lock(m_mutex);
m_locked = true;
}
bool timed_lock(const xtime& xt)
{
if (m_locked) throw lock_error();
return (m_locked = lock_ops<TimedMutex>::timedlock(m_mutex, xt));
}
void unlock()
{
if (!m_locked) throw lock_error();
lock_ops<TimedMutex>::unlock(m_mutex);
m_locked = false;
}
Mutex& m_mutex; bool locked() const { return m_locked; }
bool m_locked; operator const void*() const { return m_locked ? this : 0; }
};
template <typename TryMutex> private:
class scoped_try_lock : private noncopyable friend class boost::condition;
{
public:
typedef TryMutex mutex_type;
explicit scoped_try_lock(TryMutex& mx) TimedMutex& m_mutex;
: m_mutex(mx), m_locked(false) bool m_locked;
{ };
try_lock();
}
scoped_try_lock(TryMutex& mx, bool initially_locked)
: m_mutex(mx), m_locked(false)
{
if (initially_locked) lock();
}
~scoped_try_lock()
{
if (m_locked) unlock();
}
void lock() } // namespace thread
{ } // namespace detail
if (m_locked) throw lock_error();
lock_ops<TryMutex>::lock(m_mutex);
m_locked = true;
}
bool try_lock()
{
if (m_locked) throw lock_error();
return (m_locked = lock_ops<TryMutex>::trylock(m_mutex));
}
void unlock()
{
if (!m_locked) throw lock_error();
lock_ops<TryMutex>::unlock(m_mutex);
m_locked = false;
}
bool locked() const { return m_locked; }
operator const void*() const { return m_locked ? this : 0; }
private:
friend class boost::condition;
TryMutex& m_mutex;
bool m_locked;
};
template <typename TimedMutex>
class scoped_timed_lock : private noncopyable
{
public:
typedef TimedMutex mutex_type;
scoped_timed_lock(TimedMutex& mx, const xtime& xt)
: m_mutex(mx), m_locked(false)
{
timed_lock(xt);
}
scoped_timed_lock(TimedMutex& mx, bool initially_locked)
: m_mutex(mx), m_locked(false)
{
if (initially_locked) lock();
}
~scoped_timed_lock()
{
if (m_locked) unlock();
}
void lock()
{
if (m_locked) throw lock_error();
lock_ops<TimedMutex>::lock(m_mutex);
m_locked = true;
}
bool timed_lock(const xtime& xt)
{
if (m_locked) throw lock_error();
return (m_locked = lock_ops<TimedMutex>::timedlock(m_mutex, xt));
}
void unlock()
{
if (!m_locked) throw lock_error();
lock_ops<TimedMutex>::unlock(m_mutex);
m_locked = false;
}
bool locked() const { return m_locked; }
operator const void*() const { return m_locked ? this : 0; }
private:
friend class boost::condition;
TimedMutex& m_mutex;
bool m_locked;
};
} // namespace thread
} // namespace detail
} // namespace boost } // namespace boost
// Change Log: // Change Log:

View File

@@ -26,29 +26,29 @@ namespace thread {
template<class T> template<class T>
class singleton: private T class singleton: private T
{ {
private: private:
singleton(); singleton();
~singleton(); ~singleton();
public: public:
static T &instance(); static T &instance();
}; };
template<class T> template<class T>
inline singleton<T>::singleton() inline singleton<T>::singleton()
{ /* no-op */ } { /* no-op */ }
template<class T> template<class T>
inline singleton<T>::~singleton() inline singleton<T>::~singleton()
{ /* no-op */ } { /* no-op */ }
template<class T> template<class T>
/*static*/ T &singleton<T>::instance() /*static*/ T &singleton<T>::instance()
{ {
// function-local static to force this to work correctly at static // function-local static to force this to work correctly at static initialization
// initialization time. // time.
static singleton<T> s_oT; static singleton<T> s_oT;
return(s_oT); return(s_oT);
} }

View File

@@ -1,25 +0,0 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/config.hpp>
#ifndef BOOST_HAS_THREADS
# error Thread support is unavailable!
#endif
#include <boost/thread/detail/config.hpp>
#ifdef BOOST_HAS_WINTHREADS
#include <boost/thread/detail/config.hpp>
extern "C" BOOST_THREAD_DECL int on_thread_exit(void (__cdecl * func)(void));
#endif // BOOST_HAS_WINTHREADS

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2001-2003 // Copyright (C) 2001
// William E. Kempf // William E. Kempf
// //
// Permission to use, copy, modify, distribute and sell this software // Permission to use, copy, modify, distribute and sell this software
@@ -12,9 +12,6 @@
#ifndef BOOST_THREAD_EXCEPTIONS_PDM070801_H #ifndef BOOST_THREAD_EXCEPTIONS_PDM070801_H
#define BOOST_THREAD_EXCEPTIONS_PDM070801_H #define BOOST_THREAD_EXCEPTIONS_PDM070801_H
#include <boost/config.hpp>
#include <boost/thread/detail/config.hpp>
// pdm: Sorry, but this class is used all over the place & I end up // pdm: Sorry, but this class is used all over the place & I end up
// with recursive headers if I don't separate it // with recursive headers if I don't separate it
// wek: Not sure why recursive headers would cause compilation problems // wek: Not sure why recursive headers would cause compilation problems
@@ -25,13 +22,13 @@
namespace boost { namespace boost {
class BOOST_THREAD_DECL lock_error : public std::logic_error class lock_error : public std::logic_error
{ {
public: public:
lock_error(); lock_error();
}; };
class BOOST_THREAD_DECL thread_resource_error : public std::runtime_error class thread_resource_error : public std::runtime_error
{ {
public: public:
thread_resource_error(); thread_resource_error();
@@ -39,7 +36,4 @@ public:
} // namespace boost } // namespace boost
// Change log:
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
#endif // BOOST_THREAD_CONFIG_PDM070801_H #endif // BOOST_THREAD_CONFIG_PDM070801_H

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2001-2003 // Copyright (C) 2001
// William E. Kempf // William E. Kempf
// //
// Permission to use, copy, modify, distribute and sell this software // Permission to use, copy, modify, distribute and sell this software
@@ -19,7 +19,6 @@
#include <boost/utility.hpp> #include <boost/utility.hpp>
#include <boost/thread/detail/lock.hpp> #include <boost/thread/detail/lock.hpp>
#include <boost/thread/detail/config.hpp>
#if defined(BOOST_HAS_PTHREADS) #if defined(BOOST_HAS_PTHREADS)
# include <pthread.h> # include <pthread.h>
@@ -33,7 +32,7 @@ namespace boost {
struct xtime; struct xtime;
class BOOST_THREAD_DECL mutex : private noncopyable class mutex : private noncopyable
{ {
public: public:
friend class detail::thread::lock_ops<mutex>; friend class detail::thread::lock_ops<mutex>;
@@ -71,7 +70,7 @@ private:
#endif #endif
}; };
class BOOST_THREAD_DECL try_mutex : private noncopyable class try_mutex : private noncopyable
{ {
public: public:
friend class detail::thread::lock_ops<try_mutex>; friend class detail::thread::lock_ops<try_mutex>;
@@ -111,7 +110,7 @@ private:
#endif #endif
}; };
class BOOST_THREAD_DECL timed_mutex : private noncopyable class timed_mutex : private noncopyable
{ {
public: public:
friend class detail::thread::lock_ops<timed_mutex>; friend class detail::thread::lock_ops<timed_mutex>;
@@ -161,6 +160,5 @@ private:
// 8 Feb 01 WEKEMPF Initial version. // 8 Feb 01 WEKEMPF Initial version.
// 22 May 01 WEKEMPF Modified to use xtime for time outs. Factored out // 22 May 01 WEKEMPF Modified to use xtime for time outs. Factored out
// to three classes, mutex, try_mutex and timed_mutex. // to three classes, mutex, try_mutex and timed_mutex.
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
#endif // BOOST_MUTEX_WEK070601_HPP #endif // BOOST_MUTEX_WEK070601_HPP

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2001-2003 // Copyright (C) 2001
// William E. Kempf // William E. Kempf
// //
// Permission to use, copy, modify, distribute and sell this software // Permission to use, copy, modify, distribute and sell this software
@@ -17,8 +17,6 @@
# error Thread support is unavailable! # error Thread support is unavailable!
#endif #endif
#include <boost/thread/detail/config.hpp>
#if defined(BOOST_HAS_PTHREADS) #if defined(BOOST_HAS_PTHREADS)
# include <pthread.h> # include <pthread.h>
#endif #endif
@@ -32,12 +30,12 @@ typedef pthread_once_t once_flag;
#elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS)) #elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
typedef long once_flag; typedef bool once_flag;
#define BOOST_ONCE_INIT 0 #define BOOST_ONCE_INIT false
#endif #endif
void BOOST_THREAD_DECL call_once(void (*func)(), once_flag& flag); void call_once(void (*func)(), once_flag& flag);
} // namespace boost } // namespace boost

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2001-2003 // Copyright (C) 2001
// William E. Kempf // William E. Kempf
// //
// Permission to use, copy, modify, distribute and sell this software // Permission to use, copy, modify, distribute and sell this software
@@ -19,7 +19,6 @@
#include <boost/utility.hpp> #include <boost/utility.hpp>
#include <boost/thread/detail/lock.hpp> #include <boost/thread/detail/lock.hpp>
#include <boost/thread/detail/config.hpp>
#if defined(BOOST_HAS_PTHREADS) #if defined(BOOST_HAS_PTHREADS)
# include <pthread.h> # include <pthread.h>
@@ -31,7 +30,7 @@ namespace boost {
struct xtime; struct xtime;
class BOOST_THREAD_DECL recursive_mutex : private noncopyable class recursive_mutex : private noncopyable
{ {
public: public:
friend class detail::thread::lock_ops<recursive_mutex>; friend class detail::thread::lock_ops<recursive_mutex>;
@@ -74,14 +73,13 @@ private:
#endif #endif
}; };
class BOOST_THREAD_DECL recursive_try_mutex : private noncopyable class recursive_try_mutex : private noncopyable
{ {
public: public:
friend class detail::thread::lock_ops<recursive_try_mutex>; friend class detail::thread::lock_ops<recursive_try_mutex>;
typedef detail::thread::scoped_lock<recursive_try_mutex> scoped_lock; typedef detail::thread::scoped_lock<recursive_try_mutex> scoped_lock;
typedef detail::thread::scoped_try_lock< typedef detail::thread::scoped_try_lock<recursive_try_mutex> scoped_try_lock;
recursive_try_mutex> scoped_try_lock;
recursive_try_mutex(); recursive_try_mutex();
~recursive_try_mutex(); ~recursive_try_mutex();
@@ -120,16 +118,14 @@ private:
#endif #endif
}; };
class BOOST_THREAD_DECL recursive_timed_mutex : private noncopyable class recursive_timed_mutex : private noncopyable
{ {
public: public:
friend class detail::thread::lock_ops<recursive_timed_mutex>; friend class detail::thread::lock_ops<recursive_timed_mutex>;
typedef detail::thread::scoped_lock<recursive_timed_mutex> scoped_lock; typedef detail::thread::scoped_lock<recursive_timed_mutex> scoped_lock;
typedef detail::thread::scoped_try_lock< typedef detail::thread::scoped_try_lock<recursive_timed_mutex> scoped_try_lock;
recursive_timed_mutex> scoped_try_lock; typedef detail::thread::scoped_timed_lock<recursive_timed_mutex> scoped_timed_lock;
typedef detail::thread::scoped_timed_lock<
recursive_timed_mutex> scoped_timed_lock;
recursive_timed_mutex(); recursive_timed_mutex();
~recursive_timed_mutex(); ~recursive_timed_mutex();
@@ -174,7 +170,5 @@ private:
// 1 Jun 01 WEKEMPF Modified to use xtime for time outs. Factored out // 1 Jun 01 WEKEMPF Modified to use xtime for time outs. Factored out
// to three classes, mutex, try_mutex and timed_mutex. // to three classes, mutex, try_mutex and timed_mutex.
// 11 Jun 01 WEKEMPF Modified to use PTHREAD_MUTEX_RECURSIVE if available. // 11 Jun 01 WEKEMPF Modified to use PTHREAD_MUTEX_RECURSIVE if available.
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
#endif // BOOST_RECURSIVE_MUTEX_WEK070601_HPP #endif // BOOST_RECURSIVE_MUTEX_WEK070601_HPP

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2001-2003 // Copyright (C) 2001
// William E. Kempf // William E. Kempf
// //
// Permission to use, copy, modify, distribute and sell this software // Permission to use, copy, modify, distribute and sell this software
@@ -20,7 +20,6 @@
#include <boost/utility.hpp> #include <boost/utility.hpp>
#include <boost/function.hpp> #include <boost/function.hpp>
#include <boost/thread/mutex.hpp> #include <boost/thread/mutex.hpp>
#include <boost/thread/detail/config.hpp>
#include <list> #include <list>
#include <memory> #include <memory>
@@ -35,7 +34,7 @@ namespace boost {
struct xtime; struct xtime;
class BOOST_THREAD_DECL thread : private noncopyable class thread : private noncopyable
{ {
public: public:
thread(); thread();
@@ -64,7 +63,7 @@ private:
bool m_joinable; bool m_joinable;
}; };
class BOOST_THREAD_DECL thread_group : private noncopyable class thread_group : private noncopyable
{ {
public: public:
thread_group(); thread_group();

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2001-2003 // Copyright (C) 2001
// William E. Kempf // William E. Kempf
// //
// Permission to use, copy, modify, distribute and sell this software // Permission to use, copy, modify, distribute and sell this software
@@ -18,7 +18,6 @@
#endif #endif
#include <boost/utility.hpp> #include <boost/utility.hpp>
#include <boost/thread/detail/config.hpp>
#if defined(BOOST_HAS_PTHREADS) #if defined(BOOST_HAS_PTHREADS)
# include <pthread.h> # include <pthread.h>
@@ -28,32 +27,32 @@
namespace boost { namespace boost {
namespace detail { namespace detail {
class BOOST_THREAD_DECL tss : private noncopyable class tss : private noncopyable
{ {
public: public:
tss(void (*cleanup)(void*)=0); tss(void (*cleanup)(void*)=0);
~tss(); ~tss();
void* get() const; void* get() const;
bool set(void* value); bool set(void* value);
private: private:
#if defined(BOOST_HAS_WINTHREADS) #if defined(BOOST_HAS_WINTHREADS)
unsigned long m_key; unsigned long m_key;
void (*m_cleanup)(void*); void (*m_cleanup)(void*);
#elif defined(BOOST_HAS_PTHREADS) #elif defined(BOOST_HAS_PTHREADS)
pthread_key_t m_key; pthread_key_t m_key;
#elif defined(BOOST_HAS_MPTASKS) #elif defined(BOOST_HAS_MPTASKS)
TaskStorageIndex m_key; TaskStorageIndex m_key;
void (*m_cleanup)(void*); void (*m_cleanup)(void*);
#endif #endif
}; };
#if defined(BOOST_HAS_MPTASKS) #if defined(BOOST_HAS_MPTASKS)
void thread_cleanup(); void thread_cleanup();
#endif #endif
} }
template <typename T> template <typename T>
class thread_specific_ptr : private noncopyable class thread_specific_ptr : private noncopyable
@@ -65,13 +64,7 @@ public:
T* operator->() const { return get(); } T* operator->() const { return get(); }
T& operator*() const { return *get(); } T& operator*() const { return *get(); }
T* release() { T* temp = get(); m_tss.set(0); return temp; } T* release() { T* temp = get(); m_tss.set(0); return temp; }
void reset(T* p=0) void reset(T* p=0) { T* cur = get(); if (cur == p) return; delete cur; m_tss.set(p); }
{
T* cur = get();
if (cur == p) return;
delete cur;
m_tss.set(p);
}
private: private:
static void cleanup(void* p) { delete static_cast<T*>(p); } static void cleanup(void* p) { delete static_cast<T*>(p); }

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2001-2003 // Copyright (C) 2001
// William E. Kempf // William E. Kempf
// //
// Permission to use, copy, modify, distribute and sell this software // Permission to use, copy, modify, distribute and sell this software
@@ -12,9 +12,8 @@
#ifndef BOOST_XTIME_WEK070601_HPP #ifndef BOOST_XTIME_WEK070601_HPP
#define BOOST_XTIME_WEK070601_HPP #define BOOST_XTIME_WEK070601_HPP
#include <boost/config.hpp>
#include <boost/cstdint.hpp> #include <boost/cstdint.hpp>
#include <boost/thread/detail/config.hpp> #include <boost/config.hpp>
namespace boost { namespace boost {
@@ -40,13 +39,13 @@ struct xtime
int_fast32_t nsec; int_fast32_t nsec;
}; };
int BOOST_THREAD_DECL xtime_get(struct xtime* xtp, int clock_type); int xtime_get(struct xtime* xtp, int clock_type);
inline int xtime_cmp(const xtime& xt1, const xtime& xt2) inline int xtime_cmp(const xtime& xt1, const xtime& xt2)
{ {
int res = (int)(xt1.sec - xt2.sec); int res = (int)(xt1.sec - xt2.sec);
if (res == 0) if (res == 0)
res = (int)(xt1.nsec - xt2.nsec); res = (int)(xt1.nsec - xt2.nsec);
return res; return res;
} }
} // namespace boost } // namespace boost

View File

@@ -1,8 +0,0 @@
<html>
<head>
<meta http-equiv="refresh" content="0; URL=doc/index.html">
</head>
<body>
Automatic redirection failed, please go to <a href="doc/index.html">doc/index.html</a>
</body>
</html>

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2001-2003 // Copyright (C) 2001
// William E. Kempf // William E. Kempf
// //
// Permission to use, copy, modify, distribute and sell this software // Permission to use, copy, modify, distribute and sell this software
@@ -25,49 +25,45 @@
#elif defined(BOOST_HAS_PTHREADS) #elif defined(BOOST_HAS_PTHREADS)
# include <errno.h> # include <errno.h>
#elif defined(BOOST_HAS_MPTASKS) #elif defined(BOOST_HAS_MPTASKS)
# include <MacErrors.h> # include <MacErrors.h>
# include "mac/init.hpp" # include "mac/init.hpp"
# include "mac/safe.hpp" # include "mac/safe.hpp"
#endif #endif
namespace boost { namespace boost {
namespace detail {
#if defined(BOOST_HAS_WINTHREADS) #if defined(BOOST_HAS_WINTHREADS)
condition_impl::condition_impl() condition::condition()
: m_gone(0), m_blocked(0), m_waiting(0) : m_gone(0), m_blocked(0), m_waiting(0)
{ {
m_gate = reinterpret_cast<void*>(CreateSemaphore(0, 1, 1, 0)); m_gate = reinterpret_cast<void*>(CreateSemaphore(0, 1, 1, 0));
m_queue = reinterpret_cast<void*>(CreateSemaphore(0, 0, m_queue = reinterpret_cast<void*>(CreateSemaphore(0, 0, std::numeric_limits<long>::max(), 0));
std::numeric_limits<long>::max(),
0));
m_mutex = reinterpret_cast<void*>(CreateMutex(0, 0, 0)); m_mutex = reinterpret_cast<void*>(CreateMutex(0, 0, 0));
if (!m_gate || !m_queue || !m_mutex) if (!m_gate || !m_queue || !m_mutex)
{
int res = 0;
if (m_gate)
{ {
int res = 0; res = CloseHandle(reinterpret_cast<HANDLE>(m_gate));
if (m_gate) assert(res);
{
res = CloseHandle(reinterpret_cast<HANDLE>(m_gate));
assert(res);
}
if (m_queue)
{
res = CloseHandle(reinterpret_cast<HANDLE>(m_queue));
assert(res);
}
if (m_mutex)
{
res = CloseHandle(reinterpret_cast<HANDLE>(m_mutex));
assert(res);
}
throw thread_resource_error();
} }
if (m_queue)
{
res = CloseHandle(reinterpret_cast<HANDLE>(m_queue));
assert(res);
}
if (m_mutex)
{
res = CloseHandle(reinterpret_cast<HANDLE>(m_mutex));
assert(res);
}
throw thread_resource_error();
}
} }
condition_impl::~condition_impl() condition::~condition()
{ {
int res = 0; int res = 0;
res = CloseHandle(reinterpret_cast<HANDLE>(m_gate)); res = CloseHandle(reinterpret_cast<HANDLE>(m_gate));
@@ -78,7 +74,7 @@ condition_impl::~condition_impl()
assert(res); assert(res);
} }
void condition_impl::notify_one() void condition::notify_one()
{ {
unsigned signals = 0; unsigned signals = 0;
@@ -87,102 +83,101 @@ void condition_impl::notify_one()
assert(res == WAIT_OBJECT_0); assert(res == WAIT_OBJECT_0);
if (m_waiting != 0) // the m_gate is already closed if (m_waiting != 0) // the m_gate is already closed
{
if (m_blocked == 0)
{ {
if (m_blocked == 0) res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
{ assert(res);
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex)); return;
assert(res); }
return;
}
++m_waiting; ++m_waiting;
--m_blocked; --m_blocked;
signals = 1; signals = 1;
} }
else else
{
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
assert(res == WAIT_OBJECT_0);
if (m_blocked > m_gone)
{ {
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE); if (m_gone != 0)
assert(res == WAIT_OBJECT_0); {
if (m_blocked > m_gone) m_blocked -= m_gone;
{ m_gone = 0;
if (m_gone != 0) }
{ signals = m_waiting = 1;
m_blocked -= m_gone; --m_blocked;
m_gone = 0;
}
signals = m_waiting = 1;
--m_blocked;
}
else
{
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
assert(res);
}
} }
else
{
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
assert(res);
}
}
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex)); res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
assert(res); assert(res);
if (signals) if (signals)
{
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_queue), signals, 0);
assert(res);
}
}
void condition::notify_all()
{
unsigned signals = 0;
int res = 0;
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), INFINITE);
assert(res == WAIT_OBJECT_0);
if (m_waiting != 0) // the m_gate is already closed
{
if (m_blocked == 0)
{
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
assert(res);
return;
}
m_waiting += (signals = m_blocked);
m_blocked = 0;
}
else
{
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
assert(res == WAIT_OBJECT_0);
if (m_blocked > m_gone)
{
if (m_gone != 0)
{
m_blocked -= m_gone;
m_gone = 0;
}
signals = m_waiting = m_blocked;
m_blocked = 0;
}
else
{
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
assert(res);
}
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
assert(res);
if (signals)
{ {
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_queue), signals, 0); res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_queue), signals, 0);
assert(res); assert(res);
} }
}
} }
void condition_impl::notify_all() void condition::enter_wait()
{
unsigned signals = 0;
int res = 0;
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), INFINITE);
assert(res == WAIT_OBJECT_0);
if (m_waiting != 0) // the m_gate is already closed
{
if (m_blocked == 0)
{
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
assert(res);
return;
}
m_waiting += (signals = m_blocked);
m_blocked = 0;
}
else
{
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
assert(res == WAIT_OBJECT_0);
if (m_blocked > m_gone)
{
if (m_gone != 0)
{
m_blocked -= m_gone;
m_gone = 0;
}
signals = m_waiting = m_blocked;
m_blocked = 0;
}
else
{
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
assert(res);
}
}
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
assert(res);
if (signals)
{
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_queue), signals,
0);
assert(res);
}
}
void condition_impl::enter_wait()
{ {
int res = 0; int res = 0;
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE); res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
@@ -192,7 +187,7 @@ void condition_impl::enter_wait()
assert(res); assert(res);
} }
void condition_impl::do_wait() void condition::do_wait()
{ {
int res = 0; int res = 0;
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue), INFINITE); res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue), INFINITE);
@@ -206,74 +201,57 @@ void condition_impl::do_wait()
was_waiting = m_waiting; was_waiting = m_waiting;
was_gone = m_gone; was_gone = m_gone;
if (was_waiting != 0) if (was_waiting != 0)
{
if (--m_waiting == 0)
{ {
if (--m_waiting == 0) if (m_blocked != 0)
{ {
if (m_blocked != 0) res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0); // open m_gate
{ assert(res);
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, was_waiting = 0;
0); // open m_gate }
assert(res); else if (m_gone != 0)
was_waiting = 0; m_gone = 0;
}
else if (m_gone != 0)
m_gone = 0;
}
} }
}
else if (++m_gone == (std::numeric_limits<unsigned>::max() / 2)) else if (++m_gone == (std::numeric_limits<unsigned>::max() / 2))
{ {
// timeout occured, normalize the m_gone count // timeout occured, normalize the m_gone count
// this may occur if many calls to wait with a timeout are made and // this may occur if many calls to wait with a timeout are made and
// no call to notify_* is made // no call to notify_* is made
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE); res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
assert(res == WAIT_OBJECT_0); assert(res == WAIT_OBJECT_0);
m_blocked -= m_gone; m_blocked -= m_gone;
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0); res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
assert(res); assert(res);
m_gone = 0; m_gone = 0;
} }
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex)); res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
assert(res); assert(res);
if (was_waiting == 1) if (was_waiting == 1)
{
for (/**/ ; was_gone; --was_gone)
{ {
for (/**/ ; was_gone; --was_gone) // better now than spurious later
{ res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue), INFINITE);
// better now than spurious later assert(res == WAIT_OBJECT_0);
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue),
INFINITE);
assert(res == WAIT_OBJECT_0);
}
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
assert(res);
} }
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
assert(res);
}
} }
bool condition_impl::do_timed_wait(const xtime& xt) bool condition::do_timed_wait(const xtime& xt)
{ {
bool ret = false; int milliseconds;
to_duration(xt, milliseconds);
unsigned int res = 0; unsigned int res = 0;
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue), milliseconds);
assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
for (;;) bool ret = (res == WAIT_OBJECT_0);
{
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_waiting=0;
unsigned was_gone=0; unsigned was_gone=0;
@@ -283,59 +261,57 @@ bool condition_impl::do_timed_wait(const xtime& xt)
was_waiting = m_waiting; was_waiting = m_waiting;
was_gone = m_gone; was_gone = m_gone;
if (was_waiting != 0) if (was_waiting != 0)
{
if (!ret) // timeout
{ {
if (!ret) // timeout if (m_blocked != 0)
{ --m_blocked;
if (m_blocked != 0) else
--m_blocked; ++m_gone; // count spurious wakeups
else
++m_gone; // count spurious wakeups
}
if (--m_waiting == 0)
{
if (m_blocked != 0)
{
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1,
0); // open m_gate
assert(res);
was_waiting = 0;
}
else if (m_gone != 0)
m_gone = 0;
}
} }
if (--m_waiting == 0)
{
if (m_blocked != 0)
{
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0); // open m_gate
assert(res);
was_waiting = 0;
}
else if (m_gone != 0)
m_gone = 0;
}
}
else if (++m_gone == (std::numeric_limits<unsigned>::max() / 2)) else if (++m_gone == (std::numeric_limits<unsigned>::max() / 2))
{ {
// timeout occured, normalize the m_gone count // timeout occured, normalize the m_gone count
// this may occur if many calls to wait with a timeout are made and // this may occur if many calls to wait with a timeout are made and
// no call to notify_* is made // no call to notify_* is made
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE); res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
assert(res == WAIT_OBJECT_0); assert(res == WAIT_OBJECT_0);
m_blocked -= m_gone; m_blocked -= m_gone;
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0); res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
assert(res); assert(res);
m_gone = 0; m_gone = 0;
} }
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex)); res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
assert(res); assert(res);
if (was_waiting == 1) if (was_waiting == 1)
{
for (/**/ ; was_gone; --was_gone)
{ {
for (/**/ ; was_gone; --was_gone) // better now than spurious later
{ res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue), INFINITE);
// better now than spurious later assert(res == WAIT_OBJECT_0);
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue),
INFINITE);
assert(res == WAIT_OBJECT_0);
}
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
assert(res);
} }
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
assert(res);
}
return ret; return ret;
} }
#elif defined(BOOST_HAS_PTHREADS) #elif defined(BOOST_HAS_PTHREADS)
condition_impl::condition_impl() condition::condition()
{ {
int res = 0; int res = 0;
res = pthread_cond_init(&m_condition, 0); res = pthread_cond_init(&m_condition, 0);
@@ -343,35 +319,35 @@ condition_impl::condition_impl()
throw thread_resource_error(); throw thread_resource_error();
} }
condition_impl::~condition_impl() condition::~condition()
{ {
int res = 0; int res = 0;
res = pthread_cond_destroy(&m_condition); res = pthread_cond_destroy(&m_condition);
assert(res == 0); assert(res == 0);
} }
void condition_impl::notify_one() void condition::notify_one()
{ {
int res = 0; int res = 0;
res = pthread_cond_signal(&m_condition); res = pthread_cond_signal(&m_condition);
assert(res == 0); assert(res == 0);
} }
void condition_impl::notify_all() void condition::notify_all()
{ {
int res = 0; int res = 0;
res = pthread_cond_broadcast(&m_condition); res = pthread_cond_broadcast(&m_condition);
assert(res == 0); assert(res == 0);
} }
void condition_impl::do_wait(pthread_mutex_t* pmutex) void condition::do_wait(pthread_mutex_t* pmutex)
{ {
int res = 0; int res = 0;
res = pthread_cond_wait(&m_condition, pmutex); res = pthread_cond_wait(&m_condition, pmutex);
assert(res == 0); assert(res == 0);
} }
bool condition_impl::do_timed_wait(const xtime& xt, pthread_mutex_t* pmutex) bool condition::do_timed_wait(const xtime& xt, pthread_mutex_t* pmutex)
{ {
timespec ts; timespec ts;
to_timespec(xt, ts); to_timespec(xt, ts);
@@ -387,7 +363,7 @@ bool condition_impl::do_timed_wait(const xtime& xt, pthread_mutex_t* pmutex)
using threads::mac::detail::safe_enter_critical_region; using threads::mac::detail::safe_enter_critical_region;
using threads::mac::detail::safe_wait_on_semaphore; using threads::mac::detail::safe_wait_on_semaphore;
condition_impl::condition_impl() condition::condition()
: m_gone(0), m_blocked(0), m_waiting(0) : m_gone(0), m_blocked(0), m_waiting(0)
{ {
threads::mac::detail::thread_init(); threads::mac::detail::thread_init();
@@ -399,23 +375,23 @@ condition_impl::condition_impl()
lStatus = MPCreateSemaphore(ULONG_MAX, 0, &m_queue); lStatus = MPCreateSemaphore(ULONG_MAX, 0, &m_queue);
if(lStatus != noErr || !m_gate || !m_queue) if(lStatus != noErr || !m_gate || !m_queue)
{
if (m_gate)
{ {
if (m_gate) lStatus = MPDeleteSemaphore(m_gate);
{ assert(lStatus == noErr);
lStatus = MPDeleteSemaphore(m_gate);
assert(lStatus == noErr);
}
if (m_queue)
{
lStatus = MPDeleteSemaphore(m_queue);
assert(lStatus == noErr);
}
throw thread_resource_error();
} }
if (m_queue)
{
lStatus = MPDeleteSemaphore(m_queue);
assert(lStatus == noErr);
}
throw thread_resource_error();
}
} }
condition_impl::~condition_impl() condition::~condition()
{ {
OSStatus lStatus = noErr; OSStatus lStatus = noErr;
lStatus = MPDeleteSemaphore(m_gate); lStatus = MPDeleteSemaphore(m_gate);
@@ -424,113 +400,111 @@ condition_impl::~condition_impl()
assert(lStatus == noErr); assert(lStatus == noErr);
} }
void condition_impl::notify_one() void condition::notify_one()
{ {
unsigned signals = 0; unsigned signals = 0;
OSStatus lStatus = noErr; OSStatus lStatus = noErr;
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
m_mutex_mutex);
assert(lStatus == noErr); assert(lStatus == noErr);
if (m_waiting != 0) // the m_gate is already closed if (m_waiting != 0) // the m_gate is already closed
{
if (m_blocked == 0)
{ {
if (m_blocked == 0) lStatus = MPExitCriticalRegion(m_mutex);
{ assert(lStatus == noErr);
lStatus = MPExitCriticalRegion(m_mutex); return;
assert(lStatus == noErr); }
return;
}
++m_waiting; ++m_waiting;
--m_blocked;
}
else
{
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
assert(lStatus == noErr);
if (m_blocked > m_gone)
{
if (m_gone != 0)
{
m_blocked -= m_gone;
m_gone = 0;
}
signals = m_waiting = 1;
--m_blocked; --m_blocked;
} }
else else
{ {
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever); lStatus = MPSignalSemaphore(m_gate);
assert(lStatus == noErr); assert(lStatus == noErr);
if (m_blocked > m_gone)
{
if (m_gone != 0)
{
m_blocked -= m_gone;
m_gone = 0;
}
signals = m_waiting = 1;
--m_blocked;
}
else
{
lStatus = MPSignalSemaphore(m_gate);
assert(lStatus == noErr);
}
lStatus = MPExitCriticalRegion(m_mutex);
assert(lStatus == noErr);
while (signals)
{
lStatus = MPSignalSemaphore(m_queue);
assert(lStatus == noErr);
--signals;
}
} }
lStatus = MPExitCriticalRegion(m_mutex);
assert(lStatus == noErr);
while (signals)
{
lStatus = MPSignalSemaphore(m_queue);
assert(lStatus == noErr);
--signals;
}
}
} }
void condition_impl::notify_all() void condition::notify_all()
{ {
unsigned signals = 0; unsigned signals = 0;
OSStatus lStatus = noErr; OSStatus lStatus = noErr;
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
m_mutex_mutex);
assert(lStatus == noErr); assert(lStatus == noErr);
if (m_waiting != 0) // the m_gate is already closed if (m_waiting != 0) // the m_gate is already closed
{
if (m_blocked == 0)
{ {
if (m_blocked == 0)
{
lStatus = MPExitCriticalRegion(m_mutex);
assert(lStatus == noErr);
return;
}
m_waiting += (signals = m_blocked);
m_blocked = 0;
}
else
{
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
assert(lStatus == noErr);
if (m_blocked > m_gone)
{
if (m_gone != 0)
{
m_blocked -= m_gone;
m_gone = 0;
}
signals = m_waiting = m_blocked;
m_blocked = 0;
}
else
{
lStatus = MPSignalSemaphore(m_gate);
assert(lStatus == noErr);
}
lStatus = MPExitCriticalRegion(m_mutex); lStatus = MPExitCriticalRegion(m_mutex);
assert(lStatus == noErr); assert(lStatus == noErr);
return;
while (signals)
{
lStatus = MPSignalSemaphore(m_queue);
assert(lStatus == noErr);
--signals;
}
} }
m_waiting += (signals = m_blocked);
m_blocked = 0;
}
else
{
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
assert(lStatus == noErr);
if (m_blocked > m_gone)
{
if (m_gone != 0)
{
m_blocked -= m_gone;
m_gone = 0;
}
signals = m_waiting = m_blocked;
m_blocked = 0;
}
else
{
lStatus = MPSignalSemaphore(m_gate);
assert(lStatus == noErr);
}
lStatus = MPExitCriticalRegion(m_mutex);
assert(lStatus == noErr);
while (signals)
{
lStatus = MPSignalSemaphore(m_queue);
assert(lStatus == noErr);
--signals;
}
}
} }
void condition_impl::enter_wait() void condition::enter_wait()
{ {
OSStatus lStatus = noErr; OSStatus lStatus = noErr;
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever); lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
@@ -540,7 +514,7 @@ void condition_impl::enter_wait()
assert(lStatus == noErr); assert(lStatus == noErr);
} }
void condition_impl::do_wait() void condition::do_wait()
{ {
OSStatus lStatus = noErr; OSStatus lStatus = noErr;
lStatus = safe_wait_on_semaphore(m_queue, kDurationForever); lStatus = safe_wait_on_semaphore(m_queue, kDurationForever);
@@ -549,54 +523,53 @@ void condition_impl::do_wait()
unsigned was_waiting=0; unsigned was_waiting=0;
unsigned was_gone=0; unsigned was_gone=0;
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
m_mutex_mutex);
assert(lStatus == noErr); assert(lStatus == noErr);
was_waiting = m_waiting; was_waiting = m_waiting;
was_gone = m_gone; was_gone = m_gone;
if (was_waiting != 0) if (was_waiting != 0)
{
if (--m_waiting == 0)
{ {
if (--m_waiting == 0) if (m_blocked != 0)
{ {
if (m_blocked != 0) lStatus = MPSignalSemaphore(m_gate); // open m_gate
{ assert(lStatus == noErr);
lStatus = MPSignalSemaphore(m_gate); // open m_gate was_waiting = 0;
assert(lStatus == noErr); }
was_waiting = 0; else if (m_gone != 0)
} m_gone = 0;
else if (m_gone != 0)
m_gone = 0;
}
} }
}
else if (++m_gone == (std::numeric_limits<unsigned>::max() / 2)) else if (++m_gone == (std::numeric_limits<unsigned>::max() / 2))
{ {
// timeout occured, normalize the m_gone count // timeout occured, normalize the m_gone count
// this may occur if many calls to wait with a timeout are made and // this may occur if many calls to wait with a timeout are made and
// no call to notify_* is made // no call to notify_* is made
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever); lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
assert(lStatus == noErr); assert(lStatus == noErr);
m_blocked -= m_gone; m_blocked -= m_gone;
lStatus = MPSignalSemaphore(m_gate); lStatus = MPSignalSemaphore(m_gate);
assert(lStatus == noErr); assert(lStatus == noErr);
m_gone = 0; m_gone = 0;
} }
lStatus = MPExitCriticalRegion(m_mutex); lStatus = MPExitCriticalRegion(m_mutex);
assert(lStatus == noErr); assert(lStatus == noErr);
if (was_waiting == 1) if (was_waiting == 1)
{
for (/**/ ; was_gone; --was_gone)
{ {
for (/**/ ; was_gone; --was_gone) // better now than spurious later
{ lStatus = safe_wait_on_semaphore(m_queue, kDurationForever);
// better now than spurious later
lStatus = safe_wait_on_semaphore(m_queue, kDurationForever);
assert(lStatus == noErr);
}
lStatus = MPSignalSemaphore(m_gate);
assert(lStatus == noErr); assert(lStatus == noErr);
} }
lStatus = MPSignalSemaphore(m_gate);
assert(lStatus == noErr);
}
} }
bool condition_impl::do_timed_wait(const xtime& xt) bool condition::do_timed_wait(const xtime& xt)
{ {
int milliseconds; int milliseconds;
to_duration(xt, milliseconds); to_duration(xt, milliseconds);
@@ -610,68 +583,64 @@ bool condition_impl::do_timed_wait(const xtime& xt)
unsigned was_waiting=0; unsigned was_waiting=0;
unsigned was_gone=0; unsigned was_gone=0;
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
m_mutex_mutex);
assert(lStatus == noErr); assert(lStatus == noErr);
was_waiting = m_waiting; was_waiting = m_waiting;
was_gone = m_gone; was_gone = m_gone;
if (was_waiting != 0) if (was_waiting != 0)
{
if (!ret) // timeout
{ {
if (!ret) // timeout if (m_blocked != 0)
{ --m_blocked;
if (m_blocked != 0) else
--m_blocked; ++m_gone; // count spurious wakeups
else
++m_gone; // count spurious wakeups
}
if (--m_waiting == 0)
{
if (m_blocked != 0)
{
lStatus = MPSignalSemaphore(m_gate); // open m_gate
assert(lStatus == noErr);
was_waiting = 0;
}
else if (m_gone != 0)
m_gone = 0;
}
} }
if (--m_waiting == 0)
{
if (m_blocked != 0)
{
lStatus = MPSignalSemaphore(m_gate); // open m_gate
assert(lStatus == noErr);
was_waiting = 0;
}
else if (m_gone != 0)
m_gone = 0;
}
}
else if (++m_gone == (std::numeric_limits<unsigned>::max() / 2)) else if (++m_gone == (std::numeric_limits<unsigned>::max() / 2))
{ {
// timeout occured, normalize the m_gone count // timeout occured, normalize the m_gone count
// this may occur if many calls to wait with a timeout are made and // this may occur if many calls to wait with a timeout are made and
// no call to notify_* is made // no call to notify_* is made
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever); lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
assert(lStatus == noErr); assert(lStatus == noErr);
m_blocked -= m_gone; m_blocked -= m_gone;
lStatus = MPSignalSemaphore(m_gate); lStatus = MPSignalSemaphore(m_gate);
assert(lStatus == noErr); assert(lStatus == noErr);
m_gone = 0; m_gone = 0;
} }
lStatus = MPExitCriticalRegion(m_mutex); lStatus = MPExitCriticalRegion(m_mutex);
assert(lStatus == noErr); assert(lStatus == noErr);
if (was_waiting == 1) if (was_waiting == 1)
{
for (/**/ ; was_gone; --was_gone)
{ {
for (/**/ ; was_gone; --was_gone) // better now than spurious later
{ lStatus = safe_wait_on_semaphore(m_queue, kDurationForever);
// better now than spurious later
lStatus = safe_wait_on_semaphore(m_queue, kDurationForever);
assert(lStatus == noErr);
}
lStatus = MPSignalSemaphore(m_gate);
assert(lStatus == noErr); assert(lStatus == noErr);
} }
lStatus = MPSignalSemaphore(m_gate);
assert(lStatus == noErr);
}
return ret; return ret;
} }
#endif #endif
} // namespace detail
} // namespace boost } // namespace boost
// Change Log: // Change Log:
// 8 Feb 01 WEKEMPF Initial version. // 8 Feb 01 WEKEMPF Initial version.
// 22 May 01 WEKEMPF Modified to use xtime for time outs. // 22 May 01 WEKEMPF Modified to use xtime for time outs.
// 3 Jan 03 WEKEMPF Modified for DLL implementation.

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2001-2003 // Copyright (C) 2001
// William E. Kempf // William E. Kempf
// //
// Permission to use, copy, modify, distribute and sell this software // Permission to use, copy, modify, distribute and sell this software
@@ -14,13 +14,11 @@
namespace boost { namespace boost {
lock_error::lock_error() lock_error::lock_error() : std::logic_error("thread lock error")
: std::logic_error("thread lock error")
{ {
} }
thread_resource_error::thread_resource_error() thread_resource_error::thread_resource_error() : std::runtime_error("thread resource error")
: std::runtime_error("thread resource error")
{ {
} }

View File

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

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2001-2003 // Copyright (C) 2001
// William E. Kempf // William E. Kempf
// //
// Permission to use, copy, modify, distribute and sell this software // Permission to use, copy, modify, distribute and sell this software
@@ -16,6 +16,7 @@
#include <boost/limits.hpp> #include <boost/limits.hpp>
#include <stdexcept> #include <stdexcept>
#include <cassert> #include <cassert>
#include <new>
#include "timeconv.inl" #include "timeconv.inl"
#if defined(BOOST_HAS_WINTHREADS) #if defined(BOOST_HAS_WINTHREADS)
@@ -24,23 +25,18 @@
#elif defined(BOOST_HAS_PTHREADS) #elif defined(BOOST_HAS_PTHREADS)
# include <errno.h> # include <errno.h>
#elif defined(BOOST_HAS_MPTASKS) #elif defined(BOOST_HAS_MPTASKS)
# include <MacErrors.h> # include <MacErrors.h>
# include "mac/init.hpp"
# include "mac/safe.hpp" # include "mac/init.hpp"
# include "mac/safe.hpp"
#endif #endif
namespace boost { namespace boost {
#if defined(BOOST_HAS_WINTHREADS) #if defined(BOOST_HAS_WINTHREADS)
mutex::mutex() : m_mutex(0) mutex::mutex()
{ {
try m_mutex = reinterpret_cast<void*>(new(std::nothrow) CRITICAL_SECTION);
{
m_mutex = reinterpret_cast<void*>(new CRITICAL_SECTION);
}
catch (...)
{
}
if (!m_mutex) if (!m_mutex)
throw thread_resource_error(); throw thread_resource_error();
InitializeCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(m_mutex)); InitializeCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(m_mutex));
@@ -149,26 +145,12 @@ bool timed_mutex::do_trylock()
bool timed_mutex::do_timedlock(const xtime& xt) bool timed_mutex::do_timedlock(const xtime& xt)
{ {
unsigned int res = 0; int milliseconds;
for (;;) to_duration(xt, milliseconds);
{
int milliseconds;
to_duration(xt, milliseconds);
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), unsigned int res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), milliseconds);
milliseconds); assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
assert(res != WAIT_FAILED && res != WAIT_ABANDONED); return res == WAIT_OBJECT_0;
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() void timed_mutex::do_unlock()
@@ -432,8 +414,7 @@ mutex::~mutex()
void mutex::do_lock() void mutex::do_lock()
{ {
OSStatus lStatus = noErr; OSStatus lStatus = noErr;
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
m_mutex_mutex);
assert(lStatus == noErr); assert(lStatus == noErr);
} }
@@ -465,8 +446,7 @@ try_mutex::~try_mutex()
void try_mutex::do_lock() void try_mutex::do_lock()
{ {
OSStatus lStatus = noErr; OSStatus lStatus = noErr;
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
m_mutex_mutex);
assert(lStatus == noErr); assert(lStatus == noErr);
} }
@@ -506,8 +486,7 @@ timed_mutex::~timed_mutex()
void timed_mutex::do_lock() void timed_mutex::do_lock()
{ {
OSStatus lStatus = noErr; OSStatus lStatus = noErr;
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
m_mutex_mutex);
assert(lStatus == noErr); assert(lStatus == noErr);
} }

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2001-2003 // Copyright (C) 2001
// William E. Kempf // William E. Kempf
// //
// Permission to use, copy, modify, distribute and sell this software // Permission to use, copy, modify, distribute and sell this software
@@ -17,16 +17,14 @@
# include <windows.h> # include <windows.h>
# if defined(BOOST_NO_STRINGSTREAM) # if defined(BOOST_NO_STRINGSTREAM)
# include <strstream> # include <strstream>
class unfreezer
class unfreezer {
{ public:
public: unfreezer(std::ostrstream& s) : m_stream(s) {}
unfreezer(std::ostrstream& s) : m_stream(s) {} ~unfreezer() { m_stream.freeze(false); }
~unfreezer() { m_stream.freeze(false); } private:
private: std::ostrstream& m_stream;
std::ostrstream& m_stream; };
};
# else # else
# include <sstream> # include <sstream>
# endif # endif
@@ -35,7 +33,7 @@ private:
#endif #endif
#ifdef BOOST_NO_STDC_NAMESPACE #ifdef BOOST_NO_STDC_NAMESPACE
namespace std { using ::sprintf; } namespace std { using ::sprintf; }
#endif #endif
#if defined(BOOST_HAS_PTHREADS) #if defined(BOOST_HAS_PTHREADS)
@@ -48,25 +46,22 @@ typedef void (*once_callback)();
extern "C" { extern "C" {
static void key_init() static void key_init()
{ {
pthread_key_create(&key, 0); pthread_key_create(&key, 0);
} }
static void do_once() static void do_once()
{ {
once_callback* cb = reinterpret_cast<once_callback*>( once_callback* cb = reinterpret_cast<once_callback*>(pthread_getspecific(key));
pthread_getspecific(key)); (**cb)();
(**cb)(); }
}
} }
#elif defined(BOOST_HAS_MPTASKS) #elif defined(BOOST_HAS_MPTASKS)
namespace {
void *remote_call_proxy(void *pData) void *remote_call_proxy(void *pData)
{ {
std::pair<void (*)(), boost::once_flag *> &rData( std::pair<void (*)(), boost::once_flag *> &rData(*reinterpret_cast<std::pair<void (*)(), boost::once_flag *> *>(pData));
*reinterpret_cast<std::pair<void (*)(), boost::once_flag *> *>(pData));
if(*rData.second == false) if(*rData.second == false)
{ {
@@ -76,43 +71,6 @@ void *remote_call_proxy(void *pData)
return(NULL); return(NULL);
} }
}
#elif defined(BOOST_HAS_WINTHREADS)
namespace {
// The signature for InterlockedCompareExchange has changed with the
// addition of Win64 support. I can't determine any (consistent and
// portable) way of using conditional compilation to detect this, so
// we use these type wrappers. Unfortunately, the various vendors
// use different calling conventions and other signature anamolies,
// and thus have unique types as well. This is known to work on VC6,
// VC7, Borland 5.5.2 and gcc 3.2. Are there other signatures for
// other platforms?
inline LONG ice_wrapper(LONG (__stdcall *ice)(LONG*, LONG, LONG),
volatile LONG* dest, LONG exch, LONG cmp)
{
return (*ice)(const_cast<LONG*>(dest), exch, cmp);
}
inline LONG ice_wrapper(LONG (__stdcall *ice)(volatile LONG*, LONG, LONG),
volatile LONG* dest, LONG exch, LONG cmp)
{
return (*ice)(dest, exch, cmp);
}
inline LONG ice_wrapper(LPVOID (__stdcall *ice)(LPVOID*, LPVOID, LPVOID),
volatile LONG* dest, LONG exch, LONG cmp)
{
return (LONG)(*ice)((LPVOID*)dest, (LPVOID)exch, (LPVOID)cmp);
}
// The friendly form of InterlockedCompareExchange that defers
// according to the above function type wrappers.
inline LONG compare_exchange(volatile LPLONG dest, LONG exch, LONG cmp)
{
return ice_wrapper(&InterlockedCompareExchange, dest, exch, cmp);
}
}
#endif #endif
namespace boost { namespace boost {
@@ -120,19 +78,22 @@ namespace boost {
void call_once(void (*func)(), once_flag& flag) void call_once(void (*func)(), once_flag& flag)
{ {
#if defined(BOOST_HAS_WINTHREADS) #if defined(BOOST_HAS_WINTHREADS)
if (compare_exchange(&flag, 1, 1) == 0) once_flag tmp = flag;
// Memory barrier would be needed here to prevent race conditions on some platforms with
// partial ordering.
if (!tmp)
{ {
#if defined(BOOST_NO_STRINGSTREAM) #if defined(BOOST_NO_STRINGSTREAM)
std::ostrstream strm; std::ostrstream strm;
strm << "2AC1A572DB6944B0A65C38C4140AF2F4" << std::hex strm << "2AC1A572DB6944B0A65C38C4140AF2F4" << std::hex << GetCurrentProcessId() << &flag << std::ends;
<< GetCurrentProcessId() << &flag << std::ends;
unfreezer unfreeze(strm); unfreezer unfreeze(strm);
HANDLE mutex = CreateMutex(NULL, FALSE, strm.str()); HANDLE mutex = CreateMutex(NULL, FALSE, strm.str());
#else #else
std::ostringstream strm; std::ostringstream strm;
strm << "2AC1A572DB6944B0A65C38C4140AF2F4" << std::hex strm << "2AC1A572DB6944B0A65C38C4140AF2F4" << std::hex << GetCurrentProcessId() << &flag;
<< GetCurrentProcessId() << &flag; HANDLE mutex = CreateMutex(NULL, FALSE, strm.str().c_str());
HANDLE mutex = CreateMutexA(NULL, FALSE, strm.str().c_str());
#endif #endif
assert(mutex != NULL); assert(mutex != NULL);
@@ -140,10 +101,16 @@ void call_once(void (*func)(), once_flag& flag)
res = WaitForSingleObject(mutex, INFINITE); res = WaitForSingleObject(mutex, INFINITE);
assert(res == WAIT_OBJECT_0); assert(res == WAIT_OBJECT_0);
if (compare_exchange(&flag, 1, 1) == 0) tmp = flag;
if (!tmp)
{ {
func(); func();
InterlockedExchange(&flag, 1); tmp = true;
// Memory barrier would be needed here to prevent race conditions on some platforms
// with partial ordering.
flag = tmp;
} }
res = ReleaseMutex(mutex); res = ReleaseMutex(mutex);
@@ -158,8 +125,7 @@ void call_once(void (*func)(), once_flag& flag)
#elif defined(BOOST_HAS_MPTASKS) #elif defined(BOOST_HAS_MPTASKS)
if(flag == false) if(flag == false)
{ {
// all we do here is make a remote call to blue, as blue is not // all we do here is make a remote call to blue, as blue is not reentrant.
// reentrant.
std::pair<void (*)(), once_flag *> sData(func, &flag); std::pair<void (*)(), once_flag *> sData(func, &flag);
MPRemoteCall(remote_call_proxy, &sData, kMPOwningProcessRemoteContext); MPRemoteCall(remote_call_proxy, &sData, kMPOwningProcessRemoteContext);
assert(flag == true); assert(flag == true);

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2001-2003 // Copyright (C) 2001
// William E. Kempf // William E. Kempf
// //
// Permission to use, copy, modify, distribute and sell this software // Permission to use, copy, modify, distribute and sell this software
@@ -23,23 +23,17 @@
#elif defined(BOOST_HAS_PTHREADS) #elif defined(BOOST_HAS_PTHREADS)
# include <errno.h> # include <errno.h>
#elif defined(BOOST_HAS_MPTASKS) #elif defined(BOOST_HAS_MPTASKS)
# include <MacErrors.h> # include <MacErrors.h>
# include "safe.hpp" # include "safe.hpp"
#endif #endif
namespace boost { namespace boost {
#if defined(BOOST_HAS_WINTHREADS) #if defined(BOOST_HAS_WINTHREADS)
recursive_mutex::recursive_mutex() recursive_mutex::recursive_mutex()
: m_mutex(0), m_count(0) : m_count(0)
{ {
try m_mutex = reinterpret_cast<void*>(new(std::nothrow) CRITICAL_SECTION);
{
m_mutex = reinterpret_cast<void*>(new CRITICAL_SECTION);
}
catch (...)
{
}
if (!m_mutex) if (!m_mutex)
throw thread_resource_error(); throw thread_resource_error();
InitializeCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(m_mutex)); InitializeCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(m_mutex));
@@ -201,36 +195,23 @@ bool recursive_timed_mutex::do_trylock()
bool recursive_timed_mutex::do_timedlock(const xtime& xt) bool recursive_timed_mutex::do_timedlock(const xtime& xt)
{ {
for (;;) int milliseconds;
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)
{ {
int milliseconds; if (++m_count > 1)
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)
{ {
xtime cur; res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
xtime_get(&cur, TIME_UTC); assert(res);
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() void recursive_timed_mutex::do_unlock()
@@ -805,8 +786,7 @@ recursive_mutex::~recursive_mutex()
void recursive_mutex::do_lock() void recursive_mutex::do_lock()
{ {
OSStatus lStatus = noErr; OSStatus lStatus = noErr;
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
m_mutex_mutex);
assert(lStatus == noErr); assert(lStatus == noErr);
if (++m_count > 1) if (++m_count > 1)
@@ -829,8 +809,7 @@ void recursive_mutex::do_unlock()
void recursive_mutex::do_lock(cv_state& state) void recursive_mutex::do_lock(cv_state& state)
{ {
OSStatus lStatus = noErr; OSStatus lStatus = noErr;
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
m_mutex_mutex);
assert(lStatus == noErr); assert(lStatus == noErr);
m_count = state; m_count = state;
@@ -858,8 +837,7 @@ recursive_try_mutex::~recursive_try_mutex()
void recursive_try_mutex::do_lock() void recursive_try_mutex::do_lock()
{ {
OSStatus lStatus = noErr; OSStatus lStatus = noErr;
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
m_mutex_mutex);
assert(lStatus == noErr); assert(lStatus == noErr);
if (++m_count > 1) if (++m_count > 1)
@@ -900,8 +878,7 @@ void recursive_try_mutex::do_unlock()
void recursive_try_mutex::do_lock(cv_state& state) void recursive_try_mutex::do_lock(cv_state& state)
{ {
OSStatus lStatus = noErr; OSStatus lStatus = noErr;
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
m_mutex_mutex);
assert(lStatus == noErr); assert(lStatus == noErr);
m_count = state; m_count = state;
@@ -929,8 +906,7 @@ recursive_timed_mutex::~recursive_timed_mutex()
void recursive_timed_mutex::do_lock() void recursive_timed_mutex::do_lock()
{ {
OSStatus lStatus = noErr; OSStatus lStatus = noErr;
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
m_mutex_mutex);
assert(lStatus == noErr); assert(lStatus == noErr);
if (++m_count > 1) if (++m_count > 1)
@@ -993,8 +969,7 @@ void recursive_timed_mutex::do_unlock()
void recursive_timed_mutex::do_lock(cv_state& state) void recursive_timed_mutex::do_lock(cv_state& state)
{ {
OSStatus lStatus = noErr; OSStatus lStatus = noErr;
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
m_mutex_mutex);
assert(lStatus == noErr); assert(lStatus == noErr);
m_count = state; m_count = state;

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2001-2003 // Copyright (C) 2001
// William E. Kempf // William E. Kempf
// //
// Permission to use, copy, modify, distribute and sell this software // Permission to use, copy, modify, distribute and sell this software
@@ -18,11 +18,11 @@
# include <windows.h> # include <windows.h>
# include <process.h> # include <process.h>
#elif defined(BOOST_HAS_MPTASKS) #elif defined(BOOST_HAS_MPTASKS)
# include <DriverServices.h> # include <DriverServices.h>
# include "init.hpp" # include "init.hpp"
# include "safe.hpp" # include "safe.hpp"
# include <boost/thread/tss.hpp> # include <boost/thread/tss.hpp>
#endif #endif
#include "timeconv.inl" #include "timeconv.inl"
@@ -32,10 +32,7 @@ namespace {
class thread_param class thread_param
{ {
public: public:
thread_param(const boost::function0<void>& threadfunc) thread_param(const boost::function0<void>& threadfunc) : m_threadfunc(threadfunc), m_started(false) { }
: m_threadfunc(threadfunc), m_started(false)
{
}
void wait() void wait()
{ {
boost::mutex::scoped_lock scoped_lock(m_mutex); boost::mutex::scoped_lock scoped_lock(m_mutex);
@@ -59,28 +56,28 @@ public:
extern "C" { extern "C" {
#if defined(BOOST_HAS_WINTHREADS) #if defined(BOOST_HAS_WINTHREADS)
unsigned __stdcall thread_proxy(void* param) unsigned __stdcall thread_proxy(void* param)
#elif defined(BOOST_HAS_PTHREADS) #elif defined(BOOST_HAS_PTHREADS)
static void* thread_proxy(void* param) static void* thread_proxy(void* param)
#elif defined(BOOST_HAS_MPTASKS) #elif defined(BOOST_HAS_MPTASKS)
static OSStatus thread_proxy(void* param) static OSStatus thread_proxy(void* param)
#endif #endif
{
try
{ {
try thread_param* p = static_cast<thread_param*>(param);
{ boost::function0<void> threadfunc = p->m_threadfunc;
thread_param* p = static_cast<thread_param*>(param); p->started();
boost::function0<void> threadfunc = p->m_threadfunc; threadfunc();
p->started();
threadfunc();
}
catch (...)
{
}
#if defined(BOOST_HAS_MPTASKS)
::boost::detail::thread_cleanup();
#endif
return 0;
} }
catch (...)
{
}
#if defined(BOOST_HAS_MPTASKS)
::boost::detail::thread_cleanup();
#endif
return 0;
}
} }
@@ -107,8 +104,7 @@ thread::thread(const function0<void>& threadfunc)
{ {
thread_param param(threadfunc); thread_param param(threadfunc);
#if defined(BOOST_HAS_WINTHREADS) #if defined(BOOST_HAS_WINTHREADS)
m_thread = reinterpret_cast<void*>(_beginthreadex(0, 0, &thread_proxy, m_thread = reinterpret_cast<void*>(_beginthreadex(0, 0, &thread_proxy, &param, 0, &m_id));
&param, 0, &m_id));
if (!m_thread) if (!m_thread)
throw thread_resource_error(); throw thread_resource_error();
#elif defined(BOOST_HAS_PTHREADS) #elif defined(BOOST_HAS_PTHREADS)
@@ -125,11 +121,11 @@ thread::thread(const function0<void>& threadfunc)
m_pTaskID = kInvalidID; m_pTaskID = kInvalidID;
lStatus = MPCreateQueue(&m_pJoinQueueID); lStatus = MPCreateQueue(&m_pJoinQueueID);
if (lStatus != noErr) throw thread_resource_error(); if(lStatus != noErr) throw thread_resource_error();
lStatus = MPCreateTask(&thread_proxy, &param, 0UL, m_pJoinQueueID, NULL, lStatus = MPCreateTask(&thread_proxy, &param, 0UL, m_pJoinQueueID, NULL, NULL,
NULL, 0UL, &m_pTaskID); 0UL, &m_pTaskID);
if (lStatus != noErr) if(lStatus != noErr)
{ {
lStatus = MPDeleteQueue(m_pJoinQueueID); lStatus = MPDeleteQueue(m_pJoinQueueID);
assert(lStatus == noErr); assert(lStatus == noErr);
@@ -185,8 +181,7 @@ void thread::join()
res = pthread_join(m_thread, 0); res = pthread_join(m_thread, 0);
assert(res == 0); assert(res == 0);
#elif defined(BOOST_HAS_MPTASKS) #elif defined(BOOST_HAS_MPTASKS)
OSStatus lStatus = threads::mac::detail::safe_wait_on_queue( OSStatus lStatus = threads::mac::detail::safe_wait_on_queue(m_pJoinQueueID, NULL, NULL, NULL, kDurationForever);
m_pJoinQueueID, NULL, NULL, NULL, kDurationForever);
assert(lStatus == noErr); assert(lStatus == noErr);
#endif #endif
// This isn't a race condition since any race that could occur would // This isn't a race condition since any race that could occur would
@@ -196,44 +191,44 @@ void thread::join()
void thread::sleep(const xtime& xt) void thread::sleep(const xtime& xt)
{ {
for (int foo=0; foo < 5; ++foo) for (;;)
{ {
#if defined(BOOST_HAS_WINTHREADS) #if defined(BOOST_HAS_WINTHREADS)
int milliseconds; int milliseconds;
to_duration(xt, milliseconds); to_duration(xt, milliseconds);
Sleep(milliseconds); Sleep(milliseconds);
xtime xt2;
xtime_get(&xt2, TIME_UTC);
#elif defined(BOOST_HAS_PTHREADS) #elif defined(BOOST_HAS_PTHREADS)
# if defined(BOOST_HAS_PTHREAD_DELAY_NP) # if defined(BOOST_HAS_PTHREAD_DELAY_NP)
timespec ts; timespec ts;
to_timespec_duration(xt, ts); to_timespec_duration(xt, ts);
int res = 0; int res = 0;
res = pthread_delay_np(&ts); res = pthread_delay_np(&ts);
assert(res == 0); assert(res == 0);
# elif defined(BOOST_HAS_NANOSLEEP) # elif defined(BOOST_HAS_NANOSLEEP)
timespec ts; timespec ts;
to_timespec_duration(xt, ts); to_timespec_duration(xt, ts);
// nanosleep takes a timespec that is an offset, not // nanosleep takes a timespec that is an offset, not
// an absolute time. // an absolute time.
nanosleep(&ts, 0); nanosleep(&ts, 0);
# else # else
mutex mx; mutex mx;
mutex::scoped_lock lock(mx); mutex::scoped_lock lock(mx);
condition cond; condition cond;
cond.timed_wait(lock, xt); cond.timed_wait(lock, xt);
# endif # endif
#elif defined(BOOST_HAS_MPTASKS) #elif defined(BOOST_HAS_MPTASKS)
int microseconds; int microseconds;
to_microduration(xt, microseconds); to_microduration(xt, microseconds);
Duration lMicroseconds(kDurationMicrosecond * microseconds); Duration lMicroseconds(kDurationMicrosecond * microseconds);
AbsoluteTime sWakeTime(DurationToAbsolute(lMicroseconds)); AbsoluteTime sWakeTime(DurationToAbsolute(lMicroseconds));
threads::mac::detail::safe_delay_until(&sWakeTime); threads::mac::detail::safe_delay_until(&sWakeTime);
#endif #endif
xtime cur; if (xtime_cmp(xt, xt2) >= 0)
xtime_get(&cur, TIME_UTC); return;
if (xtime_cmp(xt, cur) <= 0) }
return;
}
} }
void thread::yield() void thread::yield()
@@ -265,20 +260,17 @@ thread_group::thread_group()
thread_group::~thread_group() thread_group::~thread_group()
{ {
// We shouldn't have to scoped_lock here, since referencing this object // We shouldn't have to scoped_lock here, since referencing this object from another thread
// from another thread while we're deleting it in the current thread is // while we're deleting it in the current thread is going to lead to undefined behavior
// going to lead to undefined behavior any way. // any way.
for (std::list<thread*>::iterator it = m_threads.begin(); for (std::list<thread*>::iterator it = m_threads.begin(); it != m_threads.end(); ++it)
it != m_threads.end(); ++it)
{
delete (*it); delete (*it);
}
} }
thread* thread_group::create_thread(const function0<void>& threadfunc) thread* thread_group::create_thread(const function0<void>& threadfunc)
{ {
// No scoped_lock required here since the only "shared data" that's // No scoped_lock required here since the only "shared data" that's modified here occurs
// modified here occurs inside add_thread which does scoped_lock. // inside add_thread which does scoped_lock.
std::auto_ptr<thread> thrd(new thread(threadfunc)); std::auto_ptr<thread> thrd(new thread(threadfunc));
add_thread(thrd.get()); add_thread(thrd.get());
return thrd.release(); return thrd.release();
@@ -288,11 +280,9 @@ void thread_group::add_thread(thread* thrd)
{ {
mutex::scoped_lock scoped_lock(m_mutex); mutex::scoped_lock scoped_lock(m_mutex);
// For now we'll simply ignore requests to add a thread object multiple // For now we'll simply ignore requests to add a thread object multiple times.
// times. Should we consider this an error and either throw or return an // Should we consider this an error and either throw or return an error value?
// error value? std::list<thread*>::iterator it = std::find(m_threads.begin(), m_threads.end(), thrd);
std::list<thread*>::iterator it = std::find(m_threads.begin(),
m_threads.end(), thrd);
assert(it == m_threads.end()); assert(it == m_threads.end());
if (it == m_threads.end()) if (it == m_threads.end())
m_threads.push_back(thrd); m_threads.push_back(thrd);
@@ -302,11 +292,9 @@ void thread_group::remove_thread(thread* thrd)
{ {
mutex::scoped_lock scoped_lock(m_mutex); mutex::scoped_lock scoped_lock(m_mutex);
// For now we'll simply ignore requests to remove a thread object that's // For now we'll simply ignore requests to remove a thread object that's not in the group.
// not in the group. Should we consider this an error and either throw or // Should we consider this an error and either throw or return an error value?
// return an error value? std::list<thread*>::iterator it = std::find(m_threads.begin(), m_threads.end(), thrd);
std::list<thread*>::iterator it = std::find(m_threads.begin(),
m_threads.end(), thrd);
assert(it != m_threads.end()); assert(it != m_threads.end());
if (it != m_threads.end()) if (it != m_threads.end())
m_threads.erase(it); m_threads.erase(it);
@@ -315,11 +303,8 @@ void thread_group::remove_thread(thread* thrd)
void thread_group::join_all() void thread_group::join_all()
{ {
mutex::scoped_lock scoped_lock(m_mutex); mutex::scoped_lock scoped_lock(m_mutex);
for (std::list<thread*>::iterator it = m_threads.begin(); for (std::list<thread*>::iterator it = m_threads.begin(); it != m_threads.end(); ++it)
it != m_threads.end(); ++it)
{
(*it)->join(); (*it)->join();
}
} }
} // namespace boost } // namespace boost

View File

@@ -1,23 +1,12 @@
// Copyright (C) 2001-2003 // threadmon.cpp : Defines the entry point for the DLL application.
// William E. Kempf
// //
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/config.hpp> #define BOOST_THREADMON_EXPORTS
#include "threadmon.hpp"
#if defined(BOOST_HAS_WINTHREADS) #ifdef BOOST_HAS_WINTHREADS
#if defined(BOOST_THREAD_BUILD_DLL) #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#include <boost/thread/detail/threadmon.hpp>
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#include <windows.h> #include <windows.h>
#ifdef BOOST_MSVC #ifdef BOOST_MSVC
@@ -34,9 +23,9 @@ typedef std::set<exit_handlers*> registered_handlers;
namespace namespace
{ {
CRITICAL_SECTION cs; CRITICAL_SECTION cs;
DWORD key; DWORD key;
registered_handlers registry; registered_handlers registry;
} }
#if defined(__BORLANDC__) #if defined(__BORLANDC__)
@@ -44,75 +33,61 @@ registered_handlers registry;
#endif #endif
extern "C" extern "C"
BOOL WINAPI DllMain(HANDLE /*module*/, DWORD reason, LPVOID) BOOL WINAPI DllMain(HANDLE module, DWORD reason, LPVOID)
{ {
switch (reason) switch (reason)
{ {
case DLL_PROCESS_ATTACH: case DLL_PROCESS_ATTACH:
InitializeCriticalSection(&cs); InitializeCriticalSection(&cs);
key = TlsAlloc(); key = TlsAlloc();
break; break;
case DLL_THREAD_ATTACH: case DLL_THREAD_ATTACH:
break; break;
case DLL_THREAD_DETACH: case DLL_THREAD_DETACH:
{
// Call the thread's exit handlers.
exit_handlers* handlers =
static_cast<exit_handlers*>(TlsGetValue(key));
if (handlers)
{
for (exit_handlers::iterator it = handlers->begin();
it != handlers->end(); ++it)
{ {
(*it)(); // Call the thread's exit handlers.
} exit_handlers* handlers = static_cast<exit_handlers*>(TlsGetValue(key));
if (handlers)
{
for (exit_handlers::iterator it = handlers->begin(); it != handlers->end(); ++it)
(*it)();
// Remove the exit handler list from the registered lists // Remove the exit handler list from the registered lists and then destroy it.
// and then destroy it. EnterCriticalSection(&cs);
EnterCriticalSection(&cs); registry.erase(handlers);
registry.erase(handlers); LeaveCriticalSection(&cs);
LeaveCriticalSection(&cs); delete handlers;
delete handlers; }
} }
} break;
break; case DLL_PROCESS_DETACH:
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)(); // 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 // Destroy any remaining exit handlers. Above we assumed there'd only be the main
// there'd only be the main thread left, but to insure we // thread left, but to insure we don't get memory leaks we won't make that assumption
// don't get memory leaks we won't make that assumption // here.
// here. EnterCriticalSection(&cs);
EnterCriticalSection(&cs); for (registered_handlers::iterator it = registry.begin(); it != registry.end(); ++it)
for (registered_handlers::iterator it = registry.begin(); delete (*it);
it != registry.end(); ++it) LeaveCriticalSection(&cs);
{ DeleteCriticalSection(&cs);
delete (*it); TlsFree(key);
} }
LeaveCriticalSection(&cs); break;
DeleteCriticalSection(&cs);
TlsFree(key);
}
break;
} }
return TRUE; return TRUE;
} }
extern "C" BOOST_THREAD_DECL int on_thread_exit(void (__cdecl * func)(void)) int on_thread_exit(void (__cdecl * func)(void))
{ {
// Get the exit handlers for the current thread, creating and registering // Get the exit handlers for the current thread, creating and registering
// one if it doesn't exist. // one if it doesn't exist.
@@ -122,7 +97,7 @@ extern "C" BOOST_THREAD_DECL int on_thread_exit(void (__cdecl * func)(void))
try try
{ {
handlers = new exit_handlers; handlers = new exit_handlers;
// Handle broken implementations of operator new that don't throw. // Handle "broken" implementations of operator new that don't throw.
if (!handlers) if (!handlers)
return -1; return -1;
} }
@@ -154,8 +129,8 @@ extern "C" BOOST_THREAD_DECL int on_thread_exit(void (__cdecl * func)(void))
} }
} }
// Attempt to add the handler to the list of exit handlers. If it's been // Attempt to add the handler to the list of exit handlers. If it's been previously
// previously added just report success and exit. // added just report success and exit.
try try
{ {
handlers->push_front(func); handlers->push_front(func);
@@ -168,6 +143,4 @@ extern "C" BOOST_THREAD_DECL int on_thread_exit(void (__cdecl * func)(void))
return 0; return 0;
} }
#endif // BOOST_THREAD_BUILD_DLL
#endif // BOOST_HAS_WINTHREADS #endif // BOOST_HAS_WINTHREADS

23
src/threadmon.hpp Normal file
View File

@@ -0,0 +1,23 @@
#include <boost/config.hpp>
#ifndef BOOST_HAS_THREADS
# error Thread support is unavailable!
#endif
#ifdef BOOST_HAS_WINTHREADS
// The following ifdef block is the standard way of creating macros which make exporting
// from a DLL simpler. All files within this DLL are compiled with the BOOST_THREADMON_EXPORTS
// symbol defined on the command line. this symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see
// BOOST_THREADMON_API functions as being imported from a DLL, wheras this DLL sees symbols
// defined with this macro as being exported.
#ifdef BOOST_THREADMON_EXPORTS
#define BOOST_THREADMON_API __declspec(dllexport)
#else
#define BOOST_THREADMON_API __declspec(dllimport)
#endif
extern "C" BOOST_THREADMON_API int on_thread_exit(void (__cdecl * func)(void));
#endif // BOOST_HAS_WINTHREADS

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2001-2003 // Copyright (C) 2001
// William E. Kempf // William E. Kempf
// //
// Permission to use, copy, modify, distribute and sell this software // Permission to use, copy, modify, distribute and sell this software
@@ -10,119 +10,113 @@
// It is provided "as is" without express or implied warranty. // It is provided "as is" without express or implied warranty.
namespace { namespace {
const int MILLISECONDS_PER_SECOND = 1000; const int MILLISECONDS_PER_SECOND = 1000;
const int NANOSECONDS_PER_SECOND = 1000000000; const int NANOSECONDS_PER_SECOND = 1000000000;
const int NANOSECONDS_PER_MILLISECOND = 1000000; const int NANOSECONDS_PER_MILLISECOND = 1000000;
const int MICROSECONDS_PER_SECOND = 1000000; const int MICROSECONDS_PER_SECOND = 1000000;
const int NANOSECONDS_PER_MICROSECOND = 1000; const int NANOSECONDS_PER_MICROSECOND = 1000;
inline void to_time(int milliseconds, boost::xtime& xt) inline void to_time(int milliseconds, boost::xtime& xt)
{
int res = 0;
res = boost::xtime_get(&xt, boost::TIME_UTC);
assert(res == boost::TIME_UTC);
xt.sec += (milliseconds / MILLISECONDS_PER_SECOND);
xt.nsec += ((milliseconds % MILLISECONDS_PER_SECOND) *
NANOSECONDS_PER_MILLISECOND);
if (xt.nsec > static_cast<const int>(NANOSECONDS_PER_SECOND))
{ {
++xt.sec; int res = 0;
xt.nsec -= NANOSECONDS_PER_SECOND; res = boost::xtime_get(&xt, boost::TIME_UTC);
assert(res == boost::TIME_UTC);
xt.sec += (milliseconds / MILLISECONDS_PER_SECOND);
xt.nsec += ((milliseconds % MILLISECONDS_PER_SECOND) * NANOSECONDS_PER_MILLISECOND);
if (xt.nsec > static_cast<const int>(NANOSECONDS_PER_SECOND))
{
++xt.sec;
xt.nsec -= NANOSECONDS_PER_SECOND;
}
} }
}
#if defined(BOOST_HAS_PTHREADS) #if defined(BOOST_HAS_PTHREADS)
inline void to_timespec(const boost::xtime& xt, timespec& ts) inline void to_timespec(const boost::xtime& xt, timespec& ts)
{
ts.tv_sec = static_cast<int>(xt.sec);
ts.tv_nsec = static_cast<int>(xt.nsec);
if(ts.tv_nsec > static_cast<const int>(NANOSECONDS_PER_SECOND))
{ {
ts.tv_sec += ts.tv_nsec / NANOSECONDS_PER_SECOND; ts.tv_sec = static_cast<int>(xt.sec);
ts.tv_nsec %= NANOSECONDS_PER_SECOND; ts.tv_nsec = static_cast<int>(xt.nsec);
}
}
inline void to_time(int milliseconds, timespec& ts)
{
boost::xtime xt;
to_time(milliseconds, xt);
to_timespec(xt, ts);
}
inline void to_timespec_duration(const boost::xtime& xt, timespec& ts)
{
boost::xtime cur;
int res = 0;
res = boost::xtime_get(&cur, boost::TIME_UTC);
assert(res == boost::TIME_UTC);
if (boost::xtime_cmp(xt, cur) <= 0)
{
ts.tv_sec = 0;
ts.tv_nsec = 0;
}
else
{
ts.tv_sec = xt.sec - cur.sec;
ts.tv_nsec = xt.nsec - cur.nsec;
if( ts.tv_nsec < 0 )
{
ts.tv_sec -= 1;
ts.tv_nsec += NANOSECONDS_PER_SECOND;
}
if(ts.tv_nsec > static_cast<const int>(NANOSECONDS_PER_SECOND)) if(ts.tv_nsec > static_cast<const int>(NANOSECONDS_PER_SECOND))
{ {
ts.tv_sec += ts.tv_nsec / NANOSECONDS_PER_SECOND; ts.tv_sec += ts.tv_nsec / NANOSECONDS_PER_SECOND;
ts.tv_nsec %= NANOSECONDS_PER_SECOND; ts.tv_nsec %= NANOSECONDS_PER_SECOND;
} }
} }
}
inline void to_time(int milliseconds, timespec& ts)
{
boost::xtime xt;
to_time(milliseconds, xt);
to_timespec(xt, ts);
}
inline void to_timespec_duration(const boost::xtime& xt, timespec& ts)
{
boost::xtime cur;
int res = 0;
res = boost::xtime_get(&cur, boost::TIME_UTC);
assert(res == boost::TIME_UTC);
if (xt.sec < cur.sec || (xt.sec == cur.sec && xt.nsec < cur.nsec))
{
ts.tv_sec = 0;
ts.tv_nsec = 0;
}
else
{
ts.tv_sec = xt.sec - cur.sec;
ts.tv_nsec = xt.nsec - cur.nsec;
if( ts.tv_nsec < 0 )
{
ts.tv_sec -= 1;
ts.tv_nsec += NANOSECONDS_PER_SECOND;
}
if(ts.tv_nsec > static_cast<const int>(NANOSECONDS_PER_SECOND))
{
ts.tv_sec += ts.tv_nsec / NANOSECONDS_PER_SECOND;
ts.tv_nsec %= NANOSECONDS_PER_SECOND;
}
}
}
#endif #endif
inline void to_duration(boost::xtime xt, int& milliseconds) inline void to_duration(const boost::xtime& xt, int& milliseconds)
{
boost::xtime cur;
int res = 0;
res = boost::xtime_get(&cur, boost::TIME_UTC);
assert(res == boost::TIME_UTC);
if (boost::xtime_cmp(xt, cur) <= 0)
milliseconds = 0;
else
{ {
if (cur.nsec > xt.nsec) boost::xtime cur;
int res = 0;
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))
milliseconds = 0;
else
{ {
xt.nsec += NANOSECONDS_PER_SECOND; milliseconds = ((xt.sec - cur.sec) * MILLISECONDS_PER_SECOND) +
--xt.sec; (((xt.nsec - cur.nsec) + (NANOSECONDS_PER_MILLISECOND/2)) /
}
milliseconds = (int)((xt.sec - cur.sec) * MILLISECONDS_PER_SECOND) +
(((xt.nsec - cur.nsec) + (NANOSECONDS_PER_MILLISECOND/2)) /
NANOSECONDS_PER_MILLISECOND); NANOSECONDS_PER_MILLISECOND);
}
} }
}
inline void to_microduration(const boost::xtime& xt, int& microseconds) inline void to_microduration(const boost::xtime& xt, int& microseconds)
{
boost::xtime cur;
int res = 0;
res = boost::xtime_get(&cur, boost::TIME_UTC);
assert(res == boost::TIME_UTC);
if (boost::xtime_get(&cur, boost::TIME_UTC) <= 0)
microseconds = 0;
else
{ {
microseconds = (int)((xt.sec - cur.sec) * MICROSECONDS_PER_SECOND) + boost::xtime cur;
(((xt.nsec - cur.nsec) + (NANOSECONDS_PER_MICROSECOND/2)) / int res = 0;
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))
microseconds = 0;
else
{
microseconds = ((xt.sec - cur.sec) * MICROSECONDS_PER_SECOND) +
(((xt.nsec - cur.nsec) + (NANOSECONDS_PER_MICROSECOND/2)) /
NANOSECONDS_PER_MICROSECOND); NANOSECONDS_PER_MICROSECOND);
}
} }
} }
}
// Change Log: // Change Log:
// 1 Jun 01 Initial creation. // 1 Jun 01 Initial creation.

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2001-2003 // Copyright (C) 2001
// William E. Kempf // William E. Kempf
// //
// Permission to use, copy, modify, distribute and sell this software // Permission to use, copy, modify, distribute and sell this software
@@ -20,103 +20,97 @@
#endif #endif
#if defined(BOOST_HAS_WINTHREADS) #if defined(BOOST_HAS_WINTHREADS)
#include <boost/thread/detail/threadmon.hpp> #include "threadmon.hpp"
#include <map> #include <map>
namespace { namespace {
typedef std::pair<void(*)(void*), void*> cleanup_info; typedef std::pair<void(*)(void*), void*> cleanup_info;
typedef std::map<int, cleanup_info> cleanup_handlers; typedef std::map<int, cleanup_info> cleanup_handlers;
DWORD key; DWORD key;
boost::once_flag once = BOOST_ONCE_INIT; boost::once_flag once = BOOST_ONCE_INIT;
void init_cleanup_key() void init_cleanup_key()
{
key = TlsAlloc();
assert(key != 0xFFFFFFFF);
}
void __cdecl cleanup()
{
cleanup_handlers* handlers = static_cast<cleanup_handlers*>(
TlsGetValue(key));
for (cleanup_handlers::iterator it = handlers->begin();
it != handlers->end(); ++it)
{ {
cleanup_info info = it->second; key = TlsAlloc();
if (info.second) assert(key != 0xFFFFFFFF);
info.first(info.second);
}
delete handlers;
}
cleanup_handlers* get_handlers()
{
boost::call_once(&init_cleanup_key, once);
cleanup_handlers* handlers = static_cast<cleanup_handlers*>(
TlsGetValue(key));
if (!handlers)
{
try
{
handlers = new cleanup_handlers;
}
catch (...)
{
return 0;
}
int res = 0;
res = TlsSetValue(key, handlers);
assert(res);
res = on_thread_exit(&cleanup);
assert(res == 0);
} }
return handlers; void __cdecl cleanup()
} {
cleanup_handlers* handlers = static_cast<cleanup_handlers*>(TlsGetValue(key));
for (cleanup_handlers::iterator it = handlers->begin(); it != handlers->end(); ++it)
{
cleanup_info info = it->second;
if (info.second)
info.first(info.second);
}
delete handlers;
}
cleanup_handlers* get_handlers()
{
boost::call_once(&init_cleanup_key, once);
cleanup_handlers* handlers = static_cast<cleanup_handlers*>(TlsGetValue(key));
if (!handlers)
{
try
{
handlers = new cleanup_handlers;
}
catch (...)
{
return 0;
}
int res = 0;
res = TlsSetValue(key, handlers);
assert(res);
res = on_thread_exit(&cleanup);
assert(res == 0);
}
return handlers;
}
} }
#elif defined(BOOST_HAS_MPTASKS) #elif defined(BOOST_HAS_MPTASKS)
#include <map> #include <map>
namespace { namespace {
typedef std::pair<void(*)(void*), void*> cleanup_info; typedef std::pair<void(*)(void*), void*> cleanup_info;
typedef std::map<int, cleanup_info> cleanup_handlers; typedef std::map<int, cleanup_info> cleanup_handlers;
TaskStorageIndex key; TaskStorageIndex key;
boost::once_flag once = BOOST_ONCE_INIT; boost::once_flag once = BOOST_ONCE_INIT;
void init_cleanup_key() void init_cleanup_key()
{
OSStatus lStatus = MPAllocateTaskStorageIndex(&key);
assert(lStatus == noErr);
}
cleanup_handlers* get_handlers()
{
boost::call_once(&init_cleanup_key, once);
cleanup_handlers* handlers = reinterpret_cast<cleanup_handlers*>(
MPGetTaskStorageValue(key));
if (!handlers)
{ {
try OSStatus lStatus = MPAllocateTaskStorageIndex(&key);
{
handlers = new cleanup_handlers;
}
catch (...)
{
return 0;
}
OSStatus lStatus = noErr;
lStatus = MPSetTaskStorageValue(key,
reinterpret_cast<TaskStorageValue>(handlers));
assert(lStatus == noErr); assert(lStatus == noErr);
// TODO - create a generalized mechanism for registering thread exit
// functions and use it here.
} }
return handlers; cleanup_handlers* get_handlers()
} {
boost::call_once(&init_cleanup_key, once);
cleanup_handlers* handlers = reinterpret_cast<cleanup_handlers*>(MPGetTaskStorageValue(key));
if (!handlers)
{
try
{
handlers = new cleanup_handlers;
}
catch (...)
{
return 0;
}
OSStatus lStatus = noErr;
lStatus = MPSetTaskStorageValue(key, reinterpret_cast<TaskStorageValue>(handlers));
assert(lStatus == noErr);
// TODO - create a generalized mechanism for registering thread exit functions
// and use it here.
}
return handlers;
}
} }
namespace boost { namespace boost {
@@ -126,12 +120,10 @@ namespace detail {
void thread_cleanup() void thread_cleanup()
{ {
cleanup_handlers* handlers = reinterpret_cast<cleanup_handlers*>( cleanup_handlers* handlers = reinterpret_cast<cleanup_handlers*>(MPGetTaskStorageValue(key));
MPGetTaskStorageValue(key));
if(handlers != NULL) if(handlers != NULL)
{ {
for (cleanup_handlers::iterator it = handlers->begin(); for (cleanup_handlers::iterator it = handlers->begin(); it != handlers->end(); ++it)
it != handlers->end(); ++it)
{ {
cleanup_info info = it->second; cleanup_info info = it->second;
if (info.second) if (info.second)
@@ -243,8 +235,7 @@ bool tss::set(void* value)
cleanup_info info(m_cleanup, value); cleanup_info info(m_cleanup, value);
(*handlers)[m_key] = info; (*handlers)[m_key] = info;
} }
OSStatus lStatus = MPSetTaskStorageValue(m_key, OSStatus lStatus = MPSetTaskStorageValue(m_key, reinterpret_cast<TaskStorageValue>(value));
reinterpret_cast<TaskStorageValue>(value));
return(lStatus == noErr); return(lStatus == noErr);
} }
#endif #endif

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2001-2003 // Copyright (C) 2001
// William E. Kempf // William E. Kempf
// //
// Permission to use, copy, modify, distribute and sell this software // Permission to use, copy, modify, distribute and sell this software
@@ -33,30 +33,29 @@ struct startup_time_info
{ {
startup_time_info() startup_time_info()
{ {
// 1970 Jan 1 at 00:00:00 // 1970 Jan 1 at 00:00:00
static const DateTimeRec k_sUNIXBase = {1970, 1, 1, 0, 0, 0, 0}; static const DateTimeRec k_sUNIXBase = {1970, 1, 1, 0, 0, 0, 0};
static unsigned long s_ulUNIXBaseSeconds = 0UL; static unsigned long s_ulUNIXBaseSeconds = 0UL;
if(s_ulUNIXBaseSeconds == 0UL) if(s_ulUNIXBaseSeconds == 0UL)
{ {
// calculate the number of seconds between the Mac OS base and the // calculate the number of seconds between the Mac OS base and the UNIX base
// UNIX base the first time we enter this constructor. // the first time we enter this constructor.
DateToSeconds(&k_sUNIXBase, &s_ulUNIXBaseSeconds); DateToSeconds(&k_sUNIXBase, &s_ulUNIXBaseSeconds);
} }
unsigned long ulSeconds; unsigned long ulSeconds;
// get the time in UpTime units twice, with the time in seconds in the // get the time in UpTime units twice, with the time in seconds in the middle.
// middle.
uint64_t ullFirstUpTime = force_cast<uint64_t>(UpTime()); uint64_t ullFirstUpTime = force_cast<uint64_t>(UpTime());
GetDateTime(&ulSeconds); GetDateTime(&ulSeconds);
uint64_t ullSecondUpTime = force_cast<uint64_t>(UpTime()); uint64_t ullSecondUpTime = force_cast<uint64_t>(UpTime());
// calculate the midpoint of the two UpTimes, and save that. // calculate the midpoint of the two UpTimes, and save that.
uint64_t ullAverageUpTime = (ullFirstUpTime + ullSecondUpTime) / 2ULL; uint64_t ullAverageUpTime = (ullFirstUpTime + ullSecondUpTime) / 2ULL;
m_sStartupAbsoluteTime = force_cast<AbsoluteTime>(ullAverageUpTime); m_sStartupAbsoluteTime = force_cast<AbsoluteTime>(ullAverageUpTime);
// save the number of seconds, recentered at the UNIX base. // save the number of seconds, recentered at the UNIX base.
m_ulStartupSeconds = ulSeconds - s_ulUNIXBaseSeconds; m_ulStartupSeconds = ulSeconds - s_ulUNIXBaseSeconds;
} }
@@ -78,13 +77,10 @@ int xtime_get(struct xtime* xtp, int clock_type)
#if defined(BOOST_HAS_FTIME) #if defined(BOOST_HAS_FTIME)
FILETIME ft; FILETIME ft;
GetSystemTimeAsFileTime(&ft); GetSystemTimeAsFileTime(&ft);
const boost::uint64_t TIMESPEC_TO_FILETIME_OFFSET = const boost::uint64_t TIMESPEC_TO_FILETIME_OFFSET = ((boost::uint64_t)27111902UL << 32) + (boost::uint64_t)3577643008UL;
((boost::uint64_t)27111902UL << 32) + xtp->sec = (int)((*(__int64*)&ft - TIMESPEC_TO_FILETIME_OFFSET) / 10000000);
(boost::uint64_t)3577643008UL;
xtp->sec = (int)((*(__int64*)&ft - TIMESPEC_TO_FILETIME_OFFSET) /
10000000);
xtp->nsec = (int)((*(__int64*)&ft - TIMESPEC_TO_FILETIME_OFFSET - xtp->nsec = (int)((*(__int64*)&ft - TIMESPEC_TO_FILETIME_OFFSET -
((__int64)xtp->sec * (__int64)10000000)) * 100); ((__int64)xtp->sec * (__int64)10000000)) * 100);
return clock_type; return clock_type;
#elif defined(BOOST_HAS_GETTIMEOFDAY) #elif defined(BOOST_HAS_GETTIMEOFDAY)
struct timeval tv; struct timeval tv;
@@ -100,16 +96,12 @@ int xtime_get(struct xtime* xtp, int clock_type)
return clock_type; return clock_type;
#elif defined(BOOST_HAS_MPTASKS) #elif defined(BOOST_HAS_MPTASKS)
using detail::thread::force_cast; using detail::thread::force_cast;
// the Mac OS does not have an MP-safe way of getting the date/time, // the Mac OS does not have an MP-safe way of getting the date/time, so we use a
// so we use a delta from the startup time. We _could_ defer this // delta from the startup time. We _could_ defer this and use something that is
// and use something that is interrupt-safe, but this would be _SLOW_, // interrupt-safe, but this would be _SLOW_, and we need speed here.
// and we need speed here.
const uint64_t k_ullNanosecondsPerSecond(1000ULL * 1000ULL * 1000ULL); const uint64_t k_ullNanosecondsPerSecond(1000ULL * 1000ULL * 1000ULL);
AbsoluteTime sUpTime(UpTime()); AbsoluteTime sUpTime(UpTime());
uint64_t ullNanoseconds( uint64_t ullNanoseconds(force_cast<uint64_t>(AbsoluteDeltaToNanoseconds(sUpTime, detail::g_sStartupTimeInfo.m_sStartupAbsoluteTime)));
force_cast<uint64_t>(
AbsoluteDeltaToNanoseconds(sUpTime,
detail::g_sStartupTimeInfo.m_sStartupAbsoluteTime)));
uint64_t ullSeconds = (ullNanoseconds / k_ullNanosecondsPerSecond); uint64_t ullSeconds = (ullNanoseconds / k_ullNanosecondsPerSecond);
ullNanoseconds -= (ullSeconds * k_ullNanosecondsPerSecond); ullNanoseconds -= (ullSeconds * k_ullNanosecondsPerSecond);
xtp->sec = detail::g_sStartupTimeInfo.m_ulStartupSeconds + ullSeconds; xtp->sec = detail::g_sStartupTimeInfo.m_ulStartupSeconds + ullSeconds;

View File

@@ -1,10 +1,12 @@
# (C) Copyright William E. Kempf 2001. Permission to copy, use, modify, sell # (C) Copyright William E. Kempf 2001. Permission to copy, use, modify, sell and
# and distribute this software is granted provided this copyright notice # distribute this software is granted provided this copyright notice appears
# appears in all copies. This software is provided "as is" without express or # in all copies. This software is provided "as is" without express or implied
# implied warranty, and with no claim as to its suitability for any purpose. # warranty, and with no claim as to its suitability for any purpose.
# #
# Boost.Threads test Jamfile # Boost.Threads test Jamfile
# #
# Declares the following targets:
# 1. test_thread, a unit test executable.
# Additional configuration variables used: # Additional configuration variables used:
# 1. PTW32 may be used on Win32 platforms to specify that the pthreads-win32 # 1. PTW32 may be used on Win32 platforms to specify that the pthreads-win32
# library should be used instead of "native" threads. This feature is # library should be used instead of "native" threads. This feature is
@@ -21,31 +23,21 @@ subproject libs/thread/test ;
# Include threads.jam for Boost.Threads global build information. # Include threads.jam for Boost.Threads global build information.
# This greatly simplifies the Jam code needed to configure the build # This greatly simplifies the Jam code needed to configure the build
# for the various Win32 build types. # for the various Win32 build types.
SEARCH on threads.jam = $(BOOST_ROOT)/libs/thread/build ; SEARCH on <module@>threads.jam = $(BOOST_ROOT)/libs/thread/build ;
include threads.jam ; include <module@>threads.jam ;
# bring in rules for testing sources = test.cpp test_thread.cpp test_mutex.cpp test_condition.cpp test_tss.cpp test_once.cpp ;
SEARCH on testing.jam = $(BOOST_BUILD_PATH) ;
include testing.jam ;
{ #######################
template test # Declare the Boost.Threads unit test program test_thread.
## sources ##
: <template>thread_base
<dll>../build/boost_thread
<lib>../../test/build/boost_unit_test_framework
## requirements ##
:
## default build ##
:
;
test-suite "threads" unit-test test_thread
: [ run test_thread.cpp <template>test ] : $(sources)
[ run test_mutex.cpp <template>test ] <lib>../build/boost_thread
[ run test_condition.cpp <template>test ] <lib>../../test/build/unit_test_framework
[ run test_tss.cpp <template>test ] $(threadmon)
[ run test_once.cpp <template>test ] : <sysinclude>$(BOOST_ROOT)
[ run test_xtime.cpp <template>test ] $(pthreads-win32)
; <threading>multi
} : debug release <runtime-link>static/dynamic
;

20
test/test.cpp Normal file
View File

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

Binary file not shown.

View File

@@ -1,101 +1,104 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/condition.hpp> #include <boost/thread/condition.hpp>
#include <boost/thread/thread.hpp> #include <boost/thread/thread.hpp>
#include <boost/thread/xtime.hpp> #include <boost/thread/xtime.hpp>
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
#include "util.inl" namespace
struct condition_test_data
{ {
condition_test_data() : notified(0), awoken(0) { } struct condition_test_data
{
condition_test_data() : notified(0), awoken(0) { }
boost::mutex mutex; boost::mutex mutex;
boost::condition condition; boost::condition condition;
int notified; int notified;
int awoken; int awoken;
}; };
void condition_test_thread(condition_test_data* data) void condition_test_thread(void* param)
{ {
boost::mutex::scoped_lock lock(data->mutex); condition_test_data* data = static_cast<condition_test_data*>(param);
BOOST_CHECK(lock ? true : false); boost::mutex::scoped_lock lock(data->mutex);
while (!(data->notified > 0)) BOOST_CHECK(lock);
data->condition.wait(lock); while (!(data->notified > 0))
BOOST_CHECK(lock ? true : false); data->condition.wait(lock);
data->awoken++; BOOST_CHECK(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;
};
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);
// Test wait.
while (data->notified != 1)
data->condition.wait(lock);
BOOST_CHECK(lock);
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);
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), boost::TIME_UTC);
xt.nsec += 100000000;
while (data->notified != 3)
data->condition.timed_wait(lock, xt);
BOOST_CHECK(lock);
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), boost::TIME_UTC);
xt.sec += 2;
BOOST_CHECK(data->condition.timed_wait(lock, xt, cond_predicate(data->notified, 4)));
BOOST_CHECK(lock);
BOOST_CHECK_EQUAL(data->notified, 4);
data->awoken++;
}
} }
struct cond_predicate void test_condition_notify_one()
{
cond_predicate(int& var, int val) : _var(var), _val(val) { }
bool operator()() { return _var == _val; }
int& _var;
int _val;
};
void condition_test_waits(condition_test_data* data)
{
boost::mutex::scoped_lock lock(data->mutex);
BOOST_CHECK(lock ? true : false);
// Test wait.
while (data->notified != 1)
data->condition.wait(lock);
BOOST_CHECK(lock ? true : false);
BOOST_CHECK_EQUAL(data->notified, 1);
data->awoken++;
data->condition.notify_one();
// Test predicate wait.
data->condition.wait(lock, cond_predicate(data->notified, 2));
BOOST_CHECK(lock ? true : false);
BOOST_CHECK_EQUAL(data->notified, 2);
data->awoken++;
data->condition.notify_one();
// Test timed_wait.
boost::xtime xt = delay(10);
while (data->notified != 3)
data->condition.timed_wait(lock, xt);
BOOST_CHECK(lock ? true : false);
BOOST_CHECK_EQUAL(data->notified, 3);
data->awoken++;
data->condition.notify_one();
// Test predicate timed_wait.
xt = delay(10);
cond_predicate pred(data->notified, 4);
BOOST_CHECK(data->condition.timed_wait(lock, xt, pred));
BOOST_CHECK(lock ? true : false);
BOOST_CHECK(pred());
BOOST_CHECK_EQUAL(data->notified, 4);
data->awoken++;
data->condition.notify_one();
}
void do_test_condition_notify_one()
{ {
condition_test_data data; condition_test_data data;
boost::thread thread(bind(&condition_test_thread, &data)); boost::thread thread(thread_adapter(&condition_test_thread, &data));
{ {
boost::mutex::scoped_lock lock(data.mutex); boost::mutex::scoped_lock lock(data.mutex);
BOOST_CHECK(lock ? true : false); BOOST_CHECK(lock);
data.notified++; data.notified++;
data.condition.notify_one(); data.condition.notify_one();
} }
@@ -104,23 +107,18 @@ void do_test_condition_notify_one()
BOOST_CHECK_EQUAL(data.awoken, 1); BOOST_CHECK_EQUAL(data.awoken, 1);
} }
void test_condition_notify_one() void test_condition_notify_all()
{
timed_test(&do_test_condition_notify_one, 2, execution_monitor::use_mutex);
}
void do_test_condition_notify_all()
{ {
const int NUMTHREADS = 5; const int NUMTHREADS = 5;
boost::thread_group threads; boost::thread_group threads;
condition_test_data data; condition_test_data data;
for (int i = 0; i < NUMTHREADS; ++i) for (int i = 0; i < NUMTHREADS; ++i)
threads.create_thread(bind(&condition_test_thread, &data)); threads.create_thread(thread_adapter(&condition_test_thread, &data));
{ {
boost::mutex::scoped_lock lock(data.mutex); boost::mutex::scoped_lock lock(data.mutex);
BOOST_CHECK(lock ? true : false); BOOST_CHECK(lock);
data.notified++; data.notified++;
data.condition.notify_all(); data.condition.notify_all();
} }
@@ -129,77 +127,65 @@ void do_test_condition_notify_all()
BOOST_CHECK_EQUAL(data.awoken, NUMTHREADS); BOOST_CHECK_EQUAL(data.awoken, NUMTHREADS);
} }
void test_condition_notify_all() void test_condition_waits()
{
// We should have already tested notify_one here, so
// a timed test with the default execution_monitor::use_condition
// should be OK, and gives the fastest performance
timed_test(&do_test_condition_notify_all, 3);
}
void do_test_condition_waits()
{ {
condition_test_data data; condition_test_data data;
boost::thread thread(bind(&condition_test_waits, &data)); boost::thread thread(thread_adapter(&condition_test_waits, &data));
boost::xtime xt;
{ {
boost::mutex::scoped_lock lock(data.mutex); boost::mutex::scoped_lock lock(data.mutex);
BOOST_CHECK(lock ? true : false); BOOST_CHECK(lock);
boost::thread::sleep(delay(1)); BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), boost::TIME_UTC);
xt.sec += 1;
boost::thread::sleep(xt);
data.notified++; data.notified++;
data.condition.notify_one(); data.condition.notify_one();
while (data.awoken != 1) while (data.awoken != 1)
data.condition.wait(lock); data.condition.wait(lock);
BOOST_CHECK(lock ? true : false);
BOOST_CHECK_EQUAL(data.awoken, 1); BOOST_CHECK_EQUAL(data.awoken, 1);
boost::thread::sleep(delay(1)); BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), boost::TIME_UTC);
xt.sec += 1;
boost::thread::sleep(xt);
data.notified++; data.notified++;
data.condition.notify_one(); data.condition.notify_one();
while (data.awoken != 2) while (data.awoken != 2)
data.condition.wait(lock); data.condition.wait(lock);
BOOST_CHECK(lock ? true : false);
BOOST_CHECK_EQUAL(data.awoken, 2); BOOST_CHECK_EQUAL(data.awoken, 2);
boost::thread::sleep(delay(1)); BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), boost::TIME_UTC);
xt.sec += 1;
boost::thread::sleep(xt);
data.notified++; data.notified++;
data.condition.notify_one(); data.condition.notify_one();
while (data.awoken != 3) while (data.awoken != 3)
data.condition.wait(lock); data.condition.wait(lock);
BOOST_CHECK(lock ? true : false);
BOOST_CHECK_EQUAL(data.awoken, 3); BOOST_CHECK_EQUAL(data.awoken, 3);
boost::thread::sleep(delay(1));
data.notified++;
data.condition.notify_one();
while (data.awoken != 4)
data.condition.wait(lock);
BOOST_CHECK(lock ? true : false);
BOOST_CHECK_EQUAL(data.awoken, 4);
} }
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), boost::TIME_UTC);
xt.sec += 1;
boost::thread::sleep(xt);
data.notified++;
data.condition.notify_one();
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), boost::TIME_UTC);
xt.sec += 1;
boost::thread::sleep(xt);
thread.join(); thread.join();
BOOST_CHECK_EQUAL(data.awoken, 4); BOOST_CHECK_EQUAL(data.awoken, 4);
} }
void test_condition_waits() boost::unit_test_framework::test_suite* condition_tests()
{ {
// We should have already tested notify_one here, so boost::unit_test_framework::test_suite* test = BOOST_TEST_SUITE("Boost.Threads: condition test suite");
// a timed test with the default execution_monitor::use_condition
// should be OK, and gives the fastest performance
timed_test(&do_test_condition_waits, 12);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) test->add(BOOST_TEST_CASE(&test_condition_notify_one));
{ test->add(BOOST_TEST_CASE(&test_condition_notify_all));
boost::unit_test_framework::test_suite* test = test->add(BOOST_TEST_CASE(&test_condition_waits));
BOOST_TEST_SUITE("Boost.Threads: condition test suite");
test->add(BOOST_TEST_CASE(&test_condition_notify_one)); return test;
test->add(BOOST_TEST_CASE(&test_condition_notify_all)); }
test->add(BOOST_TEST_CASE(&test_condition_waits));
return test;
}

View File

@@ -1,14 +1,3 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/mutex.hpp> #include <boost/thread/mutex.hpp>
#include <boost/thread/recursive_mutex.hpp> #include <boost/thread/recursive_mutex.hpp>
#include <boost/thread/xtime.hpp> #include <boost/thread/xtime.hpp>
@@ -17,43 +6,42 @@
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
#include <boost/test/unit_test_suite_ex.hpp> #include <boost/test/unit_test_suite_ex.hpp>
#define DEFAULT_EXECUTION_MONITOR_TYPE execution_monitor::use_sleep_only
#include "util.inl"
template <typename M> template <typename M>
struct test_lock struct test_lock
{ {
typedef M mutex_type; typedef M mutex_type;
typedef typename M::scoped_lock lock_type; typedef typename M::scoped_lock lock_type;
void operator()() void operator()()
{ {
mutex_type mutex; mutex_type mutex;
boost::condition condition; boost::condition condition;
// Test the lock's constructors. // Test the lock's constructors.
{ {
lock_type lock(mutex, false); lock_type lock(mutex, false);
BOOST_CHECK(!lock); BOOST_CHECK(!lock);
} }
lock_type lock(mutex); lock_type lock(mutex);
BOOST_CHECK(lock ? true : false); BOOST_CHECK(lock);
// Construct and initialize an xtime for a fast time out. // Construct and initialize an xtime for a fast time out.
boost::xtime xt = delay(0, 100); boost::xtime xt;
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), boost::TIME_UTC);
xt.nsec += 100000000;
// Test the lock and the mutex with condition variables. // Test the lock and the mutex with condition variables.
// No one is going to notify this condition variable. We expect to // No one is going to notify this condition variable. We expect to
// time out. // time out.
BOOST_CHECK(!condition.timed_wait(lock, xt)); BOOST_CHECK(!condition.timed_wait(lock, xt));
BOOST_CHECK(lock ? true : false); BOOST_CHECK(lock);
// Test the lock and unlock methods. // Test the lock and unlock methods.
lock.unlock(); lock.unlock();
BOOST_CHECK(!lock); BOOST_CHECK(!lock);
lock.lock(); lock.lock();
BOOST_CHECK(lock ? true : false); BOOST_CHECK(lock);
} }
}; };
template <typename M> template <typename M>
@@ -62,42 +50,44 @@ struct test_trylock
typedef M mutex_type; typedef M mutex_type;
typedef typename M::scoped_try_lock try_lock_type; typedef typename M::scoped_try_lock try_lock_type;
void operator()() void operator()()
{ {
mutex_type mutex; mutex_type mutex;
boost::condition condition; boost::condition condition;
// Test the lock's constructors. // Test the lock's constructors.
{ {
try_lock_type lock(mutex); try_lock_type lock(mutex);
BOOST_CHECK(lock ? true : false); BOOST_CHECK(lock);
} }
{ {
try_lock_type lock(mutex, false); try_lock_type lock(mutex, false);
BOOST_CHECK(!lock); BOOST_CHECK(!lock);
} }
try_lock_type lock(mutex, true); try_lock_type lock(mutex, true);
BOOST_CHECK(lock ? true : false); BOOST_CHECK(lock);
// Construct and initialize an xtime for a fast time out. // Construct and initialize an xtime for a fast time out.
boost::xtime xt = delay(0, 100); boost::xtime xt;
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), boost::TIME_UTC);
xt.nsec += 100000000;
// Test the lock and the mutex with condition variables. // Test the lock and the mutex with condition variables.
// No one is going to notify this condition variable. We expect to // No one is going to notify this condition variable. We expect to
// time out. // time out.
BOOST_CHECK(!condition.timed_wait(lock, xt)); BOOST_CHECK(!condition.timed_wait(lock, xt));
BOOST_CHECK(lock ? true : false); BOOST_CHECK(lock);
// Test the lock, unlock and trylock methods. // Test the lock, unlock and trylock methods.
lock.unlock(); lock.unlock();
BOOST_CHECK(!lock); BOOST_CHECK(!lock);
lock.lock(); lock.lock();
BOOST_CHECK(lock ? true : false); BOOST_CHECK(lock);
lock.unlock(); lock.unlock();
BOOST_CHECK(!lock); BOOST_CHECK(!lock);
BOOST_CHECK(lock.try_lock()); BOOST_CHECK(lock.try_lock());
BOOST_CHECK(lock ? true : false); BOOST_CHECK(lock);
} }
}; };
template <typename M> template <typename M>
@@ -106,143 +96,89 @@ struct test_timedlock
typedef M mutex_type; typedef M mutex_type;
typedef typename M::scoped_timed_lock timed_lock_type; typedef typename M::scoped_timed_lock timed_lock_type;
void operator()() void operator()()
{ {
mutex_type mutex; mutex_type mutex;
boost::condition condition; boost::condition condition;
// Test the lock's constructors. // Test the lock's constructors.
{ {
// Construct and initialize an xtime for a fast time out. // Construct and initialize an xtime for a fast time out.
boost::xtime xt = delay(0, 100); boost::xtime xt;
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), boost::TIME_UTC);
xt.nsec += 100000000;
timed_lock_type lock(mutex, xt); timed_lock_type lock(mutex, xt);
BOOST_CHECK(lock ? true : false); BOOST_CHECK(lock);
} }
{ {
timed_lock_type lock(mutex, false); timed_lock_type lock(mutex, false);
BOOST_CHECK(!lock); BOOST_CHECK(!lock);
} }
timed_lock_type lock(mutex, true); timed_lock_type lock(mutex, true);
BOOST_CHECK(lock ? true : false); BOOST_CHECK(lock);
// Construct and initialize an xtime for a fast time out. // Construct and initialize an xtime for a fast time out.
boost::xtime xt = delay(0, 100); boost::xtime xt;
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), boost::TIME_UTC);
xt.nsec += 100000000;
// Test the lock and the mutex with condition variables. // Test the lock and the mutex with condition variables.
// No one is going to notify this condition variable. We expect to // No one is going to notify this condition variable. We expect to
// time out. // time out.
BOOST_CHECK(!condition.timed_wait(lock, xt)); BOOST_CHECK(!condition.timed_wait(lock, xt));
BOOST_CHECK(lock ? true : false); BOOST_CHECK(lock);
BOOST_CHECK(in_range(xt));
// Test the lock, unlock and timedlock methods. // Test the lock, unlock and timedlock methods.
lock.unlock(); lock.unlock();
BOOST_CHECK(!lock); BOOST_CHECK(!lock);
lock.lock(); lock.lock();
BOOST_CHECK(lock ? true : false); BOOST_CHECK(lock);
lock.unlock(); lock.unlock();
BOOST_CHECK(!lock); BOOST_CHECK(!lock);
xt = delay(0, 100); BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), boost::TIME_UTC);
BOOST_CHECK(lock.timed_lock(xt)); xt.nsec += 100000000;
BOOST_CHECK(lock ? true : false); BOOST_CHECK(lock.timed_lock(xt));
} }
}; };
template <typename M> template <typename M>
struct test_recursive_lock struct test_recursive_lock
{ {
typedef M mutex_type; typedef M mutex;
typedef typename M::scoped_lock lock_type;
void operator()() void operator()()
{ {
mutex_type mx; mutex mx;
lock_type lock1(mx); mutex::scoped_lock lock1(mx);
lock_type lock2(mx); mutex::scoped_lock lock2(mx);
} }
}; };
void do_test_mutex() boost::unit_test_framework::test_suite* mutex_tests()
{ {
test_lock<boost::mutex>()(); boost::unit_test_framework::test_suite* test = BOOST_TEST_SUITE("Boost.Threads: mutex test suite");
}
void test_mutex() test->add(BOOST_TEST_CASE(test_lock<boost::mutex>()));
{
timed_test(&do_test_mutex, 3);
}
void do_test_try_mutex() test->add(BOOST_TEST_CASE(test_lock<boost::try_mutex>()));
{ test->add(BOOST_TEST_CASE(test_trylock<boost::try_mutex>()));
test_lock<boost::try_mutex>()();
test_trylock<boost::try_mutex>()();
}
void test_try_mutex() test->add(BOOST_TEST_CASE(test_lock<boost::timed_mutex>()));
{ test->add(BOOST_TEST_CASE(test_trylock<boost::timed_mutex>()));
timed_test(&do_test_try_mutex, 3); test->add(BOOST_TEST_CASE(test_timedlock<boost::timed_mutex>()));
}
void do_test_timed_mutex() test->add(BOOST_TEST_CASE(test_lock<boost::recursive_mutex>()));
{ test->add(BOOST_TEST_CASE(test_recursive_lock<boost::recursive_mutex>()));
test_lock<boost::timed_mutex>()();
test_trylock<boost::timed_mutex>()();
test_timedlock<boost::timed_mutex>()();
}
void test_timed_mutex() test->add(BOOST_TEST_CASE(test_lock<boost::recursive_try_mutex>()));
{ test->add(BOOST_TEST_CASE(test_trylock<boost::recursive_try_mutex>()));
timed_test(&do_test_timed_mutex, 3); test->add(BOOST_TEST_CASE(test_recursive_lock<boost::recursive_try_mutex>()));
}
void do_test_recursive_mutex() test->add(BOOST_TEST_CASE(test_lock<boost::recursive_timed_mutex>()));
{ test->add(BOOST_TEST_CASE(test_trylock<boost::recursive_timed_mutex>()));
test_lock<boost::recursive_mutex>()(); test->add(BOOST_TEST_CASE(test_timedlock<boost::recursive_timed_mutex>()));
test_recursive_lock<boost::recursive_mutex>()(); test->add(BOOST_TEST_CASE(test_recursive_lock<boost::recursive_timed_mutex>()));
}
void test_recursive_mutex() return test;
{ }
timed_test(&do_test_recursive_mutex, 3);
}
void do_test_recursive_try_mutex()
{
test_lock<boost::recursive_try_mutex>()();
test_trylock<boost::recursive_try_mutex>()();
test_recursive_lock<boost::recursive_try_mutex>()();
}
void test_recursive_try_mutex()
{
timed_test(&do_test_recursive_try_mutex, 3);
}
void do_test_recursive_timed_mutex()
{
test_lock<boost::recursive_timed_mutex>()();
test_trylock<boost::recursive_timed_mutex>()();
test_timedlock<boost::recursive_timed_mutex>()();
test_recursive_lock<boost::recursive_timed_mutex>()();
}
void test_recursive_timed_mutex()
{
timed_test(&do_test_recursive_timed_mutex, 3);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: mutex test suite");
test->add(BOOST_TEST_CASE(&test_mutex));
test->add(BOOST_TEST_CASE(&test_try_mutex));
test->add(BOOST_TEST_CASE(&test_timed_mutex));
test->add(BOOST_TEST_CASE(&test_recursive_mutex));
test->add(BOOST_TEST_CASE(&test_recursive_try_mutex));
test->add(BOOST_TEST_CASE(&test_recursive_timed_mutex));
return test;
}

View File

@@ -1,55 +1,39 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/once.hpp> #include <boost/thread/once.hpp>
#include <boost/thread/thread.hpp> #include <boost/thread/thread.hpp>
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
#include "util.inl" namespace
int once_value = 0;
boost::once_flag once = BOOST_ONCE_INIT;
void init_once_value()
{ {
once_value++; int once_value = 0;
} boost::once_flag once = BOOST_ONCE_INIT;
void test_once_thread() void init_once_value()
{ {
boost::call_once(init_once_value, once); once_value++;
} }
void do_test_once() void test_once_thread()
{ {
const int NUMTHREADS=5; boost::call_once(&init_once_value, once);
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);
} }
void test_once() void test_once()
{ {
timed_test(&do_test_once, 2); 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* once_tests()
{ {
boost::unit_test_framework::test_suite* test = boost::unit_test_framework::test_suite* test = BOOST_TEST_SUITE("Boost.Threads: once test suite");
BOOST_TEST_SUITE("Boost.Threads: once test suite");
test->add(BOOST_TEST_CASE(test_once)); test->add(BOOST_TEST_CASE(&test_once));
return test; return test;
} }

View File

@@ -1,79 +1,89 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/thread.hpp> #include <boost/thread/thread.hpp>
#include <boost/thread/xtime.hpp> #include <boost/thread/xtime.hpp>
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
#define DEFAULT_EXECUTION_MONITOR_TYPE execution_monitor::use_sleep_only namespace
#include "util.inl"
int test_value;
void simple_thread()
{ {
test_value = 999; inline bool xtime_in_range(boost::xtime& xt, int less_seconds, int greater_seconds)
} {
boost::xtime cur;
BOOST_CHECK_EQUAL(boost::xtime_get(&cur, boost::TIME_UTC), boost::TIME_UTC);
void comparison_thread(boost::thread* parent) boost::xtime less = cur;
{ less.sec += less_seconds;
boost::thread thrd;
BOOST_TEST(thrd != *parent); boost::xtime greater = cur;
BOOST_TEST(thrd == boost::thread()); 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() void test_sleep()
{ {
boost::xtime xt = delay(3); boost::xtime xt;
boost::thread::sleep(xt); BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), boost::TIME_UTC);
xt.sec += 5;
boost::thread::sleep(xt);
// Ensure it's in a range instead of checking actual equality due to time // Insure it's in a range instead of checking actual equality due to time lapse
// lapse BOOST_CHECK(xtime_in_range(xt, -1, 1));
BOOST_CHECK(in_range(xt));
}
void do_test_creation()
{
test_value = 0;
boost::thread thrd(&simple_thread);
thrd.join();
BOOST_CHECK_EQUAL(test_value, 999);
} }
void test_creation() void test_creation()
{ {
timed_test(&do_test_creation, 1); test_value = 0;
} boost::thread thrd(&simple_thread);
thrd.join();
void do_test_comparison() BOOST_CHECK_EQUAL(test_value, 999);
{
boost::thread self;
boost::thread thrd(bind(&comparison_thread, &self));
thrd.join();
} }
void test_comparison() void test_comparison()
{ {
timed_test(&do_test_comparison, 1); boost::thread self;
boost::thread thrd(thread_adapter(&comparison_thread, self));
thrd.join();
} }
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) boost::unit_test_framework::test_suite* thread_tests()
{ {
boost::unit_test_framework::test_suite* test = boost::unit_test_framework::test_suite* test = BOOST_TEST_SUITE("Boost.Threads: thread test suite");
BOOST_TEST_SUITE("Boost.Threads: thread test suite");
test->add(BOOST_TEST_CASE(test_sleep)); test->add(BOOST_TEST_CASE(&test_sleep));
test->add(BOOST_TEST_CASE(test_creation)); test->add(BOOST_TEST_CASE(&test_creation));
test->add(BOOST_TEST_CASE(test_comparison)); test->add(BOOST_TEST_CASE(&test_comparison));
return test; return test;
} }

View File

@@ -1,55 +1,45 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/tss.hpp> #include <boost/thread/tss.hpp>
#include <boost/thread/mutex.hpp> #include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp> #include <boost/thread/thread.hpp>
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
#include "util.inl" namespace
boost::mutex tss_mutex;
int tss_instances = 0;
struct tss_value_t
{ {
tss_value_t() boost::mutex tss_mutex;
{ int tss_instances = 0;
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; 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;
};
void test_tss_thread() boost::thread_specific_ptr<tss_value_t> tss_value;
{
tss_value.reset(new tss_value_t()); void test_tss_thread()
for (int i=0; i<1000; ++i) {
{ tss_value.reset(new tss_value_t());
int& n = tss_value->value; for (int i=0; i<1000; ++i)
BOOST_CHECK_EQUAL(n, i); {
++n; int& n = tss_value->value;
} BOOST_CHECK_EQUAL(n, i);
++n;
}
}
} }
void do_test_tss() void test_tss()
{ {
const int NUMTHREADS=5; const int NUMTHREADS=5;
boost::thread_group threads; boost::thread_group threads;
@@ -59,17 +49,11 @@ void do_test_tss()
BOOST_CHECK_EQUAL(tss_instances, 0); BOOST_CHECK_EQUAL(tss_instances, 0);
} }
void test_tss() boost::unit_test_framework::test_suite* tss_tests()
{ {
timed_test(&do_test_tss, 2); boost::unit_test_framework::test_suite* test = BOOST_TEST_SUITE("Boost.Threads: tss test suite");
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) test->add(BOOST_TEST_CASE(&test_tss));
{
boost::unit_test_framework::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: tss test suite");
test->add(BOOST_TEST_CASE(test_tss)); return test;
}
return test;
}

View File

@@ -1,68 +0,0 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/xtime.hpp>
#include <boost/test/unit_test.hpp>
void test_xtime_cmp()
{
boost::xtime xt1, xt2, cur;
BOOST_CHECK_EQUAL(
boost::xtime_get(&cur, boost::TIME_UTC),
static_cast<int>(boost::TIME_UTC));
xt1 = xt2 = cur;
xt1.nsec -= 1;
xt2.nsec += 1;
BOOST_CHECK(boost::xtime_cmp(xt1, cur) < 0);
BOOST_CHECK(boost::xtime_cmp(xt2, cur) > 0);
BOOST_CHECK(boost::xtime_cmp(cur, cur) == 0);
xt1 = xt2 = cur;
xt1.sec -= 1;
xt2.sec += 1;
BOOST_CHECK(boost::xtime_cmp(xt1, cur) < 0);
BOOST_CHECK(boost::xtime_cmp(xt2, cur) > 0);
BOOST_CHECK(boost::xtime_cmp(cur, cur) == 0);
}
void test_xtime_get()
{
boost::xtime orig, cur, old;
BOOST_CHECK_EQUAL(
boost::xtime_get(&orig,
boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
old = orig;
for (int x=0; x < 100; ++x)
{
BOOST_CHECK_EQUAL(
boost::xtime_get(&cur, boost::TIME_UTC),
static_cast<int>(boost::TIME_UTC));
BOOST_CHECK(boost::xtime_cmp(cur, orig) >= 0);
BOOST_CHECK(boost::xtime_cmp(cur, old) >= 0);
old = cur;
}
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: xtime test suite");
test->add(BOOST_TEST_CASE(&test_xtime_cmp));
test->add(BOOST_TEST_CASE(&test_xtime_get));
return test;
}

View File

@@ -1,162 +0,0 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#if !defined(UTIL_INL_WEK01242003)
#define UTIL_INL_WEK01242003
#include <boost/thread/xtime.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/thread.hpp>
#ifndef DEFAULT_EXECUTION_MONITOR_TYPE
# define DEFAULT_EXECUTION_MONITOR_TYPE execution_monitor::use_condition
#endif
namespace
{
inline boost::xtime delay(int secs, int msecs=0, int nsecs=0)
{
const int MILLISECONDS_PER_SECOND = 1000;
const int NANOSECONDS_PER_SECOND = 1000000000;
const int NANOSECONDS_PER_MILLISECOND = 1000000;
boost::xtime xt;
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC),
static_cast<int>(boost::TIME_UTC));
nsecs += xt.nsec;
msecs += nsecs / NANOSECONDS_PER_MILLISECOND;
secs += msecs / MILLISECONDS_PER_SECOND;
nsecs += (msecs % MILLISECONDS_PER_SECOND) * NANOSECONDS_PER_MILLISECOND;
xt.nsec = nsecs % NANOSECONDS_PER_SECOND;
xt.sec += secs + (nsecs / NANOSECONDS_PER_SECOND);
return xt;
}
inline bool in_range(const boost::xtime& xt, int secs=1)
{
boost::xtime min = delay(-secs);
boost::xtime max = delay(0);
return (boost::xtime_cmp(xt, min) >= 0) &&
(boost::xtime_cmp(xt, max) <= 0);
}
class execution_monitor
{
public:
enum wait_type { use_sleep_only, use_mutex, use_condition };
execution_monitor(wait_type type, int secs)
: done(false), type(type), secs(secs) { }
void start()
{
if (type != use_sleep_only) {
boost::mutex::scoped_lock lock(mutex); done = false;
} else {
done = false;
}
}
void finish()
{
if (type != use_sleep_only) {
boost::mutex::scoped_lock lock(mutex);
done = true;
if (type == use_condition)
cond.notify_one();
} else {
done = true;
}
}
bool wait()
{
boost::xtime xt = delay(secs);
if (type != use_condition)
boost::thread::sleep(xt);
if (type != use_sleep_only) {
boost::mutex::scoped_lock lock(mutex);
while (type == use_condition && !done) {
if (!cond.timed_wait(lock, xt))
break;
}
return done;
}
return done;
}
private:
boost::mutex mutex;
boost::condition cond;
bool done;
wait_type type;
int secs;
};
template <typename F>
class indirect_adapter
{
public:
indirect_adapter(F func, execution_monitor& monitor)
: func(func), monitor(monitor) { }
void operator()() const
{
try
{
boost::thread thrd(func);
thrd.join();
}
catch (...)
{
monitor.finish();
throw;
}
monitor.finish();
}
private:
F func;
execution_monitor& monitor;
};
template <typename F>
void timed_test(F func, int secs,
execution_monitor::wait_type type=DEFAULT_EXECUTION_MONITOR_TYPE)
{
execution_monitor monitor(type, secs);
indirect_adapter<F> ifunc(func, monitor);
monitor.start();
boost::thread thrd(ifunc);
BOOST_REQUIRE_MESSAGE(monitor.wait(),
"Timed test didn't complete in time, possible deadlock.");
}
template <typename F, typename T>
class binder
{
public:
binder(const F& func, const T& param)
: func(func), param(param) { }
void operator()() const { func(param); }
private:
F func;
T param;
};
template <typename F, typename T>
binder<F, T> bind(const F& func, const T& param)
{
return binder<F, T>(func, param);
}
} // namespace
#endif

View File

@@ -1,49 +0,0 @@
# (C) Copyright William E. Kempf 2001. Permission to copy, use, modify, sell
# and distribute this software is granted provided this copyright notice
# appears in all copies. This software is provided "as is" without express or
# implied warranty, and with no claim as to its suitability for any purpose.
#
# Boost.Threads example Jamfile
#
# Additional configuration variables used:
# 1. PTW32 may be used on Win32 platforms to specify that the pthreads-win32
# library should be used instead of "native" threads. This feature is
# mostly used for testing and it's generally recommended you use the
# native threading libraries instead. PTW32 should be set to be a list
# of two strings, the first specifying the installation path of the
# pthreads-win32 library and the second specifying which library
# variant to link against (see the pthreads-win32 documentation).
# Example: jam -sPTW32="c:\pthreads-win32 pthreadVCE.lib"
# Declare the location of this subproject relative to the root.
subproject libs/thread/tutorial ;
# Include threads.jam for Boost.Threads global build information.
# This greatly simplifies the Jam code needed to configure the build
# for the various Win32 build types.
SEARCH on <module@>threads.jam = $(BOOST_ROOT)/libs/thread/build ;
include <module@>threads.jam ;
{
template tutorial
## sources ##
: <template>thread_base
<dll>../build/boost_thread
## requirements ##
:
## default build ##
:
;
exe helloworld : <template>tutorial helloworld.cpp ;
exe helloworld2 : <template>tutorial helloworld2.cpp ;
exe helloworld3 : <template>tutorial helloworld3.cpp ;
exe helloworld4 : <template>tutorial helloworld4.cpp ;
exe factorial : <template>tutorial factorial.cpp ;
exe factorial2 : <template>tutorial factorial2.cpp ;
exe factorial3 : <template>tutorial factorial3.cpp ;
exe counter : <template>tutorial counter.cpp ;
exe bounded_buffer : <template>tutorial bounded_buffer.cpp ;
exe once : <template>tutorial once.cpp ;
}

View File

@@ -1,74 +0,0 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/condition.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include <iostream>
#include <vector>
class bounded_buffer : private boost::noncopyable
{
public:
typedef boost::mutex::scoped_lock lock;
bounded_buffer(int n) : begin(0), end(0), buffered(0), circular_buf(n) { }
void send (int m) {
lock lk(monitor);
while (buffered == circular_buf.size())
buffer_not_full.wait(lk);
circular_buf[end] = m;
end = (end+1) % circular_buf.size();
++buffered;
buffer_not_empty.notify_one();
}
int receive() {
lock lk(monitor);
while (buffered == 0)
buffer_not_empty.wait(lk);
int i = circular_buf[begin];
begin = (begin+1) % circular_buf.size();
--buffered;
buffer_not_full.notify_one();
return i;
}
private:
int begin, end, buffered;
std::vector<int> circular_buf;
boost::condition buffer_not_full, buffer_not_empty;
boost::mutex monitor;
};
bounded_buffer buf(2);
void sender() {
int n = 0;
while (n < 100) {
buf.send(n);
std::cout << "sent: " << n << std::endl;
++n;
}
buf.send(-1);
}
void receiver() {
int n;
do {
n = buf.receive();
std::cout << "received: " << n << std::endl;
} while (n != -1); // -1 indicates end of buffer
}
int main()
{
boost::thread thrd1(&sender);
boost::thread thrd2(&receiver);
thrd1.join();
thrd2.join();
}

View File

@@ -1,33 +0,0 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include <iostream>
boost::mutex mutex;
int counter=0;
void change_count()
{
boost::mutex::scoped_lock lock(mutex);
int i = ++counter;
std::cout << "count == " << i << std::endl;
}
int main()
{
const int num_threads = 4;
boost::thread_group thrds;
for (int i=0; i < num_threads; ++i)
thrds.create_thread(&change_count);
thrds.join_all();
}

View File

@@ -1,37 +0,0 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/thread.hpp>
#include <iostream>
class factorial
{
public:
factorial(int x, int& res) : x(x), res(res) { }
void operator()() { res = calculate(x); }
int result() const { return res; }
private:
int calculate(int x) { return x <= 1 ? 1 : x * calculate(x-1); }
private:
int x;
int& res;
};
int main()
{
int result;
factorial f(10, result);
boost::thread thrd(f);
thrd.join();
std::cout << "10! = " << result << std::endl;
}

View File

@@ -1,37 +0,0 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/thread.hpp>
#include <boost/ref.hpp>
#include <iostream>
class factorial
{
public:
factorial(int x) : x(x), res(0) { }
void operator()() { res = calculate(x); }
int result() const { return res; }
private:
int calculate(int x) { return x <= 1 ? 1 : x * calculate(x-1); }
private:
int x;
int res;
};
int main()
{
factorial f(10);
boost::thread thrd(boost::ref(f));
thrd.join();
std::cout << "10! = " << f.result() << std::endl;
}

View File

@@ -1,41 +0,0 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/thread.hpp>
#include <iostream>
const int NUM_CALCS=5;
class factorial
{
public:
factorial(int x, int& res) : x(x), res(res) { }
void operator()() { res = calculate(x); }
int result() const { return res; }
private:
int calculate(int x) { return x <= 1 ? 1 : x * calculate(x-1); }
private:
int x;
int& res;
};
int main()
{
int results[NUM_CALCS];
boost::thread_group thrds;
for (int i=0; i < NUM_CALCS; ++i)
thrds.create_thread(factorial(i*10, results[i]));
thrds.join_all();
for (int j=0; j < NUM_CALCS; ++j)
std::cout << j*10 << "! = " << results[j] << std::endl;
}

View File

@@ -1,24 +0,0 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/thread.hpp>
#include <iostream>
void helloworld()
{
std::cout << "Hello World!" << std::endl;
}
int main()
{
boost::thread thrd(&helloworld);
thrd.join();
}

View File

@@ -1,25 +0,0 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/thread.hpp>
#include <iostream>
struct helloworld
{
helloworld() { }
void operator()() { std::cout << "Hello World." << std::endl; }
};
int main()
{
boost::thread thrd(helloworld());
thrd.join();
}

View File

@@ -1,26 +0,0 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/thread.hpp>
#include <iostream>
struct helloworld
{
helloworld(const char* who) : m_who(who) { }
void operator()() { std::cout << m_who << "says, \"Hello World.\"" << std::endl; }
const char* m_who;
};
int main()
{
boost::thread thrd(helloworld("Bob"));
thrd.join();
}

View File

@@ -1,25 +0,0 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/thread.hpp>
#include <boost/bind.hpp>
#include <iostream>
void helloworld(const char* who)
{
std::cout << who << "says, \"Hello World.\"" << std::endl;
}
int main()
{
boost::thread thrd(boost::bind(&helloworld, "Bob"));
thrd.join();
}

View File

@@ -1,36 +0,0 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/thread.hpp>
#include <boost/thread/once.hpp>
#include <cassert>
int value=0;
boost::once_flag once = BOOST_ONCE_INIT;
void init()
{
++value;
}
void thread_proc()
{
boost::call_once(&init, once);
}
int main(int argc, char* argv[])
{
boost::thread_group threads;
for (int i=0; i<5; ++i)
threads.create_thread(&thread_proc);
threads.join_all();
assert(value == 1);
}

View File

@@ -1,41 +0,0 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/thread.hpp>
#include <boost/thread/tss.hpp>
#include <cassert>
boost::thread_specific_ptr<int> value;
void increment()
{
int* p = value.get();
++*p;
}
void thread_proc()
{
value.reset(new int(0)); // initialize the thread's storage
for (int i=0; i<10; ++i)
{
increment();
int* p = value.get();
assert(*p == i+1);
}
}
int main(int argc, char* argv[])
{
boost::thread_group threads;
for (int i=0; i<5; ++i)
threads.create_thread(&thread_proc);
threads.join_all();
}