mirror of
https://github.com/boostorg/thread.git
synced 2026-02-03 09:42:16 +00:00
Compare commits
61 Commits
svn-branch
...
svn-branch
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f25e80b47c | ||
|
|
43cbd3a283 | ||
|
|
31cf6b5e64 | ||
|
|
99109ab78b | ||
|
|
a80d5f159d | ||
|
|
7ba4fc4aed | ||
|
|
9fb31e9868 | ||
|
|
3a2246de5b | ||
|
|
e7c4e2fa57 | ||
|
|
724ab285f0 | ||
|
|
d60e66fb00 | ||
|
|
97cdaca028 | ||
|
|
3044c8f905 | ||
|
|
2775a2a945 | ||
|
|
c43c1febba | ||
|
|
ceb6471d57 | ||
|
|
b99cc044f3 | ||
|
|
d91429dcec | ||
|
|
b1d1f7d8f1 | ||
|
|
86b608cf41 | ||
|
|
f263f75751 | ||
|
|
24bec05b86 | ||
|
|
ce1a5e9359 | ||
|
|
311525bc06 | ||
|
|
ecdfd96529 | ||
|
|
5aab32bc1a | ||
|
|
e152a1c6f2 | ||
|
|
e84fde78ec | ||
|
|
6ec4652bcf | ||
|
|
a5239c820b | ||
|
|
41b001b22c | ||
|
|
34e903b8b0 | ||
|
|
2b67e953fd | ||
|
|
aa0d3adf1d | ||
|
|
a1f57a8a80 | ||
|
|
6bc82a8580 | ||
|
|
c4c2e5d3a2 | ||
|
|
dd7d4b2173 | ||
|
|
2719c4d545 | ||
|
|
33c1e36b54 | ||
|
|
e7e46e185e | ||
|
|
9200d48873 | ||
|
|
831d054d24 | ||
|
|
f3af804ddb | ||
|
|
1f35149ef0 | ||
|
|
554a18842f | ||
|
|
869243b6d1 | ||
|
|
c0da02326a | ||
|
|
9b5f666fc5 | ||
|
|
1ce93426a4 | ||
|
|
6dacf3478b | ||
|
|
dff91699c3 | ||
|
|
9f83e8c1fc | ||
|
|
7b07cb0759 | ||
|
|
c2e7091632 | ||
|
|
1ab320042e | ||
|
|
b0cd307eaf | ||
|
|
ca2cf20cf3 | ||
|
|
b3acba1d2d | ||
|
|
6d2731c463 | ||
|
|
b7f8f8867c |
2
build/.cvsignore
Normal file
2
build/.cvsignore
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
bin*
|
||||||
|
*.pdb
|
||||||
70
build/Jamfile
Normal file
70
build/Jamfile
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
# (C) Copyright William E. Kempf 2001. Permission to copy, use, modify, sell and
|
||||||
|
# distribute this software is granted provided this copyright notice appears
|
||||||
|
# in all copies. This software is provided "as is" without express or implied
|
||||||
|
# warranty, and with no claim as to its suitability for any purpose.
|
||||||
|
#
|
||||||
|
# Boost.Threads build Jamfile
|
||||||
|
#
|
||||||
|
# Declares the following targets:
|
||||||
|
# 1. libboost_thread, a static link library.
|
||||||
|
# 1a. On Win32 (when PTW32 is not defined), a dynamic link library
|
||||||
|
# boost_threadmon, which must be used in conjunction with
|
||||||
|
# libboost_thread. Note that this DLL *must* be used through static
|
||||||
|
# linking to the import library. Dynamic loading will cause undefined
|
||||||
|
# behavior.
|
||||||
|
# Additional configuration variables used:
|
||||||
|
# 1. PTW32 may be used on Win32 platforms to specify that the pthreads-win32
|
||||||
|
# library should be used instead of "native" threads. This feature is
|
||||||
|
# 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/build ;
|
||||||
|
|
||||||
|
# Include threads.jam for Boost.Threads global build information.
|
||||||
|
# This greatly simplifies the Jam code needed to configure the build
|
||||||
|
# for the various Win32 build types.
|
||||||
|
SEARCH on <module@>threads.jam = $(SUBDIR) ;
|
||||||
|
include <module@>threads.jam ;
|
||||||
|
|
||||||
|
#######################
|
||||||
|
# Conditionally declare the Boost.Threads dynamic link library boost_threadmon.
|
||||||
|
|
||||||
|
if $(NT) && ! $(PTW32)
|
||||||
|
{
|
||||||
|
dll boost_threadmon
|
||||||
|
: ../src/threadmon.cpp
|
||||||
|
: <sysinclude>$(BOOST_ROOT)
|
||||||
|
<threading>multi
|
||||||
|
: debug release <runtime-link>static/dynamic
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
#######################
|
||||||
|
# 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
|
||||||
|
#;
|
||||||
23
build/threads.jam
Normal file
23
build/threads.jam
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# Do some OS-specific setup
|
||||||
|
|
||||||
|
threadmon = ;
|
||||||
|
pthreads-win32 = ;
|
||||||
|
|
||||||
|
if $(NT)
|
||||||
|
{
|
||||||
|
if $(PTW32)
|
||||||
|
{
|
||||||
|
local install-path = $(PTW32[1]) ;
|
||||||
|
local lib = $(PTW32[2]) ;
|
||||||
|
pthreads-win32 =
|
||||||
|
<define>BOOST_HAS_PTHREADS
|
||||||
|
<define>PtW32NoCatchWarn
|
||||||
|
<include>$(install-path)/pre-built/include
|
||||||
|
<library-file>$(install-path)/pre-built/lib/$(lib)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
threadmon = <dll>../build/boost_threadmon ;
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
build/threads.mcp
Normal file
BIN
build/threads.mcp
Normal file
Binary file not shown.
69
doc/acknowledgments.html
Normal file
69
doc/acknowledgments.html
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||||
|
<link rel="stylesheet" type="text/css" href="../../../boost.css">
|
||||||
|
<title>Boost.Threads - Acknowledgments</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">Acknowledgments</h2>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<hr>
|
||||||
|
<p><a href="../../../people/william_kempf.htm">William E. Kempf</a> was the architect,
|
||||||
|
designer, and implementor of <b>Boost.Threads</b>.</p>
|
||||||
|
<p>Mac OS Carbon implementation written by <a href="../../../people/mac_murrett.htm">Mac
|
||||||
|
Murrett</a>.</p>
|
||||||
|
<p>Important contributions were also made by Jeremy Siek (lots of input on the
|
||||||
|
design and on the implementation), Alexander Terekhov (lots of input on the
|
||||||
|
Win32 implementation, especially in regards to boost::condition, as well as
|
||||||
|
a lot of explanation of POSIX behavior), Greg Colvin (lots of input on the design),
|
||||||
|
Paul Mclachlan, Thomas Matelich and Iain Hanson (for help in trying to get the
|
||||||
|
build to work on other platforms), and Kevin S. Van Horn (for several updates/corrections
|
||||||
|
to the documentation).</p>
|
||||||
|
<p>The documentation was written by William E. Kempf. Beman Dawes provided additional
|
||||||
|
documentation material and editing.</p>
|
||||||
|
<p>Discussions on the boost.org mailing list were essential in the development
|
||||||
|
of <b>Boost.Threads</b>. As of August 1, 2001, participants included Alan Griffiths,
|
||||||
|
Albrecht Fritzsche, Aleksey Gurtovoy, Alexander Terekhov, Andrew Green, Andy
|
||||||
|
Sawyer, Asger Alstrup Nielsen, Beman Dawes, Bill Klein, Bill Rutiser, Bill Wade,
|
||||||
|
Branko Èibej, Brent Verner, Craig Henderson, Csaba Szepesvari, Dale Peakall,
|
||||||
|
Damian Dixon, Dan Nuffer, Darryl Green, Daryle Walker, David Abrahams, David
|
||||||
|
Allan Finch, Dejan Jelovic, Dietmar Kuehl, Doug Gregor, Douglas Gregor, Duncan
|
||||||
|
Harris, Ed Brey, Eric Swanson, Eugene Karpachov, Fabrice Truillot, Frank Gerlach,
|
||||||
|
Gary Powell, Gernot Neppert, Geurt Vos, Ghazi Ramadan, Greg Colvin, Gregory
|
||||||
|
Seidman, HYS, Iain Hanson, Ian Bruntlett, J Panzer, Jeff Garland, Jeff Paquette,
|
||||||
|
Jens Maurer, Jeremy Siek, Jesse Jones, Joe Gottman, John (EBo) David, John Bandela,
|
||||||
|
John Maddock, John Max Skaller, John Panzer, Jon Jagger , Karl Nelson, Kevlin
|
||||||
|
Henney, KG Chandrasekhar, Levente Farkas, Lie-Quan Lee, Lois Goldthwaite, Luis
|
||||||
|
Pedro Coelho, Marc Girod, Mark A. Borgerding, Mark Rodgers, Marshall Clow, Matthew
|
||||||
|
Austern, Matthew Hurd, Michael D. Crawford, Michael H. Cox , Mike Haller, Miki
|
||||||
|
Jovanovic, Nathan Myers, Paul Moore, Pavel Cisler, Peter Dimov, Petr Kocmid,
|
||||||
|
Philip Nash, Rainer Deyke, Reid Sweatman, Ross Smith, Scott McCaskill, Shalom
|
||||||
|
Reich , Steve Cleary, Steven Kirk, Thomas Holenstein, Thomas Matelich, Trevor
|
||||||
|
Perrin, Valentin Bonnard, Vesa Karvonen, Wayne Miller, and William Kempf.</p>
|
||||||
|
<p>Apologies for anyone inadvertently missed.</p>
|
||||||
|
<hr>
|
||||||
|
<p>Revised
|
||||||
|
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
||||||
|
05 November, 2001
|
||||||
|
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
|
||||||
|
</p>
|
||||||
|
<p><i>© Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
|
||||||
|
All Rights Reserved.</i></p>
|
||||||
|
<p>Permission to use, copy, modify, distribute and sell this software and its
|
||||||
|
documentation for any purpose is hereby granted without fee, provided that the
|
||||||
|
above copyright notice appear in all copies and that both that copyright notice
|
||||||
|
and this permission notice appear in supporting documentation. William E. Kempf
|
||||||
|
makes no representations about the suitability of this software for any purpose.
|
||||||
|
It is provided "as is" without express or implied warranty.</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
165
doc/bibliography.html
Normal file
165
doc/bibliography.html
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||||
|
<link rel="stylesheet" type="text/css" href="../../../boost.css">
|
||||||
|
<title>Boost.Threads - Bibliography</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">Bibliography</h2>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<hr>
|
||||||
|
<table summary="Bibliography" border="0" cellpadding="5" width="777">
|
||||||
|
<tr>
|
||||||
|
<td width="102" valign="top" align="left"><b>[<a name=
|
||||||
|
"Andrews-83">Andrews 83</a>]</b></td>
|
||||||
|
<td width="645"> Gregory R. Andrews, Fred B. Schneider, <cite>Concepts and
|
||||||
|
Notations for Concurrent Programming</cite>, ACM Computing Surveys, Vol.
|
||||||
|
15, No. 1, March, 1983. <a href=
|
||||||
|
"http://www.acm.org/pubs/citations/journals/surveys/1983-15-1/p3-andrews/">
|
||||||
|
http://www.acm.org/pubs/citations/journals/surveys/1983-15-1/p3-andrews/</a>
|
||||||
|
<p>Good general background reading. Includes descriptions of Path Expressions,
|
||||||
|
Message Passing, and Remote Procedure Call in addition to the basics.</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="102" valign="top" align="left"><b>[<a name=
|
||||||
|
"Boost">Boost</a>]</b></td>
|
||||||
|
<td width="645"> The <cite>Boost</cite> worldwide web site. <a href=
|
||||||
|
"http://www.boost.org">http://www.boost.org</a>
|
||||||
|
<p>Boost.Threads is one of many Boost libraries. The Boost web site includes
|
||||||
|
a great deal of documentation and general information which applies to
|
||||||
|
all Boost libraries. Current copies of the libraries including documentation
|
||||||
|
and test programs may be downloaded from the web site.</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="102" valign="top" align="left"><b>[<a name=
|
||||||
|
"Brinch-Hansen-73">Brinch Hansen 73</a>]</b></td>
|
||||||
|
<td width="645"> Per Brinch Hansen, <cite>Concurrent Programming Concepts</cite>,
|
||||||
|
ACM Computing Surveys, Vol. 5, No. 4, December, 1973. <a href=
|
||||||
|
"http://www.acm.org/pubs/articles/journals/surveys/1973-5-4/p223-hansen/p223-hansen.pdf">
|
||||||
|
http://www.acm.org/pubs/articles/journals/surveys/1973-5-4/p223-hansen/</a>
|
||||||
|
<p>"This paper describes the evolution of language features for multiprogramming
|
||||||
|
from event queues and semaphores to critical regions and monitors."
|
||||||
|
Includes analysis of why <i>events</i> are considered error-prone. Also
|
||||||
|
noteworthy because of an introductory quotation from Christopher Alexander;
|
||||||
|
Brinch Hansen was years ahead of others in recognizing pattern concepts
|
||||||
|
applied to software too.</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="102" valign="top" align="left"><b>]<a name=
|
||||||
|
"Butenhof-97">Butenhof 97</a>]</b></td>
|
||||||
|
<td width="645">
|
||||||
|
<p>David R. Butenhof, <cite>Programming with POSIX Threads</cite>, Addison-Wesley
|
||||||
|
1997, ISBN 0-201-63392-2 <a
|
||||||
|
href="http://cseng.aw.com/book/0,3828,0201633922,00.html">
|
||||||
|
http://cseng.aw.com/book/0,3828,0201633922,00.html</a></p>
|
||||||
|
<p>This is a very readable explanation of threads and how to use them. Many
|
||||||
|
of the insights given apply to all multithreaded programming, not just
|
||||||
|
POSIX Threads.</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="102" valign="top" align="left"><b>[<a name=
|
||||||
|
"Hoare-74">Hoare 74</a>]</b></td>
|
||||||
|
<td width="645">
|
||||||
|
<p>C.A.R Hoare, <cite>Monitors: An Operating System Structuring Concept</cite>,
|
||||||
|
Communications of the ACM, Vol. 17, No. 10. October 1974, pp. 549-557
|
||||||
|
<a href=
|
||||||
|
"http://www.acm.org/classics/feb96/"> http://www.acm.org/classics/feb96/</a></p>
|
||||||
|
<p>Hoare and Brinch Hansen's work on Monitors is the basis for reliable
|
||||||
|
multithreading patterns. This is one of the most often referenced papers
|
||||||
|
in all of computer science, and with good reason.</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="102" valign="top" align="left"><b>[<a name=
|
||||||
|
"ISO-98">ISO 98</a>]</b></td>
|
||||||
|
<td width="645">
|
||||||
|
<p>ISO/IEC 14882:1998(E) <cite>Programming Language C++</cite> <a href="http://www.ansi.org">
|
||||||
|
http://www.ansi.org</a></p>
|
||||||
|
<p>This is the official C++ Standards document. Available from the ANSI
|
||||||
|
(American National Standards Institute) Electronic Standards Store.</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="102" valign="top" align="left"><b>[<a name=
|
||||||
|
"McDowell-89">McDowell 89</a>]</b></td>
|
||||||
|
<td width="645"> Charles E McDowell, David P. Helmbold, <cite>Debugging Concurrent
|
||||||
|
Programs</cite>, ACM Computing Surveys, Vol. 21, No. 2, December, 1989.
|
||||||
|
<a href=
|
||||||
|
"http://www.acm.org/pubs/citations/journals/surveys/1989-21-4/p593-mcdowell/">
|
||||||
|
http://www.acm.org/pubs/citations/journals/surveys/1989-21-4/p593-mcdowell/</a>
|
||||||
|
<p>Identifies many of the unique failure modes and debugging difficulties
|
||||||
|
associated with concurrent programs.</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="102" valign="top" align="left"><b>[<a name=
|
||||||
|
"Schmidt">Schmidt</a>]</b> </td>
|
||||||
|
<td width="645">
|
||||||
|
<p>Douglas C. Schmidt and Irfan Pyarali, <cite>Strategies for Implementing
|
||||||
|
POSIX Condition Variables on Win32</cite>, Department of Computer Science,
|
||||||
|
Washington University, St. Louis, Missouri. <a href=
|
||||||
|
"http://www.cs.wustl.edu/~schmidt/win32-cv-1.html"> http://www.cs.wustl.edu/~schmidt/win32-cv-1.html</a></p>
|
||||||
|
<p>Rationale for understanding Boost.Threads condition variables. Note that
|
||||||
|
Alexander Terekhov found some bugs in the implementation given in this
|
||||||
|
article, so pthreads-win32 and Boost.Threads are even more complicated
|
||||||
|
yet.</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="102" valign="top" align="left"><b>[<a name=
|
||||||
|
"Schmidt-00">Schmidt 00</a>]</b> </td>
|
||||||
|
<td width="645">
|
||||||
|
<p>Douglas C. Schmidt, Michael Stal, Hans Rohnert and Frank Buschmann, <cite>Pattern-Oriented
|
||||||
|
Software Architecture Volume 2 - Patterns for Concurrent and Networked
|
||||||
|
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</a></p>
|
||||||
|
<p>This is a very good explanation of how to apply several patterns useful
|
||||||
|
for concurrent programming. Among the patterns documented is the Monitor
|
||||||
|
Pattern mentioned frequently in the <b>Boost.Threads</b> documentation.</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="102" valign="top" align="left"><b>[<a name=
|
||||||
|
"Stroustrup-00">Stroustrup 00</a>]</b></td>
|
||||||
|
<td width="645"> Bjarne Stroustrup, <cite>The C++ Programming Language</cite>,
|
||||||
|
Special Edition, Addison-Wesley 2000, ISBN 0-201-70073-5 <a href=
|
||||||
|
"http://cseng.aw.com/book/0,3828,0201700735,00.html"> http://cseng.aw.com/book/0,3828,0201700735,00.html</a>
|
||||||
|
<p>The first book a C++ programmer should own. Note that the 3rd edition
|
||||||
|
(and subsequent editions like the Special Edition) has been rewritten
|
||||||
|
to cover the ISO standard language and library.</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<p>Note: The URL's above are provided in plain text form so that they will
|
||||||
|
be visible on printed copies of this document.</p>
|
||||||
|
<hr>
|
||||||
|
<p>Revised
|
||||||
|
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
||||||
|
05 November, 2001
|
||||||
|
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
|
||||||
|
</p>
|
||||||
|
<p><i>© Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> and
|
||||||
|
Beman Dawes 2001-2002. All Rights Reserved.</i></p>
|
||||||
|
<p>Permission to use, copy, modify, distribute and sell this software and its
|
||||||
|
documentation for any purpose is hereby granted without fee, provided that the
|
||||||
|
above copyright notice appear in all copies and that both that copyright notice
|
||||||
|
and this permission notice appear in supporting documentation. William E. Kempf
|
||||||
|
makes no representations about the suitability of this software for any purpose.
|
||||||
|
It is provided "as is" without express or implied warranty.</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
294
doc/condition.html
Normal file
294
doc/condition.html
Normal file
@@ -0,0 +1,294 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||||
|
<link rel="stylesheet" type="text/css" href="../../../boost.css">
|
||||||
|
<title>Boost.Threads - Header <boost/thread/condition.hpp></title>
|
||||||
|
</head>
|
||||||
|
<body link="#0000ff" vlink="#800080">
|
||||||
|
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
|
||||||
|
"header">
|
||||||
|
<tr>
|
||||||
|
<td valign="top" width="300">
|
||||||
|
<h3><a href="../../../index.htm"><img height="86" width="277" alt="C++ Boost" src="../../../c++boost.gif" border="0"></a></h3>
|
||||||
|
</td>
|
||||||
|
<td valign="top">
|
||||||
|
<h1 align="center">Boost.Threads</h1>
|
||||||
|
<h2 align="center">Header <<a href="../../../boost/thread/condition.hpp">boost/thread/condition.hpp</a>></h2>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<hr>
|
||||||
|
<h2>Contents</h2>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="#introduction">Introduction</a></dt>
|
||||||
|
<dt><a href="#classes">Classes</a></dt>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="#class-condition">Class <code>condition</code></a></dt>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="#class-condition-synopsis">Class <code>condition</code> synopsis</a></dt>
|
||||||
|
<dt><a href="#class-condition-ctors">Class <code>condition</code> constructors
|
||||||
|
and destructor</a></dt>
|
||||||
|
<dt><a href="#class-condition-modifiers">Class <code>condition</code> modifier
|
||||||
|
functions</a></dt>
|
||||||
|
</dl>
|
||||||
|
</dl>
|
||||||
|
<dt><a href="#examples">Example(s)</a></dt>
|
||||||
|
</dl>
|
||||||
|
<hr>
|
||||||
|
<h2><a name="introduction"></a>Introduction</h2>
|
||||||
|
<p>Include the header <<a href="../../../boost/thread/condition.hpp">boost/thread/condition.hpp</a>>
|
||||||
|
to define the class condition.</p>
|
||||||
|
<h2><a name="classes"></a>Classes</h2>
|
||||||
|
<h3><a name="class-condition"></a>Class <code>condition</code></h3>
|
||||||
|
<p>An object of class <code>condition</code> is a synchronization primitive used
|
||||||
|
to cause a thread to wait until a particular shared-data condition (or time)
|
||||||
|
is met. A <code>condition</code> object is always used in conjunction with a
|
||||||
|
mutex object (an object whose type is a model of <a href="mutex_concept.html">Mutex</a>
|
||||||
|
or one of its refinements). The mutex object must be locked prior to waiting
|
||||||
|
on the <code>condition</code>, which is verified by passing a lock object (an
|
||||||
|
object whose type is a model of <a href="lock_concept.html">Lock</a> or one
|
||||||
|
of its refinements) to the <code>condition</code> object's <code>wait</code>
|
||||||
|
functions. Upon blocking on the condition object, the thread unlocks the mutex
|
||||||
|
object. When the thread returns from a call to one of the condition object's
|
||||||
|
wait functions the mutex object is again locked. The tricky unlock/lock sequence
|
||||||
|
is performed automatically by the <code> condition</code> object's <code>wait</code>
|
||||||
|
functions.</p>
|
||||||
|
<p>The <code>condition</code> type is often used to implement the <i> Monitor
|
||||||
|
Object</i> and other important patterns (see <a href="bibliography.html#Schmidt-00">[Schmidt
|
||||||
|
00]</a> and <a href="bibliography.html#Hoare-74">[Hoare 74]</a>). Monitors are
|
||||||
|
one of the most important patterns for creating reliable multithreaded programs.</p>
|
||||||
|
<p>See <a href="definitions.html">Formal Definitions</a> for definitions of thread
|
||||||
|
states <a href="definitions.html#state"> blocked</a> and <a href="definitions.html#state">ready</a>.
|
||||||
|
Note that "waiting" is a synonym for blocked.</p>
|
||||||
|
<h4><a name="class-condition-synopsis"></a>Class <code>condition</code> synopsis</h4>
|
||||||
|
<pre>
|
||||||
|
namespace boost
|
||||||
|
{
|
||||||
|
class condition : private <a href="../../utility/utility.htm#Class noncopyable">boost::noncopyable</a> // Exposition only.
|
||||||
|
// Class condition meets the <a href="overview.html#non-copyable">NonCopyable</a> requirement.
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
condition();
|
||||||
|
~condition();
|
||||||
|
|
||||||
|
void notify_one();
|
||||||
|
void notify_all();
|
||||||
|
template <typename <a href="lock_concept.html#Lock-concept">Lock</a>>
|
||||||
|
void wait(<a href="lock_concept.html#Lock-concept">Lock</a>& lock);
|
||||||
|
template <typename <a href="lock_concept.html#Lock-concept">Lock</a>, typename <a href="http://www.sgi.com/tech/stl/Predicate.html">Predicate</a>>
|
||||||
|
void wait(<a href="lock_concept.html#Lock-concept">Lock</a>& lock, <a href="http://www.sgi.com/tech/stl/Predicate.html">Predicate</a> pred);
|
||||||
|
template <typename <a href="lock_concept.html#Lock-concept">Lock</a>>
|
||||||
|
bool timed_wait(<a href="lock_concept.html#Lock-concept">Lock</a>& lock, const xtime& xt);
|
||||||
|
template <typename <a href="lock_concept.html#Lock-concept">Lock</a>, typename <a href="http://www.sgi.com/tech/stl/Predicate.html">Predicate</a>>
|
||||||
|
bool timed_wait(<a href="lock_concept.html#Lock-concept">Lock</a>& lock, const xtime& XT, <a href="http://www.sgi.com/tech/stl/Predicate.html">Predicate</a> pred);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
</pre>
|
||||||
|
<h4><a name="class-condition-ctors"></a>Class <code>condition</code> constructors
|
||||||
|
and destructor</h4>
|
||||||
|
<pre>
|
||||||
|
condition();
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<dt><b>Effects:</b> Constructs a <code>condition</code> object.</dt>
|
||||||
|
</dl>
|
||||||
|
<pre>
|
||||||
|
~condition();
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<dt><b>Effects:</b> Destroys <code>*this</code>.</dt>
|
||||||
|
</dl>
|
||||||
|
<h4><a name="class-condition-modifiers"></a>Class <code>condition</code> modifier
|
||||||
|
functions</h4>
|
||||||
|
<pre>
|
||||||
|
void notify_one();
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<dt><b>Effects:</b> If there is a thread waiting on <code>*this</code>, change
|
||||||
|
that thread's state to ready. Otherwise there is no effect.</dt>
|
||||||
|
<dt><b>Note:</b> If more than one thread is waiting on the condition, it is
|
||||||
|
unspecified which is made ready. After returning to a ready state the notified
|
||||||
|
thread must still acquire the mutex again (which occurs within the call to
|
||||||
|
one of the <code>condition</code> object's wait functions).</dt>
|
||||||
|
</dl>
|
||||||
|
<pre>
|
||||||
|
void notify_all();
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<dt><b>Effects:</b> Change the state of all threads waiting on <code> *this</code>
|
||||||
|
to ready. If there are no waiting threads, <code> notify_all()</code> has
|
||||||
|
no effect.</dt>
|
||||||
|
</dl>
|
||||||
|
<pre>
|
||||||
|
template <typename ScopedLock>
|
||||||
|
void wait(ScopedLock& lock);
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<dt><b>Requires:</b> <code>ScopedLock</code> meets the <a href="lock_concept.html#ScopedLock">ScopedLock</a>
|
||||||
|
requirements.</dt>
|
||||||
|
<dt><b>Effects:</b> Releases the lock on the <a href="mutex_concept.html">mutex
|
||||||
|
model</a> associated with <code>lock</code>, blocks the current thread of
|
||||||
|
execution until readied by a call to <code>this->notify_one()</code> or
|
||||||
|
<code> this->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>
|
||||||
|
if <code>!lock.locked()</code></dt>
|
||||||
|
<dt><b>Danger:</b> This version should always be used within a loop checking
|
||||||
|
that the state logically associated with the <code>condition</code> has become
|
||||||
|
true. Without the loop, race conditions can ensue due to possible "spurious
|
||||||
|
wake ups". The second version encapsulates this loop idiom internally
|
||||||
|
and is generally the preferred method.</dt>
|
||||||
|
</dl>
|
||||||
|
<pre>
|
||||||
|
Template<typename ScopedLock, typename Pr>
|
||||||
|
void wait(ScopedLock& lock, Pr pred);
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<dt><b>Requires:</b> <code>ScopedLock</code> meets the <a href="lock_concept.html#ScopedLock">ScopedLock</a>
|
||||||
|
requirements, return from <code>pred()</code> convertible to bool.</dt>
|
||||||
|
<dt><b>Effects:</b> As if: <code>while (!pred()) wait(lock)</code></dt>
|
||||||
|
<dt><b>Throws:</b> <code><a href="exceptions.html#class-lock_error">lock_error</a></code>
|
||||||
|
if <code>!lock.locked()</code></dt>
|
||||||
|
</dl>
|
||||||
|
<pre>
|
||||||
|
template <typename ScopedLock>
|
||||||
|
bool timed_wait(ScopedLock& lock, const <a href="xtime.html">xtime</a>& XT);
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<dt><b>Requires:</b> <code>ScopedLock</code> meets the <a href="lock_concept.html#ScopedLock">ScopedLock</a>
|
||||||
|
requirements.</dt>
|
||||||
|
<dt><b>Effects:</b> Releases the lock on the <a href="mutex_concept.html">mutex
|
||||||
|
model</a> associated with the <code> lock</code>, blocks the current thread
|
||||||
|
of execution until readied by a call to <code>this->notify_one()</code>
|
||||||
|
or <code> this->notify_all()</code>, or until <code>XT</code>, and then
|
||||||
|
reacquires the lock.</dt>
|
||||||
|
<dt><b>Returns:</b> <code>false</code> if <code>XT</code> is reached, otherwise
|
||||||
|
<code>true</code>.</dt>
|
||||||
|
<dt><b>Throws:</b> <code><a href="exceptions.html#class-lock_error">lock_error</a></code>
|
||||||
|
if <code>!lock.locked()</code></dt>
|
||||||
|
<dt><b>Danger:</b> This version should always be used within a loop checking
|
||||||
|
that the state logically associated with the <code>condition</code> has become
|
||||||
|
true. Without the loop, race conditions can ensue due to "spurious wake
|
||||||
|
ups". The second version encapsulates this loop idiom internally and
|
||||||
|
is generally the preferred method.</dt>
|
||||||
|
</dl>
|
||||||
|
<pre>
|
||||||
|
Template<typename ScopedLock, typename Pr>
|
||||||
|
bool timed_wait(ScopedLock& lock, const <a href="xtime.html">xtime</a>& XT, Pr pred);
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<dt><b>Requires:</b> <code>ScopedLock</code> meets the <a href="lock_concept.html#ScopedLock">ScopedLock</a>
|
||||||
|
requirements, return from <code>pred()</code> convertible to bool.</dt>
|
||||||
|
<dt><b>Effects:</b> As if:<br>
|
||||||
|
<pre>
|
||||||
|
while (!pred())
|
||||||
|
{
|
||||||
|
if (!timed_wait(lock, XT))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
</pre>
|
||||||
|
</dt>
|
||||||
|
<dt><b>Returns:</b> <code>false</code> if <code>XT</code> is reached, otherwise
|
||||||
|
<code>true</code>.</dt>
|
||||||
|
<dt><b>Throws:</b> <code><a href="exceptions.html#class-lock_error">lock_error</a></code>
|
||||||
|
if <code>!lock.locked()</code></dt>
|
||||||
|
</dl>
|
||||||
|
<h2><a name="examples"></a>Example(s)</h2>
|
||||||
|
<pre>
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <a href="../../../boost/utility.hpp"><boost/utility.hpp></a>
|
||||||
|
#include <a href="../../../boost/thread/condition.hpp"><boost/thread/condition.hpp></a>
|
||||||
|
#include <a href="../../../boost/thread/thread.hpp"><boost/thread/thread.hpp></a>
|
||||||
|
|
||||||
|
class bounded_buffer : private boost::noncopyable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef boost::mutex::scoped_lock lock;
|
||||||
|
|
||||||
|
bounded_buffer(int n) : begin(0), end(0), buffered(0), circular_buf(n) { }
|
||||||
|
|
||||||
|
void send (int m) {
|
||||||
|
lock lk(monitor);
|
||||||
|
while (buffered == circular_buf.size())
|
||||||
|
buffer_not_full.wait(lk);
|
||||||
|
circular_buf[end] = m;
|
||||||
|
end = (end+1) % circular_buf.size();
|
||||||
|
++buffered;
|
||||||
|
buffer_not_empty.notify_one();
|
||||||
|
}
|
||||||
|
int receive() {
|
||||||
|
lock lk(monitor);
|
||||||
|
while (buffered == 0)
|
||||||
|
buffer_not_empty.wait(lk);
|
||||||
|
int i = circular_buf[begin];
|
||||||
|
begin = (begin+1) % circular_buf.size();
|
||||||
|
--buffered;
|
||||||
|
buffer_not_full.notify_one();
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int begin, end, buffered;
|
||||||
|
std::vector<int> circular_buf;
|
||||||
|
boost::condition buffer_not_full, buffer_not_empty;
|
||||||
|
boost::mutex monitor;
|
||||||
|
};
|
||||||
|
|
||||||
|
bounded_buffer buf(2);
|
||||||
|
|
||||||
|
void sender() {
|
||||||
|
int n = 0;
|
||||||
|
while (n < 100) {
|
||||||
|
buf.send(n);
|
||||||
|
std::cout << "sent: " << n << std::endl;
|
||||||
|
++n;
|
||||||
|
}
|
||||||
|
buf.send(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void receiver() {
|
||||||
|
int n;
|
||||||
|
do {
|
||||||
|
n = buf.receive();
|
||||||
|
std::cout << "received: " << n << std::endl;
|
||||||
|
} while (n != -1); // -1 indicates end of buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int, char*[])
|
||||||
|
{
|
||||||
|
boost::thread thrd1(&sender);
|
||||||
|
boost::thread thrd2(&receiver);
|
||||||
|
thrd1.join();
|
||||||
|
thrd2.join();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
<p>Typical output (dependent on scheduling policies) is:</p>
|
||||||
|
<pre>
|
||||||
|
sent: 0
|
||||||
|
sent: 1
|
||||||
|
received: 0
|
||||||
|
received: 1
|
||||||
|
sent: 2
|
||||||
|
sent: 3
|
||||||
|
received: 2
|
||||||
|
received: 3
|
||||||
|
sent: 4
|
||||||
|
received: 4
|
||||||
|
</pre>
|
||||||
|
<p>Revised
|
||||||
|
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
||||||
|
05 November, 2001
|
||||||
|
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
|
||||||
|
</p>
|
||||||
|
<p><i>© Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
|
||||||
|
All Rights Reserved.</i></p>
|
||||||
|
<p>Permission to use, copy, modify, distribute and sell this software and its
|
||||||
|
documentation for any purpose is hereby granted without fee, provided that the
|
||||||
|
above copyright notice appear in all copies and that both that copyright notice
|
||||||
|
and this permission notice appear in supporting documentation. William E. Kempf
|
||||||
|
makes no representations about the suitability of this software for any purpose.
|
||||||
|
It is provided "as is" without express or implied warranty.</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
94
doc/configuration.html
Normal file
94
doc/configuration.html
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||||
|
<link rel="stylesheet" type="text/css" href="../../../boost.css">
|
||||||
|
<title>Boost.Threads - Configuration</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">Configuration</h2>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<hr>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="#introduction">Introduction</a></dt>
|
||||||
|
<dt><a href="#lib-defined-public">Public Library Defined Macros</a></dt>
|
||||||
|
<dt><a href="#lib-defined-impl">Library Defined Implementation Macros</a></dt>
|
||||||
|
</dl>
|
||||||
|
<h2><a name="introduction"></a>Introduction</h2>
|
||||||
|
<p><b>Boost.Threads</b> uses several configuration macros in <a href="../../config/config.htm"><boost/config.hpp></a>,
|
||||||
|
as well as configuration macros meant to be supplied by the application. These
|
||||||
|
macros are documented here.</p>
|
||||||
|
<h2><a name="lib-defined-public"></a>Public Library Defined Macros</h2>
|
||||||
|
<p>These macros are defined by <b>Boost.Threads</b> but are expected to be used
|
||||||
|
by application code.</p>
|
||||||
|
<table summary="public library defined macros" cellspacing="10" width="100%">
|
||||||
|
<tr>
|
||||||
|
<td><b>Macro</b></td>
|
||||||
|
<td><b>Meaning</b></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>BOOST_HAS_THREADS</td>
|
||||||
|
<td>Indicates that threading support is available. This means both that there
|
||||||
|
is a platform specific implementation for <b>Boost.Threads</b> and that
|
||||||
|
threading support has been enabled in a platform specific manner. For instance,
|
||||||
|
on the Win32 platform there's an implementation for <b>Boost.Threads</b>
|
||||||
|
but unless the program is compiled against one of the multithreading runtimes
|
||||||
|
(often determined by the compiler predefining the macro _MT) the BOOST_HAS_THREADS
|
||||||
|
macro remains undefined.</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<h2><a name="lib-defined-impl"></a>Library Defined Implementation Macros</h2>
|
||||||
|
<p>These macros are defined by <b>Boost.Threads</b> and are implementation details
|
||||||
|
of interest only to implementors.</p>
|
||||||
|
<table summary="library defined implementation macros" cellspacing="10" width="100%">
|
||||||
|
<tr>
|
||||||
|
<td><b>Macro</b></td>
|
||||||
|
<td><b>Meaning</b></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>BOOST_HAS_WINTHREADS</td>
|
||||||
|
<td>Indicates that the platform has the Microsoft Win32 threading libraries,
|
||||||
|
and that they should be used to implement <b>Boost.Threads</b>.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>BOOST_HAS_PTHREADS</td>
|
||||||
|
<td>Indicates that the platform has the POSIX pthreads libraries, and that
|
||||||
|
they should be used to implement <b>Boost.Threads</b>.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>BOOST_HAS_FTIME</td>
|
||||||
|
<td>Indicates that the implementation should use GetSystemTimeAsFileTime()
|
||||||
|
and the FILETIME type to calculate the current time. This is an implementation
|
||||||
|
detail used by boost::detail::getcurtime().</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>BOOST_HAS_GETTTIMEOFDAY</td>
|
||||||
|
<td>Indicates that the implementation should use gettimeofday() to calculate
|
||||||
|
the current time. This is an implementation detail used by boost::detail::getcurtime().</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<hr>
|
||||||
|
<p>Revised
|
||||||
|
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
||||||
|
05 November, 2001
|
||||||
|
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
|
||||||
|
</p>
|
||||||
|
<p><i>© Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
|
||||||
|
All Rights Reserved.</i></p>
|
||||||
|
<p>Permission to use, copy, modify, distribute and sell this software and its
|
||||||
|
documentation for any purpose is hereby granted without fee, provided that the
|
||||||
|
above copyright notice appear in all copies and that both that copyright notice
|
||||||
|
and this permission notice appear in supporting documentation. William E. Kempf
|
||||||
|
makes no representations about the suitability of this software for any purpose.
|
||||||
|
It is provided "as is" without express or implied warranty.</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
263
doc/definitions.html
Normal file
263
doc/definitions.html
Normal file
@@ -0,0 +1,263 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||||
|
<link rel="stylesheet" type="text/css" href="../../../boost.css">
|
||||||
|
<title>Boost.Threads - Definitions</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">Definitions</h2>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<hr>
|
||||||
|
<h2>Contents</h2>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="#introduction">Introduction</a></dt>
|
||||||
|
<dt><a href="#definitions">Definitions</a></dt>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="#definition-thread">Thread</a></dt>
|
||||||
|
<dt><a href="#definition-thread-safe">Thread-safe</a></dt>
|
||||||
|
<dt><a href="#definition-thread-state">Thread State</a></dt>
|
||||||
|
<dt><a href="#definition-race-condition">Race Condition</a></dt>
|
||||||
|
<dt><a href="#definition-deadlock">Deadlock</a></dt>
|
||||||
|
<dt><a href="#definition-starvation">Starvation</a></dt>
|
||||||
|
<dt><a href="#definition-priority-failure">Priority Failure</a></dt>
|
||||||
|
<dt><a href="#definition-visibility">Memory Visibility</a></dt>
|
||||||
|
</dl>
|
||||||
|
<dt><a href="#acknowledgements">Acknowledgments</a></dt>
|
||||||
|
</dl>
|
||||||
|
<hr>
|
||||||
|
<h2><a name="introduction"></a>Introduction</h2>
|
||||||
|
<p>The definitions are given in terms of the <a href=
|
||||||
|
"bibliography.html#ISO-98">C++ Standard</a>. References to the standard
|
||||||
|
are in the form [1.2.3/4], which represents the section number, with the paragraph
|
||||||
|
number following the "/".</p>
|
||||||
|
<p>Because the definitions are written in something akin to "standardese",
|
||||||
|
they can be difficult to understand. The intent isn't to confuse, but rather
|
||||||
|
to clarify the additional requirements Boost.Threads places on a C++ implementation
|
||||||
|
as defined by the C++ Standard.</p>
|
||||||
|
<h2><a name="definitions"></a>Definitions</h2>
|
||||||
|
<h3><a name="definition-thread"></a>Thread</h3>
|
||||||
|
<p>Thread is short for "thread of execution". A thread of execution
|
||||||
|
is an execution environment [1.9/7] within the execution environment of a C++
|
||||||
|
program [1.9]. The main() function [3.6.1] of the program is the initial function
|
||||||
|
of the initial thread. A program in a multithreading environment always has
|
||||||
|
an initial thread even if the program explicitly creates no additional threads.</p>
|
||||||
|
<p>Unless otherwise specified, each thread shares all aspects of its execution
|
||||||
|
environment with other threads in the program. Shared aspects of the execution
|
||||||
|
environment include, but are not limited to, the following:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Static storage duration (static, extern) objects [3.7.1].</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li>Dynamic storage duration (heap) objects [3.7.3]. Thus each memory allocation
|
||||||
|
will return a unique addresses, regardless of the thread making the allocation
|
||||||
|
request.</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li>Automatic storage duration (stack) objects [3.7.2] accessed via pointer
|
||||||
|
or reference from another thread.</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li>Resources provided by the operating system. For example, files.</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li>The program itself. In other words, each thread is executing some function
|
||||||
|
of the same program, not a totally different program.</li>
|
||||||
|
</ul>
|
||||||
|
<p>Each thread has its own:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Registers and current execution sequence (program counter) [1.9/5].</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li>Automatic storage duration (stack) objects [3.7.2].</li>
|
||||||
|
</ul>
|
||||||
|
<h3><a name="definition-thread-safe"></a>Thread-safe</h3>
|
||||||
|
<p>A program is thread-safe if it has no <a href="#Race condition">race conditions</a>,
|
||||||
|
does not <a href="#Deadlock">deadlock</a>, and has no <a href="#Priority failure">priority
|
||||||
|
failures</a>.</p>
|
||||||
|
<p>Note that thread-safety does not necessarily imply efficiency, and than while
|
||||||
|
some thread-safety violations can be determined statically at compile time,
|
||||||
|
many thread-safety errors can only only be detected at runtime.</p>
|
||||||
|
<h3><a name="definition-thread-state"></a>Thread State</h3>
|
||||||
|
<p>During the lifetime of a thread, it shall be in one of the following states:</p>
|
||||||
|
<table summary="thread states" border="1" cellpadding="5">
|
||||||
|
<tr>
|
||||||
|
<td><b>State</b></td>
|
||||||
|
<td><b>Description</b></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Ready</td>
|
||||||
|
<td>Ready to run, but waiting for a processor.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Running</td>
|
||||||
|
<td>Currently executing on a processor. Zero or more threads may be running
|
||||||
|
at any time, with a maximum equal to the number of processors.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Blocked</td>
|
||||||
|
<td>Waiting for some resource other than a processor which is not currently
|
||||||
|
available, or for the completion of calls to library functions [1.9/6].
|
||||||
|
The term "waiting" is synonymous for "blocked"</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Terminated</td>
|
||||||
|
<td>Finished execution but not yet detached or joined.</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<p>Thread state transitions shall occur only as specified:</p>
|
||||||
|
<table summary="state transitions" border="1" cellpadding="5">
|
||||||
|
<tr>
|
||||||
|
<td><b>From</b></td>
|
||||||
|
<td><b>To</b></td>
|
||||||
|
<td><b>Cause</b></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<p align="left">[none]</p>
|
||||||
|
</td>
|
||||||
|
<td>Ready</td>
|
||||||
|
<td>Thread is created by a call to a library function. In the case of the
|
||||||
|
initial thread, creation is implicit and occurs during the startup of the
|
||||||
|
main() function [3.6.1].</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Ready</td>
|
||||||
|
<td>Running</td>
|
||||||
|
<td>Processor becomes available.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Running</td>
|
||||||
|
<td>Ready</td>
|
||||||
|
<td>Thread preempted.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Running</td>
|
||||||
|
<td>Blocked</td>
|
||||||
|
<td>Thread calls a library function which waits for a resource or for the
|
||||||
|
completion of I/O.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Running</td>
|
||||||
|
<td>Terminated</td>
|
||||||
|
<td>Thread returns from its initial function, calls a thread termination library
|
||||||
|
function, or is canceled by some other thread calling a thread termination
|
||||||
|
library function.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Blocked</td>
|
||||||
|
<td>Ready</td>
|
||||||
|
<td>The resource being waited for becomes available, or the blocking library
|
||||||
|
function completes.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Terminated</td>
|
||||||
|
<td>[none]</td>
|
||||||
|
<td>Thread is detached or joined by some other thread calling the appropriate
|
||||||
|
library function, or by program termination [3.6.3].</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<p>[Note: if a suspend() function is added to the threading library, additional
|
||||||
|
transitions to the blocked state will have to be added to the above table.]</p>
|
||||||
|
<h3><a name="definition-race-condition"></a>Race Condition</h3>
|
||||||
|
<p>A race condition is what occurs when multiple threads read and write to the
|
||||||
|
same memory without proper synchronization, resulting in an incorrect value
|
||||||
|
being read or written. The result of a race condition may be a bit pattern which
|
||||||
|
isn't even a valid value for the data type. A race condition results in
|
||||||
|
undefined behavior [1.3.12].</p>
|
||||||
|
<p>Race conditions can be prevented by serializing memory access using the tools
|
||||||
|
provided by Boost.Threads.</p>
|
||||||
|
<h3><a name="definition-deadlock"></a>Deadlock</h3>
|
||||||
|
<p>Deadlock is an execution state where for some set of threads, each thread in
|
||||||
|
the set is blocked waiting for some action by one of the other threads in the
|
||||||
|
set. Since each is waiting on the others, none will ever become ready again.</p>
|
||||||
|
<h3><a name="definition-starvation"></a>Starvation</h3>
|
||||||
|
<p>The condition in which a thread is not making sufficient progress in its work
|
||||||
|
during a given time interval.</p>
|
||||||
|
<h3><a name="definition-priority-failure"></a>Priority Failure</h3>
|
||||||
|
<p>A priority failure (such as priority inversion or infinite overtaking) occurs
|
||||||
|
when threads executed in such a sequence that required work is not performed
|
||||||
|
in time to be useful.</p>
|
||||||
|
<h3><a name="definition-visibility"></a>Memory Visibility</h3>
|
||||||
|
<p>An address [1.7] shall always point to the same memory byte, regardless of
|
||||||
|
the thread or processor dereferencing the address.</p>
|
||||||
|
<p>An object [1.8, 1.9] is accessible from multiple threads if it is of static
|
||||||
|
storage duration (static, extern) [3.7.1], or if a pointer or reference to it
|
||||||
|
is explicitly or implicitly dereferenced in multiple threads.</p>
|
||||||
|
<p>For an object accessible from multiple threads, the value of the object accessed
|
||||||
|
from one thread may be indeterminate or different than the value accessed from
|
||||||
|
another thread, except under the conditions specified in the following table.
|
||||||
|
For the same row of the table, the value of an object accessible at the indicated
|
||||||
|
sequence point in thread A will be determinate and the same if accessed at or
|
||||||
|
after the indicated sequence point in thread B, provided the object is not otherwise
|
||||||
|
modified. In the table, the "sequence point at a call" is the sequence
|
||||||
|
point after the evaluation of all function arguments [1.9/17], while the "sequence
|
||||||
|
point after a call" is the sequence point after the copying of the returned
|
||||||
|
value..." [1.9/17].</p>
|
||||||
|
<table summary="memory visibility" border="1" cellpadding="5">
|
||||||
|
<tr>
|
||||||
|
<td align="center"><b>Thread A</b></td>
|
||||||
|
<td align="center"><b>Thread B</b></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>The sequence point at a call to a library thread-creation function.</td>
|
||||||
|
<td>The first sequence point of the initial function in the new thread created
|
||||||
|
by the Thread A call.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>The sequence point at a call to a library function which locks a mutex,
|
||||||
|
directly or by waiting for a condition variable.</td>
|
||||||
|
<td>The sequence point after a call to a library function which unlocks the
|
||||||
|
same mutex.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>The last sequence point before thread termination.</td>
|
||||||
|
<td>The sequence point after a call to a library function which joins the
|
||||||
|
terminated thread.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>The sequence point at a call to a library function which signals or broadcasts
|
||||||
|
a condition variable.</td>
|
||||||
|
<td>The sequence point after the call to the library function which was waiting
|
||||||
|
on that same condition variable or signal.</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<p>The architecture of the execution environment and the observable behavior of
|
||||||
|
the abstract machine [1.9] shall be the same on all processors.</p>
|
||||||
|
<p>The latitude granted by the C++ standard for an implementation to alter the
|
||||||
|
definition of observable behavior of the abstract machine to include additional
|
||||||
|
library I/O functions [1.9/6] is extended to include threading library functions.</p>
|
||||||
|
<p>When an exception is thrown and there is no matching exception handler in the
|
||||||
|
same thread, behavior is undefined. The preferred behavior is the same as when
|
||||||
|
there is no matching exception handler in a program [15.3/9]. That is, terminate()
|
||||||
|
is called, and it is implementation defined whether or not the stack is unwound.</p>
|
||||||
|
<h2><a name="acknowledgements"></a>Acknowledgments</h2>
|
||||||
|
<p>This document has been much improved by the incorporation of comments from
|
||||||
|
William Kempf.</p>
|
||||||
|
<p>The visibility rules are based on <a href=
|
||||||
|
"bibliography.html#Butenhof-97">[Butenhof 97]</a>.</p>
|
||||||
|
<hr>
|
||||||
|
<p>Revised
|
||||||
|
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
||||||
|
05 November, 2001
|
||||||
|
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
|
||||||
|
</p>
|
||||||
|
<p><i>© Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
|
||||||
|
All Rights Reserved.</i></p>
|
||||||
|
<p>Permission to use, copy, modify, distribute and sell this software and its
|
||||||
|
documentation for any purpose is hereby granted without fee, provided that the
|
||||||
|
above copyright notice appear in all copies and that both that copyright notice
|
||||||
|
and this permission notice appear in supporting documentation. William E. Kempf
|
||||||
|
makes no representations about the suitability of this software for any purpose.
|
||||||
|
It is provided "as is" without express or implied warranty.</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
110
doc/exceptions.html
Normal file
110
doc/exceptions.html
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||||
|
<link rel="stylesheet" type="text/css" href="../../../boost.css">
|
||||||
|
<title>Boost.Threads - Header <boost/thread/exceptions.hpp></title>
|
||||||
|
</head>
|
||||||
|
<body link="#0000ff" vlink="#800080">
|
||||||
|
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
|
||||||
|
"header">
|
||||||
|
<tr>
|
||||||
|
<td valign="top" width="300">
|
||||||
|
<h3><a href="../../../index.htm"><img height="86" width="277" alt="C++ Boost" src="../../../c++boost.gif" border="0"></a></h3>
|
||||||
|
</td>
|
||||||
|
<td valign="top">
|
||||||
|
<h1 align="center">Boost.Threads</h1>
|
||||||
|
<h2 align="center">Header <<a href="../../../boost/thread/exceptions.hpp">boost/thread/exceptions.hpp</a>></h2>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<hr>
|
||||||
|
<h2>Contents</h2>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="#introduction">Introduction</a></dt>
|
||||||
|
<dt><a href="#classes">Classes</a></dt>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="#class-lock_error">Class <code>lock_error</code></a></dt>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="#class-lock_error-synopsis">Class <code>lock_error</code> synopsis</a></dt>
|
||||||
|
<dt><a href="#class-lock_error-ctors">Class <code>lock_error</code> constructors
|
||||||
|
and destructor</a></dt>
|
||||||
|
</dl>
|
||||||
|
<dt><a href="#class-thread_resource_error">Class <code>thread_resource_error</code></a></dt>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="#class-thread_resource_error-synopsis">Class <code>thread_resource_error</code>
|
||||||
|
synopsis</a></dt>
|
||||||
|
<dt><a href="#class-thread_resource_error-ctors">Class <code>thread_resource_error</code>
|
||||||
|
constructors and destructor</a></dt>
|
||||||
|
</dl>
|
||||||
|
</dl>
|
||||||
|
</dl>
|
||||||
|
<hr>
|
||||||
|
<h2><a name="introduction"></a>Introduction</h2>
|
||||||
|
<p>Include the header <<a href="../../../boost/thread/exceptions.hpp">boost/thread/exceptions.hpp</a>>
|
||||||
|
to define the exception types that may be thrown by <b>Boost.Threads</b> classes.</p>
|
||||||
|
<h2><a name="classes"></a>Classes</h2>
|
||||||
|
<h3><a name="class-lock_error"></a>Class <code>lock_error</code></h3>
|
||||||
|
<p>The lock_error class defines an exception type thrown to indicate a locking
|
||||||
|
related error has been detected. Examples of such errors include a lock operation
|
||||||
|
which can be determined to result in a deadlock, or unlock operations attempted
|
||||||
|
by a thread that does not own the lock. </p>
|
||||||
|
<h4><a name="class-lock_error-synopsis"></a>Class <code>lock_error</code> synopsis</h4>
|
||||||
|
<pre>
|
||||||
|
namespace boost
|
||||||
|
{
|
||||||
|
class lock_error : public std::logical_error
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
lock_error();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
</pre>
|
||||||
|
<h4><a name="class-lock_error-ctors"></a>Class <code>lock_error</code> constructors
|
||||||
|
and destructor</h4>
|
||||||
|
<pre>
|
||||||
|
lock_error();
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<dt><b>Effects:</b> Constructs a <code>lock_error</code> object.</dt>
|
||||||
|
</dl>
|
||||||
|
<h3><a name="class-thread_resource_error"></a>Class <code>thread_resource_error</code></h3>
|
||||||
|
<p>The thread_resource_error class defines an exception type that is thrown by
|
||||||
|
constructors in the Boost.Threads library when thread related resources can
|
||||||
|
not be acquired. This does not include memory allocation failures which instead
|
||||||
|
throw std::bad_alloc. </p>
|
||||||
|
<h4><a name="class-thread_resource_error-synopsis"></a>Class <code>thread_resource_error</code>
|
||||||
|
synopsis</h4>
|
||||||
|
<pre>
|
||||||
|
namespace boost
|
||||||
|
{
|
||||||
|
class thread_resource_error : public std::runtime_error
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
thread_resource_error();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
</pre>
|
||||||
|
<h4><a name="class-thread_resource_error-ctors"></a>Class <code>thread_resource_error</code>
|
||||||
|
constructors and destructor</h4>
|
||||||
|
<pre>
|
||||||
|
thread_resource_error();
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<dt><b>Effects:</b> Constructs a <code>thread_resource_error</code> object.</dt>
|
||||||
|
</dl>
|
||||||
|
<hr>
|
||||||
|
<p>Revised
|
||||||
|
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
||||||
|
05 November, 2001
|
||||||
|
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
|
||||||
|
</p>
|
||||||
|
<p><i>© Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
|
||||||
|
All Rights Reserved.</i></p>
|
||||||
|
<p>Permission to use, copy, modify, distribute and sell this software and its
|
||||||
|
documentation for any purpose is hereby granted without fee, provided that the
|
||||||
|
above copyright notice appear in all copies and that both that copyright notice
|
||||||
|
and this permission notice appear in supporting documentation. William E. Kempf
|
||||||
|
makes no representations about the suitability of this software for any purpose.
|
||||||
|
It is provided "as is" without express or implied warranty.</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
183
doc/faq.html
Normal file
183
doc/faq.html
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||||
|
<link rel="stylesheet" type="text/css" href="../../../boost.css">
|
||||||
|
<title>Boost.Threads - FAQ</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">Frequently Asked Questions (FAQs)</h2>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<hr>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="#question1">1. Are lock objects thread safe?</a></dt>
|
||||||
|
<dt><a href="#question2a">2a. Why was <b>Boost.Threads</b> modeled after (specific
|
||||||
|
library name)?</a></dt>
|
||||||
|
<dt><a href="#question2b">2b. Why wasn't <b>Boost.Threads</b> modeled after
|
||||||
|
(specific library name)?</a></dt>
|
||||||
|
<dt><a href="#question3">3. Why do mutexes have noncopyable semantics?</a></dt>
|
||||||
|
<dt><a href="#question4">4. How can you prevent deadlock from occurring when
|
||||||
|
a thread must lock multiple mutexes?</a></dt>
|
||||||
|
<dt><a href="#question5">5. Don't noncopyable mutex semantics mean that a class
|
||||||
|
with a mutex member will be noncopyable as well?</a></dt>
|
||||||
|
<dt><a href="#question6">6. How can you lock a mutex member in a const member
|
||||||
|
function (in order to implement the monitor pattern)?</a></dt>
|
||||||
|
<dt><a href="#question7">7. Why supply condition variables rather than event
|
||||||
|
variables?</a></dt>
|
||||||
|
<dt><a href="#question8">8. Why isn't thread cancellation or termination provided?</a></dt>
|
||||||
|
<dt><a href="#question9">9. Is it safe for threads to share automatic storage
|
||||||
|
duration (stack) objects via pointers or references?</a></dt>
|
||||||
|
<dt><a href="#question10">10. Why has class semaphore disappeared?</a></dt>
|
||||||
|
</dl>
|
||||||
|
<h2><a name="question1"></a>1. Are lock objects <a href="definitions.html#definition-thread-safe">
|
||||||
|
thread safe</a>?</h2>
|
||||||
|
<p><b>No!</b> Lock objects are not meant to be shared between threads. They are
|
||||||
|
meant to be short-lived objects created on automatic storage within a code block.
|
||||||
|
Any other usage is just likely to lead to errors and won't really be of
|
||||||
|
actual benefit any way. Share <a href=
|
||||||
|
"mutex_concept.html">mutexes</a>, not locks. For more information see
|
||||||
|
the <a href="rationale.html#lock_objects">rationale</a> behind the design for
|
||||||
|
lock objects.</p>
|
||||||
|
<h2><a name="question2a"></a>2a. Why was <b>Boost.Threads</b> modeled after (specific
|
||||||
|
library name)?</h2>
|
||||||
|
<p>It wasn't. Boost.Threads was designed from scratch. Extensive design discussions
|
||||||
|
involved numerous people representing a wide range of experience across many
|
||||||
|
platforms. To ensure portability, the initial implements were done in parallel
|
||||||
|
using POSIX Threads and the Win32 threading API. But the Boost.Threads design
|
||||||
|
is very much in the spirit of C++, and thus doesn't model such C based APIs.</p>
|
||||||
|
<h2><a name="question2b"></a>2b. Why wasn't Boost.Threads modeled after (specific
|
||||||
|
library name)?</h2>
|
||||||
|
<p>Existing C++ libraries either seemed dangerous (often failing to take advantage
|
||||||
|
of prior art to reduce errors) or had excessive dependencies on library components
|
||||||
|
unrelated to threading. Existing C libraries couldn't meet our C++ requirements,
|
||||||
|
and were also missing certain features. For instance, the WIN32 thread API lacks
|
||||||
|
condition variables, even though these are critical for the important Monitor
|
||||||
|
pattern <a href="bibliography.html#Schmidt-00">[Schmidt 00]</a>.</p>
|
||||||
|
<h2><a name="question3"></a>3. Why do <a href="mutex_concept.html">Mutexes</a>
|
||||||
|
have noncopyable semantics?</h2>
|
||||||
|
<p>To ensure that <a href="definitions.html#Deadlock">deadlocks</a> don't
|
||||||
|
occur. The only logical form of copy would be to use some sort of shallow copy
|
||||||
|
semantics in which multiple mutex objects could refer to the same mutex state.
|
||||||
|
This means that if ObjA has a mutex object as part of its state and ObjB is
|
||||||
|
copy constructed from it, then when ObjB::foo() locks the mutex it has effectively
|
||||||
|
locked ObjA as well. This behavior can result in deadlock. Other copy semantics
|
||||||
|
result in similar problems (if you think you can prove this to be wrong then
|
||||||
|
supply us with an alternative and we'll reconsider).</p>
|
||||||
|
<h2><a name="question4"></a>4. How can you prevent <a href="definitions.html#Deadlock">
|
||||||
|
deadlock</a> from occurring when a thread must lock multiple mutexes?</h2>
|
||||||
|
<p>Always lock them in the same order. One easy way of doing this is to use each
|
||||||
|
mutex's address to determine the order in which they are locked. A future
|
||||||
|
Boost.Threads concept may wrap this pattern up in a reusable class.</p>
|
||||||
|
<h2><a name="question5"></a>5. Don't noncopyable <a href="mutex_concept.html">mutex</a>
|
||||||
|
semantics mean that a class with a mutex member will be noncopyable as well?</h2>
|
||||||
|
<p>No, but what it does mean is that the compiler can't generate a copy constructor
|
||||||
|
and assignment operator, so they will have to be coded explicitly. This is a
|
||||||
|
<b>good thing</b>, however, since the compiler generated operations would not
|
||||||
|
be <a href=
|
||||||
|
"definitions.html#Thread-safe">thread-safe</a>. The following is a simple
|
||||||
|
example of a class with copyable semantics and internal synchronization through
|
||||||
|
a mutex member.</p>
|
||||||
|
<pre>
|
||||||
|
class counter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Doesn't need synchronization since there can be no references to *this
|
||||||
|
// until after it's constructed!
|
||||||
|
explicit counter(int initial_value)
|
||||||
|
: m_value(initial_value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// We only need to synchronize other for the same reason we don't have to
|
||||||
|
// synchronize on construction!
|
||||||
|
counter(const counter& other)
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock scoped_lock(other.m_mutex);
|
||||||
|
m_value = other.m_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For assignment we need to synchronize both objects!
|
||||||
|
const counter& operator=(const counter& other)
|
||||||
|
{
|
||||||
|
if (this == &other)
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
boost::mutex::scoped_lock lock1(&m_mutex < &other.m_mutex ? m_mutex : other.m_mutex);
|
||||||
|
boost::mutex::scoped_lock lock2(&m_mutex > &other.m_mutex ? m_mutex : other.m_mutex);
|
||||||
|
m_value = other.m_value;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
int value() const
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock scoped_lock(m_mutex);
|
||||||
|
return m_value;
|
||||||
|
}
|
||||||
|
int increment()
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock scoped_lock(m_mutex);
|
||||||
|
return ++m_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
mutable boost::mutex m_mutex;
|
||||||
|
int m_value;
|
||||||
|
};
|
||||||
|
</pre>
|
||||||
|
<h2><a name="question6"></a>6. How can you lock a <a href="mutex_concept.html">mutex</a>
|
||||||
|
member in a const member function, in order to implement the Monitor Pattern?</h2>
|
||||||
|
<p>The Monitor Pattern mutex <a href="bibliography.html#Schmidt-00"> [Schmidt
|
||||||
|
00]</a> should simply be declared as mutable. See the example code above. The
|
||||||
|
internal state of mutex types could have been made mutable, with all lock calls
|
||||||
|
made via const functions, but this does a poor job of documenting the actual
|
||||||
|
semantics (and in fact would be incorrect since the logical state of a locked
|
||||||
|
mutex clearly differs from the logical state of an unlocked mutex). Declaring
|
||||||
|
a mutex member as mutable clearly documents the intended semantics.</p>
|
||||||
|
<h2><a name="question7"></a>7. Why supply <a href="condition.html">condition variables</a>
|
||||||
|
rather than <a href="rationale.html#Events">event variables</a>?</h2>
|
||||||
|
<p>Condition variables result in user code much less prone to <a href=
|
||||||
|
"definitions.html#Race condition">race conditions</a> than event variables.
|
||||||
|
See <a href="rationale.html#Events">Rationale</a> for analysis. Also see <a href="bibliography.html#Hoare-74">[Hoare
|
||||||
|
74]</a> and <a href="bibliography.html#Schmidt-00">[Schmidt 00]</a>.</p>
|
||||||
|
<h2><a name="question8"></a>8. Why isn't thread cancellation or termination
|
||||||
|
provided?</h2>
|
||||||
|
<p>There's a valid need for thread termination, so at some point Boost.Threads
|
||||||
|
probably will include it, but only after we can find a truly safe (and portable)
|
||||||
|
mechanism for this concept.</p>
|
||||||
|
<h2><a name="question9"></a>9. Is it safe for threads to share automatic storage
|
||||||
|
duration (stack) objects via pointers or references?</h2>
|
||||||
|
<p>Only if you can guarantee that the lifetime of the stack object will not end
|
||||||
|
while other threads might still access the object. Thus the safest practice
|
||||||
|
is to avoid sharing stack objects, particularly in designs where threads are
|
||||||
|
created and destroyed dynamically. Restrict sharing of stack objects to simple
|
||||||
|
designs with very clear and unchanging function and thread lifetimes. (Suggested
|
||||||
|
by Darryl Green).</p>
|
||||||
|
<h2><a name="question10"></a>10. Why has class semaphore disappeared?</h2>
|
||||||
|
<p>Semaphore was removed as too error prone. The same effect can be achieved with
|
||||||
|
greater safety by the combination of a mutex and a condition variable.</p>
|
||||||
|
<hr>
|
||||||
|
<p>Revised
|
||||||
|
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
||||||
|
05 November, 2001
|
||||||
|
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
|
||||||
|
</p>
|
||||||
|
<p><i>© Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
|
||||||
|
All Rights Reserved.</i></p>
|
||||||
|
<p>Permission to use, copy, modify, distribute and sell this software and its
|
||||||
|
documentation for any purpose is hereby granted without fee, provided that the
|
||||||
|
above copyright notice appear in all copies and that both that copyright notice
|
||||||
|
and this permission notice appear in supporting documentation. William E. Kempf
|
||||||
|
makes no representations about the suitability of this software for any purpose.
|
||||||
|
It is provided "as is" without express or implied warranty.</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
155
doc/index.html
Normal file
155
doc/index.html
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||||
|
<link rel="stylesheet" type="text/css" href="../../../boost.css">
|
||||||
|
<title>Boost.Threads</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">Index</h2>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<hr>
|
||||||
|
<h2>Contents</h2>
|
||||||
|
<dl class="index">
|
||||||
|
<dt><a href="overview.html">Overview</a></dt>
|
||||||
|
<dt><a href="mutex_concept.html">Mutex Concepts</a></dt>
|
||||||
|
<dl class="index">
|
||||||
|
<dt><a href="mutex_concept.html#Mutex">Mutex</a></dt>
|
||||||
|
<dt><a href="mutex_concept.html#TryMutex">TryMutex</a></dt>
|
||||||
|
<dt><a href="mutex_concept.html#TimedMutex">TimedMutex</a></dt>
|
||||||
|
</dl>
|
||||||
|
<dt><a href="lock_concept.html">Lock Concepts</a></dt>
|
||||||
|
<dl class="index">
|
||||||
|
<dt><a href="lock_concept.html#Lock">Lock</a></dt>
|
||||||
|
<dt><a href="lock_concept.html#ScopedLock">ScopedLock</a></dt>
|
||||||
|
<dt><a href="lock_concept.html#ScopedTryLock">ScopedTryLock</a></dt>
|
||||||
|
<dt><a href="lock_concept.html#ScopedTimedLock">ScopedTimedLock</a></dt>
|
||||||
|
</dl>
|
||||||
|
<dt>Reference</dt>
|
||||||
|
<dl class="index">
|
||||||
|
<dt><a href="condition.html"><code><boost/thread/condition.hpp></code></a></dt>
|
||||||
|
<dl class="index">
|
||||||
|
<dt><a href="condition.html#classes">Classes</a></dt>
|
||||||
|
<dl class="index">
|
||||||
|
<dt><a href="condition.html#class-condition"><code>condition</code></a></dt>
|
||||||
|
</dl>
|
||||||
|
</dl>
|
||||||
|
</dl>
|
||||||
|
<dl class="index">
|
||||||
|
<dt><a href="exceptions.html"><code><boost/thread/exceptions.hpp></code></a></dt>
|
||||||
|
<dl class="index">
|
||||||
|
<dt><a href="exceptions.html#classes">Classes</a></dt>
|
||||||
|
<dl class="index">
|
||||||
|
<dt><a href="exceptions.html#class-lock_error"><code>lock_error</code></a></dt>
|
||||||
|
<dt><a href="exceptions.html#class-thread_resource_error"><code>thread_resource_error</code></a></dt>
|
||||||
|
</dl>
|
||||||
|
</dl>
|
||||||
|
</dl>
|
||||||
|
<dl class="index">
|
||||||
|
<dt><a href="mutex.html"><code><boost/thread/mutex.hpp></code></a></dt>
|
||||||
|
<dl class="index">
|
||||||
|
<dt><a href="mutex.html#classes">Classes</a></dt>
|
||||||
|
<dl class="index">
|
||||||
|
<dt><a href="mutex.html#class-mutex"><code>mutex</code></a></dt>
|
||||||
|
<dt><a href="mutex.html#class-try_mutex"><code>try_mutex</code></a></dt>
|
||||||
|
<dt><a href="mutex.html#class-timed_mutex"><code>timed_mutex</code></a></dt>
|
||||||
|
</dl>
|
||||||
|
</dl>
|
||||||
|
</dl>
|
||||||
|
<dl class="index">
|
||||||
|
<dt><a href="once.html"><code><boost/thread/once.hpp></code></a></dt>
|
||||||
|
<dl class="index">
|
||||||
|
<dt><a href="once.html#macros">Macros</a></dt>
|
||||||
|
<dl class="index">
|
||||||
|
<dt><a href="once.html#macro-BOOST_ONCE_INIT"><code>BOOST_ONCE_INIT</code></a></dt>
|
||||||
|
</dl>
|
||||||
|
<dt><a href="once.html#types">Types</a></dt>
|
||||||
|
<dl class="index">
|
||||||
|
<dt><a href="once.html#type-once_flag"><code>once_flag</code></a></dt>
|
||||||
|
</dl>
|
||||||
|
<dt><a href="once.html#functions">Functions</a></dt>
|
||||||
|
<dl class="index">
|
||||||
|
<dt><a href="once.html#function-call_once"><code>call_once</code></a></dt>
|
||||||
|
</dl>
|
||||||
|
</dl>
|
||||||
|
</dl>
|
||||||
|
<dl class="index">
|
||||||
|
<dt><a href="recursive_mutex.html"><code><boost/thread/recursive_mutex.hpp></code></a></dt>
|
||||||
|
<dl class="index">
|
||||||
|
<dt><a href="recursive_mutex.html#classes">Classes</a></dt>
|
||||||
|
<dl class="index">
|
||||||
|
<dt><a href="recursive_mutex.html#class-recursive_mutex"><code>recursive_mutex</code></a></dt>
|
||||||
|
<dt><a href="recursive_mutex.html#class-recursive_try_mutex"><code>recursive_try_mutex</code></a></dt>
|
||||||
|
<dt><a href="recursive_mutex.html#class-recursive_timed_mutex"><code>recursive_timed_mutex</code></a></dt>
|
||||||
|
</dl>
|
||||||
|
</dl>
|
||||||
|
</dl>
|
||||||
|
<dl class="index">
|
||||||
|
<dt><a href="thread.html"><code><boost/thread/thread.hpp></code></a></dt>
|
||||||
|
<dl class="index">
|
||||||
|
<dt><a href="thread.html#classes">Classes</a></dt>
|
||||||
|
<dl class="index">
|
||||||
|
<dt><a href="thread.html#class-thread"><code>thread</code></a></dt>
|
||||||
|
<dt><a href="thread.html#class-thread_group"><code>thread_group</code></a></dt>
|
||||||
|
</dl>
|
||||||
|
</dl>
|
||||||
|
</dl>
|
||||||
|
<dl class="index">
|
||||||
|
<dt><a href="tss.html"><code><boost/thread/tss.hpp></code></a></dt>
|
||||||
|
<dl class="index">
|
||||||
|
<dt><a href="tss.html#classes">Classes</a></dt>
|
||||||
|
<dl class="index">
|
||||||
|
<dt><a href="tss.html#class-thread_specific_ptr"><code>thread_specific_ptr</code></a></dt>
|
||||||
|
</dl>
|
||||||
|
</dl>
|
||||||
|
</dl>
|
||||||
|
<dl class="index">
|
||||||
|
<dt><a href="xtime.html"><code><boost/thread/xtime.hpp></code></a></dt>
|
||||||
|
<dl class="index">
|
||||||
|
<dt><a href="xtime.html#values">Values</a></dt>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="xtime.html#value-spec"><code>TIME_UTC</code></a></dt>
|
||||||
|
</dl>
|
||||||
|
<dt><a href="xtime.html#classes">Classes</a></dt>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="xtime.html#class-xtime"><code>xtime</code></a></dt>
|
||||||
|
</dl>
|
||||||
|
<dt><a href="xtime.html#functions">Functions</a></dt>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="xtime.html#function-xtime_get"><code>xtime_get</code></a></dt>
|
||||||
|
</dl>
|
||||||
|
</dl>
|
||||||
|
</dl>
|
||||||
|
<dt><a href="configuration.html">Configuration Information</a></dt>
|
||||||
|
<dt><a href="introduction.html">Introduction to Design</a></dt>
|
||||||
|
<dt><a href="rationale.html">Rationale</a></dt>
|
||||||
|
<dt><a href="definitions.html">Definitions</a></dt>
|
||||||
|
<dt><a href="faq.html">Frequently Asked Questions (FAQs)</a></dt>
|
||||||
|
<dt><a href="bibliography.html">Bibliography</a></dt>
|
||||||
|
<dt><a href="acknowledgments.html">Acknowledgments</a></dt>
|
||||||
|
</dl>
|
||||||
|
<hr>
|
||||||
|
<p>Revised
|
||||||
|
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
||||||
|
05 November, 2001
|
||||||
|
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
|
||||||
|
</p>
|
||||||
|
<p><i>© Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
|
||||||
|
All Rights Reserved.</i></p>
|
||||||
|
<p>Permission to use, copy, modify, distribute and sell this software and its
|
||||||
|
documentation for any purpose is hereby granted without fee, provided that the
|
||||||
|
above copyright notice appear in all copies and that both that copyright notice
|
||||||
|
and this permission notice appear in supporting documentation. William E. Kempf
|
||||||
|
makes no representations about the suitability of this software for any purpose.
|
||||||
|
It is provided "as is" without express or implied warranty.</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
159
doc/introduction.html
Normal file
159
doc/introduction.html
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||||
|
<link rel="stylesheet" type="text/css" href="../../../boost.css">
|
||||||
|
<title>Boost.Threads - Introduction to Design</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">Introduction to Design</h2>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<hr>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="#motivation">Motivation</a></dt>
|
||||||
|
<dt><a href="#goals">Goals</a></dt>
|
||||||
|
<dt><a href="#phases">Iterative Phases</a></dt>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="#phase1">Phase 1, Synchronization Primitives</a></dt>
|
||||||
|
<dt><a href="#phase2">Phase 2, Thread Management and Thread Specific Storage</a></dt>
|
||||||
|
<dt><a href="#next-phase">The Next Phase</a></dt>
|
||||||
|
</dl>
|
||||||
|
</dl>
|
||||||
|
<h2><a name="motivation"></a>Motivation</h2>
|
||||||
|
<p>With client/server and three-tier architectures becoming common place in today's
|
||||||
|
world, it's becoming increasingly important for programs to be able to handle
|
||||||
|
parallel processing. Modern day operating systems usually provide some support
|
||||||
|
for this through native thread APIs. Unfortunately, writing portable code that
|
||||||
|
makes use of parallel processing in C++ is made very difficult by a lack of
|
||||||
|
a standard interface for these native APIs. Further, these APIs are almost universally
|
||||||
|
C APIs and fail to take advantage of C++'s strengths, or to address C++'s
|
||||||
|
issues.</p>
|
||||||
|
<p>The <b>Boost.Threads</b> library is an attempt to define a portable interface
|
||||||
|
for writing parallel processes in C++.</p>
|
||||||
|
<h2><a name="goals"></a>Goals</h2>
|
||||||
|
<p>The <b>Boost.Threads</b> library has several goals that should help to set
|
||||||
|
it apart from other solutions. These goals are listed in order of precedence
|
||||||
|
with full descriptions below.</p>
|
||||||
|
<ul>
|
||||||
|
<li> <b>Portability</b>
|
||||||
|
<p><b>Boost.Threads</b> was designed to be highly portable. The goal is for
|
||||||
|
the interface to be easily implemented on any platform that supports threads,
|
||||||
|
and possibly even on platforms without native thread support.</p>
|
||||||
|
</li>
|
||||||
|
<li> <b>Safety</b>
|
||||||
|
<p><b>Boost.Threads</b> was designed to be as safe as possible. Writing <a href="definitions.html#Thread-safe">thread-safe</a>
|
||||||
|
code is very difficult and successful libraries must strive to insulate
|
||||||
|
the programmer from dangerous constructs as much as possible. This is accomplished
|
||||||
|
in several ways:</p>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<p align="left">C++ language features are used make correct usage easy
|
||||||
|
(if possible, the default) and error-prone impossible or at least more
|
||||||
|
difficult. For example, see the <a href="mutex_concept.html">Mutex</a>
|
||||||
|
and <a href="lock_concept.html">Lock</a> designs, and how note how they
|
||||||
|
interact.</p>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<p align="left">Certain traditional concurrent programming features are
|
||||||
|
considered so error-prone that they are not provided at all. For example,
|
||||||
|
see the <a
|
||||||
|
href="rationale.html#Events">Events Not Provided</a> rationale.</p>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<p align="left">Dangerous features, or features which may be misused,
|
||||||
|
are identified as such in the documentation to make users aware of potential
|
||||||
|
pitfalls.</p>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li> <b>Flexibility</b>
|
||||||
|
<p><b>Boost.Threads</b> was designed to be flexible. This goal is often at
|
||||||
|
odds with <i>safety</i>. When functionality might be compromised by the
|
||||||
|
desire to keep the interface safe, <b> Boost.Threads</b> has been designed
|
||||||
|
to provide the functionality, but to make it's use prohibitive for general
|
||||||
|
use. In other words, the interfaces have been designed such that it's usually
|
||||||
|
obvious when something is unsafe, and the documentation is written to explain
|
||||||
|
why.</p>
|
||||||
|
</li>
|
||||||
|
<li> <b>Efficiency</b>
|
||||||
|
<p><b>Boost.Threads</b> was designed to be as efficient as possible. When
|
||||||
|
building a library on top of another library there is always a danger that
|
||||||
|
the result will be so much slower than the "native" API that programmers
|
||||||
|
are inclined to ignore the higher level API. <b>Boost.Threads</b> was designed
|
||||||
|
to minimize the chances of this occurring. The interfaces have been crafted
|
||||||
|
to allow an implementation the greatest chance of being as efficient as
|
||||||
|
possible. This goal is often at odds with the goal for <i>safety</i>. Every
|
||||||
|
effort was made to ensure efficient implementations, but when in conflict
|
||||||
|
<i>safety</i> has always taken precedence.</p>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<h2><a name="phases"></a>Iterative Phases</h2>
|
||||||
|
<p>Another goal of <b>Boost.Threads</b> was to take a dynamic, iterative approach
|
||||||
|
in its development. The computing industry is still exploring the concepts of
|
||||||
|
parallel programming. Most thread libraries supply only simple primitive concepts
|
||||||
|
for thread synchronization. These concepts are very simple, but they are very
|
||||||
|
difficult to use safely or to provide formal proofs for constructs built on
|
||||||
|
top of them. There has been a lot of research in other concepts, such as in
|
||||||
|
"Communicating Sequential Processes." <b>Boost.Threads</b> was designed
|
||||||
|
in iterative steps, providing the building blocks necessary for the next step,
|
||||||
|
and giving the researcher the tools necessary to explore new concepts in a portable
|
||||||
|
manner.</p>
|
||||||
|
<p>Given the goal of following a dynamic, iterative approach <b> Boost.Threads</b>
|
||||||
|
shall go through several growth cycles. Each phase in its development shall
|
||||||
|
be roughly documented here.</p>
|
||||||
|
<h3><a name="phase1"></a>Phase 1, Synchronization Primitives</h3>
|
||||||
|
<p>Boost is all about providing high quality libraries with implementations for
|
||||||
|
many platforms. Unfortunately, there's a big problem faced by developers
|
||||||
|
wishing to supply such high quality libraries, namely thread-safety. The C++
|
||||||
|
standard doesn't address threads at all, but real world programs often make
|
||||||
|
use of native threading support. A portable library that doesn't address
|
||||||
|
the issue of thread-safety is there for not much help to a programmer who wants
|
||||||
|
to use the library in his multithreaded application. So there's a very great
|
||||||
|
need for portable primitives that will allow the library developer to create
|
||||||
|
<a href="definitions.html#Thread-safe"> thread-safe</a> implementations. This
|
||||||
|
need far out weighs the need for portable methods to create and manage threads.</p>
|
||||||
|
<p>Because of this need, the first phase of <b>Boost.Threads</b> focuses solely
|
||||||
|
on providing portable primitive concepts for thread synchronization. Types provided
|
||||||
|
in this phase include the <a href="mutex.html"> mutex/try_mutex/timed_mutex</a>,
|
||||||
|
<a href="recursive_mutex.html"> recursive_mutex/recursive_try_mutex/recursive_timed_mutex</a>
|
||||||
|
and <a href="exceptions.html#class-lock_error">lock_error</a>. These are considered
|
||||||
|
the "core" synchronization primitives, though there are others that
|
||||||
|
will be added in later phases.</p>
|
||||||
|
<h3><a name="phase2"></a>Phase 2, Thread Management and Thread Specific Storage</h3>
|
||||||
|
<p>This phase addresses the creation and management of threads and provides a
|
||||||
|
mechanism for thread specific storage (data associated with a thread instance).
|
||||||
|
Thread management is a tricky issue in C++, so this phase addresses only the
|
||||||
|
basic needs of multithreaded program. Later phases are likely to add additional
|
||||||
|
functionality in this area. This phase of <b>Boost.Threads</b> adds the <a href="thread.html">thread</a>
|
||||||
|
and <a href="tss.html#class-thread_specific_ptr">thread_specific_ptr</a> types.
|
||||||
|
With these additions the <b>Boost.Threads</b> library can be considered minimal
|
||||||
|
but complete.</p>
|
||||||
|
<h3><a name="next-phase"></a>The Next Phase</h3>
|
||||||
|
<p>The next phase will address more advanced synchronization concepts, such as
|
||||||
|
read/write mutexes and barriers.</p>
|
||||||
|
<hr>
|
||||||
|
<hr>
|
||||||
|
<p>Revised
|
||||||
|
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
||||||
|
05 November, 2001
|
||||||
|
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
|
||||||
|
</p>
|
||||||
|
<p><i>© Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
|
||||||
|
All Rights Reserved.</i></p>
|
||||||
|
<p>Permission to use, copy, modify, distribute and sell this software and its
|
||||||
|
documentation for any purpose is hereby granted without fee, provided that the
|
||||||
|
above copyright notice appear in all copies and that both that copyright notice
|
||||||
|
and this permission notice appear in supporting documentation. William E. Kempf
|
||||||
|
makes no representations about the suitability of this software for any purpose.
|
||||||
|
It is provided "as is" without express or implied warranty.</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
194
doc/lock_concept.html
Normal file
194
doc/lock_concept.html
Normal file
@@ -0,0 +1,194 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||||
|
<link rel="stylesheet" type="text/css" href="../../../boost.css">
|
||||||
|
<title>Boost.Threads - ScopedLock Concept</title>
|
||||||
|
</head>
|
||||||
|
<body link="#0000ff" vlink="#800080">
|
||||||
|
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
|
||||||
|
"header">
|
||||||
|
<tr>
|
||||||
|
<td valign="top" width="300">
|
||||||
|
<h3><a href="../../../index.htm"><img height="86" width="277" alt="C++ Boost" src="../../../c++boost.gif" border="0"></a></h3>
|
||||||
|
</td>
|
||||||
|
<td valign="top">
|
||||||
|
<h1 align="center">Boost.Threads</h1>
|
||||||
|
<h2 align="center">ScopedLock Concept</h2>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<hr>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="#introduction">Introduction</a></dt>
|
||||||
|
<dt><a href="#concept-requirements">Concept Requirements</a></dt>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="#Lock-concept">Lock Concept</a></dt>
|
||||||
|
<dt><a href="#ScopedLock-concept">ScopedLock Concept</a></dt>
|
||||||
|
<dt><a href="#ScopedTryLock-concept">ScopedTryLock Concept</a></dt>
|
||||||
|
<dt><a href="#ScopedTimedLock-concept">ScopedTimedLock Concept</a></dt>
|
||||||
|
</dl>
|
||||||
|
</dl>
|
||||||
|
<h2><a name="introduction"></a>Introduction</h2>
|
||||||
|
<p>A lock object provides a safe means for locking and unlocking a mutex object
|
||||||
|
(an object whose type is a model of <a href="mutex_concept.html">Mutex</a> or
|
||||||
|
one of its refinements). In other words they are an implementation of the <i>Scoped
|
||||||
|
Locking</i> <a href="bibliography.html#Schmidt-00">[Schmidt 00]</a> pattern.
|
||||||
|
The <a href="#ScopedLock-concept">ScopedLock</a> concept, with <a href="#ScopedTryLock-concept">ScopedTryLock</a>
|
||||||
|
and <a href="#ScopedTimedLock-concept">ScopedTimedLock</a> refinements, formalize
|
||||||
|
the requirements.</p>
|
||||||
|
<p>Lock objects are constructed with a reference to a mutex object and typically
|
||||||
|
acquire ownership of the mutex object by setting its state to locked. They also
|
||||||
|
ensure ownership is relinquished in the destructor. Lock objects also expose
|
||||||
|
functions to query the lock status and to manually lock and unlock the mutex
|
||||||
|
object.</p>
|
||||||
|
<p>Lock objects are meant to be short lived, expected to be used at block scope
|
||||||
|
only. The lock objects are not <a href="definitions.html#definition-thread-safe">thread-safe</a>.
|
||||||
|
Lock objects must maintain state to indicate whether or not they've been
|
||||||
|
locked and this state is not protected by any synchronization concepts. For
|
||||||
|
this reason a lock object should never be shared between multiple threads.</p>
|
||||||
|
<h2><a name="concept-requirements"></a>Concept Requirements</h2>
|
||||||
|
<h3><a name="Lock-concept"></a>Lock Concept</h3>
|
||||||
|
<p>For a Lock type <code>L</code> and an object <code>lk</code> and const object
|
||||||
|
<code>clk</code> of that type, the following expressions must be well-formed
|
||||||
|
and have the indicated effects.</p>
|
||||||
|
<table summary="Lock expressions" border="1" cellpadding="5">
|
||||||
|
<tr>
|
||||||
|
<td><b>Expression</b></td>
|
||||||
|
<td><b>Effects</b></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td valign="top"><code>(&lk)->~L();</code></td>
|
||||||
|
<td><code>if (locked()) unlock();</code></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td valign="top"><code>(&clk)->operator const void*()</code></td>
|
||||||
|
<td>Returns type void*, non-zero if if the associated mutex object has been
|
||||||
|
locked by <code>clk</code>, otherwise 0.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td valign="top"><code>clk.locked()</code></td>
|
||||||
|
<td>Returns a <code>bool</code>, <code>(&clk)->operator const void*()
|
||||||
|
!= 0</code></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td valign="top"><code>lk.lock()</code></td>
|
||||||
|
<td>Throws <code>lock_error</code> if <code>locked()</code>. If the associated
|
||||||
|
mutex object is already locked by some other thread, places the current
|
||||||
|
thread in the <a href="definitions.html#State">Blocked</a> state until the
|
||||||
|
associated mutex is unlocked, after which the current thread is placed in
|
||||||
|
the <a href="definitions.html#State"> Ready</a> state, eventually to be
|
||||||
|
returned to the <a href="definitions.html#State">Running</a> state. If the
|
||||||
|
associated mutex object is already locked by the same thread the behavior
|
||||||
|
is dependent on the <a href="mutex_concept.html#locking-strategies">locking
|
||||||
|
strategy</a> of the associated mutex object.<br>
|
||||||
|
Postcondition: <code>locked() == true</code></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td valign="top"><code>lk.unlock()</code></td>
|
||||||
|
<td>If <code>!locked()</code>, throws <code>lock_error</code>, otherwise unlocks
|
||||||
|
the associated mutex.<br>
|
||||||
|
Postcondition: <code>!locked()</code></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<h3><a name="ScopedLock-concept"></a>ScopedLock Concept</h3>
|
||||||
|
<p>A ScopedLock is a refinement of <a href="#Lock">Lock</a>. For a ScopedLock
|
||||||
|
type <code>L</code> and an object <code>lk</code> of that type, and an object
|
||||||
|
<code>m</code> of a type meeting the <a href="mutex_concept.html#Mutex-concept">Mutex</a>
|
||||||
|
requirements, and an object <code>b</code> of type <code>bool</code>, the following
|
||||||
|
expressions must be well-formed and have the indicated effects.</p>
|
||||||
|
<table summary="ScopedLock expressions" border="1" cellpadding="5">
|
||||||
|
<tr>
|
||||||
|
<td><b>Expression</b></td>
|
||||||
|
<td><b>Effects</b></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td valign="top"><code>L lk(m);</code></td>
|
||||||
|
<td>Constructs an object <code>lk</code>, and associates mutex object <code>m</code>
|
||||||
|
with it, then calls <code>lock()</code></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td valign="top"><code>L lk(m,b);</code></td>
|
||||||
|
<td>Constructs an object <code>lk</code>, and associates mutex object <code>m</code>
|
||||||
|
with it, then if <code>b</code>, calls <code>lock()</code></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<h3><a name="ScopedTryLock-concept"></a>ScopedTryLock Concept</h3>
|
||||||
|
<p>A ScopedTryLock is a refinement of <a href="#Lock-concept">Lock</a>. For a
|
||||||
|
ScopedTryLock type <code>L</code> and an object <code>lk</code> of that type,
|
||||||
|
and an object <code>m</code> of a type meeting the <a href="mutex_concept.html#TryMutex-concept">TryMutex</a>
|
||||||
|
requirements, and an object <code>b</code> of type <code>bool</code>, the following
|
||||||
|
expressions must be well-formed and have the indicated effects.</p>
|
||||||
|
<table summary="ScopedTryLock expressions" border="1" cellpadding="5">
|
||||||
|
<tr>
|
||||||
|
<td><b>Expression</b></td>
|
||||||
|
<td><b>Effects</b></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td valign="top"><code>L lk(m);</code></td>
|
||||||
|
<td>Constructs an object <code>lk</code>, and associates mutex object <code>m</code>
|
||||||
|
with it, then calls <code>try_lock()</code></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td valign="top"><code>L lk(m,b);</code></td>
|
||||||
|
<td>Constructs an object <code>lk</code>, and associates mutex object <code>m</code>
|
||||||
|
with it, then if <code>b</code>, calls <code> lock()</code></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td valign="top"><code>lk.try_lock()</code></td>
|
||||||
|
<td>If locked(), throws <code>lock_error</code>. Makes a non-blocking attempt
|
||||||
|
to lock the associated mutex object, returning <code>true</code> if the
|
||||||
|
lock attempt is successful, otherwise <code>false</code>. If the associated
|
||||||
|
mutex object is already locked by the same thread the behavior is dependent
|
||||||
|
on the <a href="mutex_concept.html#locking-strategies">locking strategy</a>
|
||||||
|
of the associated mutex object.</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<h3><a name="ScopedTimedLock-concept"></a>ScopedTimedLock Concept</h3>
|
||||||
|
<p>A ScopedTimedLock is a refinement of <a href="#Lock">Lock</a>. For a ScopedTimedLock
|
||||||
|
type <code>L</code> and an object <code>lk</code> of that type, and an object
|
||||||
|
<code>m</code> of a type meeting the <a href="mutex_concept.html#TimedMutex">TimedMutex</a>
|
||||||
|
requirements, and an object <code>b</code> of type <code>bool</code>, and an
|
||||||
|
object <code>t</code> of type <code><a href="xtime.html"> xtime</a></code>,
|
||||||
|
the following expressions must be well-formed and have the indicated effects.</p>
|
||||||
|
<table summary="ScopedTimedLock expressions" border="1" cellpadding=
|
||||||
|
"5">
|
||||||
|
<tr>
|
||||||
|
<td><b>Expression</b></td>
|
||||||
|
<td><b>Effects</b></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td valign="top"><code>L lk(m,t);</code></td>
|
||||||
|
<td>Constructs an object <code>lk</code>, and associates mutex object <code>m</code>
|
||||||
|
with it, then calls <code> timed_lock(t)</code></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td valign="top"><code>L lk(m,b);</code></td>
|
||||||
|
<td>Constructs an object <code>lk</code>, and associates mutex object <code>m</code>
|
||||||
|
with it, then if <code>b</code>, calls <code> lock()</code></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td valign="top"><code>lk.timed_lock(t)</code></td>
|
||||||
|
<td>If locked(), throws lock_error. Makes a blocking attempt to lock the associated
|
||||||
|
mutex object, and returns <code>true</code> if successful within the specified
|
||||||
|
time <code>t</code>, otherwise <code>false</code>. If the associated mutex
|
||||||
|
object is already locked by the same thread the behavior is dependent on
|
||||||
|
the <a href="mutex_concept.html#locking-strategies">locking strategy</a>
|
||||||
|
of the associated mutex object.</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<hr>
|
||||||
|
<p>Revised
|
||||||
|
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
||||||
|
05 November, 2001
|
||||||
|
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
|
||||||
|
</p>
|
||||||
|
<p><i>© Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
|
||||||
|
All Rights Reserved.</i></p>
|
||||||
|
<p>Permission to use, copy, modify, distribute and sell this software and its
|
||||||
|
documentation for any purpose is hereby granted without fee, provided that the
|
||||||
|
above copyright notice appear in all copies and that both that copyright notice
|
||||||
|
and this permission notice appear in supporting documentation. William E. Kempf
|
||||||
|
makes no representations about the suitability of this software for any purpose.
|
||||||
|
It is provided "as is" without express or implied warranty.</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
288
doc/mutex.html
Normal file
288
doc/mutex.html
Normal file
@@ -0,0 +1,288 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||||
|
<link rel="stylesheet" type="text/css" href="../../../boost.css">
|
||||||
|
<title>Boost.Threads - Header <boost/thread/mutex.hpp></title>
|
||||||
|
</head>
|
||||||
|
<body link="#0000ff" vlink="#800080">
|
||||||
|
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
|
||||||
|
"header">
|
||||||
|
<tr>
|
||||||
|
<td valign="top" width="300">
|
||||||
|
<h3><a href="../../../index.htm"><img height="86" width="277" alt="C++ Boost" src="../../../c++boost.gif" border="0"></a></h3>
|
||||||
|
</td>
|
||||||
|
<td valign="top">
|
||||||
|
<h1 align="center">Boost.Threads</h1>
|
||||||
|
<h2 align="center">Header <<a href="../../../boost/thread/mutex.hpp">boost/thread/mutex.hpp</a>></h2>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<hr>
|
||||||
|
<h2>Contents</h2>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="#introduction">Introduction</a></dt>
|
||||||
|
<dt><a href="#classes">Classes</a></dt>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="#class-mutex">Class <code>mutex</code></a></dt>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="#class-mutex-synopsis">Class <code>mutex</code> synopsis</a></dt>
|
||||||
|
<dt><a href="#class-mutex-ctors">Class <code>mutex</code> constructors and
|
||||||
|
destructor</a></dt>
|
||||||
|
</dl>
|
||||||
|
</dl>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="#class-try_mutex">Class <code>try_mutex</code></a></dt>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="#class-try_mutex-synopsis">Class <code>try_mutex</code> synopsis</a></dt>
|
||||||
|
<dt><a href="#class-try_mutex-ctors">Class <code>try_mutex</code> constructors
|
||||||
|
and destructor</a></dt>
|
||||||
|
</dl>
|
||||||
|
</dl>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="#class-timed_mutex">Class <code>timed_mutex</code></a></dt>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="#class-timed_mutex-synopsis">Class <code>timed_mutex</code>
|
||||||
|
synopsis</a></dt>
|
||||||
|
<dt><a href="#class-timed_mutex-ctors">Class <code>timed_mutex</code> constructors
|
||||||
|
and destructor</a></dt>
|
||||||
|
</dl>
|
||||||
|
</dl>
|
||||||
|
<dt><a href="#examples">Example(s)</a></dt>
|
||||||
|
</dl>
|
||||||
|
<hr>
|
||||||
|
<h2><a name="introduction"></a>Introduction</h2>
|
||||||
|
<p>Include the header <<a href="../../../boost/thread/mutex.hpp">boost/thread/mutex.hpp</a>>
|
||||||
|
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=
|
||||||
|
"#timed_mutex Synopsis">timed_mutex</a></code> classes.</p>
|
||||||
|
<p>The <code><a href="#mutex Synopsis">mutex</a></code>, <code><a href=
|
||||||
|
"#try_mutex Synopsis">try_mutex</a></code> and <code><a href=
|
||||||
|
"#timed_mutex Synopsis">timed_mutex</a></code> classes are models of <a href="mutex_concept.html#Mutex-concept">Mutex</a>,
|
||||||
|
<a href="mutex_concept.html#TryMutex-concept">TryMutex</a>, and <a href="mutex_concept.html#TimedMutex-concept">TimedMutex</a>
|
||||||
|
respectively. These types should be used to non-recursively synchronize access
|
||||||
|
to shared resources. For recursive locking mechanics, see the <a href="recursive_mutex.html">recursive
|
||||||
|
mutexes</a> supplied by <b>Boost.Threads</b>.</p>
|
||||||
|
<p>Each class supplies one or more typedefs for lock types which model matching
|
||||||
|
lock concepts. For the best possible performance you should use the mutex class
|
||||||
|
that supports the minimum set of lock types that you need.</p>
|
||||||
|
<table summary="lock types" border="1" cellpadding="5">
|
||||||
|
<tr>
|
||||||
|
<td><b>Mutex Class</b></td>
|
||||||
|
<td><b>Lock name</b></td>
|
||||||
|
<td><b>Lock Concept</b></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td valign="top"><a href="#mutex Synopsis"><code> mutex</code></a></td>
|
||||||
|
<td valign="middle"><code>scoped_lock</code></td>
|
||||||
|
<td valign="middle"><a href="lock_concept.html#ScopedLock"> ScopedLock</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td valign="top"><code><a href="#try_mutex Synopsis"> try_mutex</a></code>
|
||||||
|
</td>
|
||||||
|
<td valign="middle"><code>scoped_lock<br>
|
||||||
|
scoped_try_lock</code></td>
|
||||||
|
<td valign="middle"><a href="lock_concept.html#ScopedLock"> ScopedLock</a><br>
|
||||||
|
<a href="lock_concept.html#ScopedTryLock"> ScopedTryLock</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td valign="top"><code><a href="#timed_mutex Synopsis"> timed_mutex</a></code>
|
||||||
|
</td>
|
||||||
|
<td valign="middle"><code>scoped_lock<br>
|
||||||
|
scoped_try_lock<br>
|
||||||
|
scoped_timed_lock</code></td>
|
||||||
|
<td valign="middle"><a href="lock_concept.html#ScopedLock"> ScopedLock</a><br>
|
||||||
|
<a href="lock_concept.html#ScopedTryLock"> ScopedTryLock</a><br>
|
||||||
|
<a href="lock_concept.html#ScopedTimedLock"> ScopedTimedLock</a></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<p>The <code>mutex</code>, <code>try_mutex</code> and <code>timed_mutex</code>
|
||||||
|
classes use an <code>Unspecified</code> <a href="mutex_concept.html#LockingStrategies">locking
|
||||||
|
strategy</a>, so attempts to recursively lock them or attempts to unlock them
|
||||||
|
by threads that don't own a lock on them result in <b>undefined behavior</b>.
|
||||||
|
This strategy allows implementations to be as efficient as possible on any given
|
||||||
|
platform. It is, however, recommended that implementations include debugging
|
||||||
|
support to detect misuse when <code>NDEBUG</code> is not defined.</p>
|
||||||
|
<p>Like all the <b>Boost.Threads</b> <a href="mutex_concept.html">mutex models</a>,
|
||||||
|
the <code>mutex</code>, <code>try_mutex</code> and <code> timed_mutex</code>
|
||||||
|
leave the <a href="mutex_concept.html#SchedulingPolicies">scheduling policy</a>
|
||||||
|
as <code> Unspecified</code>. Programmers should make no assumptions about the
|
||||||
|
order in which waiting threads acquire a lock.</p>
|
||||||
|
<h2><a name="classes"></a>Classes</h2>
|
||||||
|
<h3><a name="class-mutex"></a>Class <code>mutex</code></h3>
|
||||||
|
<p>The <code>mutex</code> class is a model of <a href="mutex_concept.html#Mutex-concept">Mutex</a>
|
||||||
|
and <a href="overview.html#non-copyable">NonCopyable</a>, and provides no additional
|
||||||
|
facilities beyond the requirements of these concepts.</p>
|
||||||
|
<h4><a name="class-mutex-synopsis"></a>Class <code>mutex</code> synopsis</h4>
|
||||||
|
<pre>
|
||||||
|
namespace boost
|
||||||
|
{
|
||||||
|
class mutex : private <a href="../../utility/utility.htm">boost::noncopyable</a> // Exposition only.
|
||||||
|
// Class mutex meets the <a href="overview.html#non-copyable">NonCopyable</a> requirement.
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef <i>[implementation defined; see <a href="#Introduction">Introduction</a>]</i> scoped_lock;
|
||||||
|
|
||||||
|
mutex();
|
||||||
|
~mutex();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
</pre>
|
||||||
|
<h4><a name="class-mutex-ctors"></a>Class <code>mutex</code> constructors and
|
||||||
|
destructor</h4>
|
||||||
|
<pre>
|
||||||
|
mutex();
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<dt><b>Postconditions:</b> <code>*this</code> is in an unlocked state.</dt>
|
||||||
|
</dl>
|
||||||
|
<pre>
|
||||||
|
~mutex();
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<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
|
||||||
|
resulting in undefined behavior such as a program crash.</dt>
|
||||||
|
</dl>
|
||||||
|
<h3><a name="class-try_mutex"></a>Class <code>try_mutex</code></h3>
|
||||||
|
<p>The <code>try_mutex</code> class is a model of <a href="mutex_concept.html#TryMutex-concept">TryMutex</a>
|
||||||
|
and <a href="overview.html#non-copyable">NonCopyable</a>, and provides no additional
|
||||||
|
facilities beyond the requirements of these concepts.</p>
|
||||||
|
<h4><a name="class-try_mutex-synopsis"></a>Class <code>try_mutex</code> synopsis</h4>
|
||||||
|
<pre>
|
||||||
|
namespace boost
|
||||||
|
{
|
||||||
|
class try_mutex : private <a href="../../utility/utility.htm">boost::noncopyable</a> // Exposition only.
|
||||||
|
// Class try_mutex meets the <a href="overview.html#non-copyable">NonCopyable</a> requirement.
|
||||||
|
{
|
||||||
|
Public:
|
||||||
|
typedef <i>[implementation defined; see <a href="#Introduction">Introduction</a>]</i> scoped_lock;
|
||||||
|
typedef <i>[implementation defined; see <a href="#Introduction">Introduction</a>]</i> scoped_try_lock;
|
||||||
|
|
||||||
|
try_mutex();
|
||||||
|
~try_mutex();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
</pre>
|
||||||
|
<h4><a name="class-try_mutex-ctors"></a>Class <code>try_mutex</code> constructors
|
||||||
|
and destructor</h4>
|
||||||
|
<pre>
|
||||||
|
try_mutex();
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<dt><b>Postconditions:</b> <code>*this</code> is in an unlocked state.</dt>
|
||||||
|
</dl>
|
||||||
|
<pre>
|
||||||
|
~try_mutex();
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<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
|
||||||
|
resulting in undefined behavior such as a program crash.</dt>
|
||||||
|
</dl>
|
||||||
|
<h3><a name="class-timed_mutex"></a>Class <code>timed_mutex</code></h3>
|
||||||
|
<p>The <code>timed_mutex</code> class is a model of <a href="mutex_concept.html#TimedMutex-concept">TimedMutex</a>
|
||||||
|
and <a href="overview.html#non-copyable">NonCopyable</a>, and provides no additional
|
||||||
|
facilities beyond the requirements of these concepts.</p>
|
||||||
|
<h4><a name="class-timed_mutex-synopsis"></a>Class <code>timed_mutex</code> synopsis</h4>
|
||||||
|
<pre>
|
||||||
|
namespace boost
|
||||||
|
{
|
||||||
|
class timed_mutex : private <a href="../../utility/utility.htm">boost::noncopyable</a> // Exposition only.
|
||||||
|
// Class timed_mutex meets the <a href="overview.html#non-copyable">NonCopyable</a> requirement.
|
||||||
|
{
|
||||||
|
Public:
|
||||||
|
typedef <i>[implementation defined; see <a href="#Introduction">Introduction</a>]</i> scoped_lock;
|
||||||
|
typedef <i>[implementation defined; see <a href="#Introduction">Introduction</a>]</i> scoped_try_lock;
|
||||||
|
typedef <i>[implementation defined; see <a href="#Introduction">Introduction</a>]</i> scoped_timed_lock;
|
||||||
|
|
||||||
|
timed_mutex();
|
||||||
|
~timed_mutex();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
</pre>
|
||||||
|
<h4><a name="class-timed_mutex-ctors"></a>Class <code>timed_mutex</code> constructors
|
||||||
|
and destructor</h4>
|
||||||
|
<pre>
|
||||||
|
timed_mutex();
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<dt><b>Postconditions:</b> <code>*this</code> is in an unlocked state.</dt>
|
||||||
|
</dl>
|
||||||
|
<pre>
|
||||||
|
~timed_mutex();
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<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
|
||||||
|
resulting in undefined behavior such as a program crash.</dt>
|
||||||
|
</dl>
|
||||||
|
<h2><a name="examples"></a>Example(s)</h2>
|
||||||
|
<pre>
|
||||||
|
#include <a href=
|
||||||
|
"../../../boost/thread/mutex.hpp"><boost/thread/mutex.hpp></a>
|
||||||
|
#include <a href=
|
||||||
|
"../../../boost/thread/thread.hpp"><boost/thread/thread.hpp></a>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
boost::mutex io_mutex; // The iostreams are not guaranteed to be <a href=
|
||||||
|
"definitions.html#Thread-safe">thread-safe</a>!
|
||||||
|
|
||||||
|
class counter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
counter() : count(0) { }
|
||||||
|
|
||||||
|
int increment() {
|
||||||
|
boost::mutex::scoped_lock scoped_lock(mutex);
|
||||||
|
return ++count;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
boost::mutex mutex;
|
||||||
|
int count;
|
||||||
|
};
|
||||||
|
|
||||||
|
counter c;
|
||||||
|
|
||||||
|
void change_count()
|
||||||
|
{
|
||||||
|
int i = c.increment();
|
||||||
|
boost::mutex::scoped_lock scoped_lock(io_mutex);
|
||||||
|
std::cout << "count == " << i << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int, char*[])
|
||||||
|
{
|
||||||
|
const int num_threads = 4;
|
||||||
|
boost::thread_group thrds;
|
||||||
|
for (int i=0; i < num_threads; ++i)
|
||||||
|
thrds.create_thread(&change_count);
|
||||||
|
|
||||||
|
thrds.join_all();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
<p>The output is:</p>
|
||||||
|
<pre>
|
||||||
|
count == 1
|
||||||
|
count == 2
|
||||||
|
count == 3
|
||||||
|
count == 4
|
||||||
|
</pre>
|
||||||
|
<hr>
|
||||||
|
<p>Revised
|
||||||
|
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
||||||
|
05 November, 2001
|
||||||
|
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
|
||||||
|
</p>
|
||||||
|
<p><i>© Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
|
||||||
|
All Rights Reserved.</i></p>
|
||||||
|
<p>Permission to use, copy, modify, distribute and sell this software and its
|
||||||
|
documentation for any purpose is hereby granted without fee, provided that the
|
||||||
|
above copyright notice appear in all copies and that both that copyright notice
|
||||||
|
and this permission notice appear in supporting documentation. William E. Kempf
|
||||||
|
makes no representations about the suitability of this software for any purpose.
|
||||||
|
It is provided "as is" without express or implied warranty.</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
239
doc/mutex_concept.html
Normal file
239
doc/mutex_concept.html
Normal file
@@ -0,0 +1,239 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||||
|
<link rel="stylesheet" type="text/css" href="../../../boost.css">
|
||||||
|
<title>Boost.Threads - Mutex Concept</title>
|
||||||
|
</head>
|
||||||
|
<body link="#0000ff" vlink="#800080">
|
||||||
|
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
|
||||||
|
"header">
|
||||||
|
<tr>
|
||||||
|
<td valign="top" width="300"> <a href="../../../index.htm"><img height="86" width="277" alt="C++ Boost" src="../../../c++boost.gif" border="0"></a>
|
||||||
|
</td>
|
||||||
|
<td valign="top">
|
||||||
|
<h1 align="center">Boost.Threads</h1>
|
||||||
|
<h2 align="center">Mutex Concept</h2>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<hr>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="#introduction">Introduction</a></dt>
|
||||||
|
<dt><a href="#locking-strategies">Locking Strategies</a></dt>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="#locking-strategy-recursive">Recursive</a></dt>
|
||||||
|
<dt><a href="#locking-strategy-checked">Checked</a></dt>
|
||||||
|
<dt><a href="#locking-strategy-unchecked">Unchecked</a></dt>
|
||||||
|
<dt><a href="#locking-strategy-unspecified">Unspecified</a></dt>
|
||||||
|
</dl>
|
||||||
|
<dt><a href="#scheduling-policies">Scheduling Policies</a></dt>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="#scheduling-policy-FIFO">FIFO</a></dt>
|
||||||
|
<dt><a href="#scheduling-policy-priority-driven">Priority Driven</a></dt>
|
||||||
|
<dt><a href="#scheduling-policy-unspecified">Unspecified</a></dt>
|
||||||
|
</dl>
|
||||||
|
<dt><a href="#concept-requirements">Concept Requirements</a></dt>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="#Mutex-concept">Mutex Concept</a></dt>
|
||||||
|
<dt><a href="#TryMutex-concept">TryMutex Concept</a></dt>
|
||||||
|
<dt><a href="#TimedMutex-concept">TimedMutex Concept</a></dt>
|
||||||
|
</dl>
|
||||||
|
<dt><a href="#models">Models</a></dt>
|
||||||
|
</dl>
|
||||||
|
<h2><a name="introduction"></a>Introduction</h2>
|
||||||
|
<p>A mutex (short for mutual-exclusion) object is used to serializes access to
|
||||||
|
a resource shared between multiple threads. The <a href="#Mutex">Mutex</a> concept,
|
||||||
|
with <a href="#TryMutex">TryMutex</a> and <a href="#TimedMutex">TimedMutex</a>
|
||||||
|
refinements, formalize the requirements. A model that implements Mutex and its
|
||||||
|
refinements has two states: <b>locked</b> and <b>unlocked</b>. Before using
|
||||||
|
a shared resource, a thread locks a <b>Boost.Threads</b> mutex object (an object
|
||||||
|
whose type is a model of <a href="#Mutex-concept">Mutex</a> or one of it's
|
||||||
|
refinements), insuring <a href="definitions.html#thread-safe">thread-safe</a>
|
||||||
|
access to the shared resource. When use of the shared resource is complete,
|
||||||
|
the thread unlocks the mutex object, allowing another thread to acquire the
|
||||||
|
lock and use the shared resource.</p>
|
||||||
|
<p>Traditional C thread APIs, like POSIX threads or the Windows thread APIs, expose
|
||||||
|
functions to lock and unlock a mutex object. This is dangerous since it's
|
||||||
|
easy to forget to unlock a locked mutex. When the flow of control is complex,
|
||||||
|
with multiple return points, the likelihood of forgetting to unlock a mutex
|
||||||
|
object would become even greater. When exceptions are thrown, it becomes nearly
|
||||||
|
impossible to ensure that the mutex object is unlocked properly when using these
|
||||||
|
traditional API's. The result is <a href="definitions.html#deadlock">deadlock</a>.</p>
|
||||||
|
<p>Many C++ threading libraries use a pattern known as <i>Scoped Locking</i> <a href="bibliography.html#Schmidt-00">[Schmidt
|
||||||
|
00]</a> to free the programmer from the need to explicitly lock and unlock mutex
|
||||||
|
objects. With this pattern, a <a href="lock_concept.html">Lock</a> concept is
|
||||||
|
employed where the lock object's constructor locks the associated mutex
|
||||||
|
object and the destructor automatically does the unlocking. The <b>Boost.Threads</b>
|
||||||
|
library takes this pattern to the extreme in that Lock concepts are the only
|
||||||
|
way to lock and unlock a mutex object: lock and unlock functions are not exposed
|
||||||
|
by any <b>Boost.Threads</b> mutex objects. This helps to ensure safe usage patterns,
|
||||||
|
especially when code throws exceptions.</p>
|
||||||
|
<h2><a name="locking-strategies"></a>Locking Strategies</h2>
|
||||||
|
<p>Every mutex object follows one of several locking strategies. These strategies
|
||||||
|
define the semantics for the locking operation when the calling thread already
|
||||||
|
owns a lock on the mutex object.</p>
|
||||||
|
<h3><a name="locking-strategy-recursive"></a>Recursive</h3>
|
||||||
|
<p>With a recursive locking strategy when a thread attempts to acquire a lock
|
||||||
|
on the mutex object for which it already owns a lock, the operation is successful.
|
||||||
|
Note the distinction between a thread, which may have multiple locks outstanding
|
||||||
|
on a recursive mutex object, and a lock object, which even for a recursive mutex
|
||||||
|
object cannot have any of its lock functions called multiple times without first
|
||||||
|
calling unlock.</p>
|
||||||
|
<p>Internally a lock count is maintained and the owning thread must unlock the
|
||||||
|
mutex model the same number of times that it's locked it before the mutex
|
||||||
|
object's state returns to unlocked. Since mutex objects in <b>Boost.Threads</b>
|
||||||
|
expose locking functionality only through lock concepts, a thread will always
|
||||||
|
unlock a mutex object the same number of times that it locked it. This helps
|
||||||
|
to eliminate a whole set of errors typically found in traditional C style thread
|
||||||
|
APIs.</p>
|
||||||
|
<p>Classes <a href="recursive_mutex.html#class-recursive_mutex">recursive_mutex</a>,
|
||||||
|
<a href="recursive_mutex.html#class-recursive_try_mutex">recursive_try_mutex</a>
|
||||||
|
and <a href="recursive_mutex.html#class-recursive_timed_mutex">recursive_timed_mutex</a>
|
||||||
|
use this locking strategy.</p>
|
||||||
|
<h3><a name="locking-strategy-checked"></a>Checked</h3>
|
||||||
|
<p>With a checked locking strategy when a thread attempts to acquire a lock on
|
||||||
|
the mutex object for which the thread already owns a lock, the operation will
|
||||||
|
fail with some sort of error indication. Further, attempts by a thread to unlock
|
||||||
|
a mutex object that was not locked by the thread will also return some sort
|
||||||
|
of error indication. In <b>Boost.Threads</b>, an exception of type <a href="exceptions.html#class-lock_error">
|
||||||
|
lock_error</a> would be thrown in these cases.</p>
|
||||||
|
<p><b>Boost.Threads</b> does not currently provide any mutex objects that use
|
||||||
|
this strategy.</p>
|
||||||
|
<h3><a name="locking-strategy-unchecked"></a>Unchecked</h3>
|
||||||
|
<p>With an unchecked locking strategy when a thread attempts to acquire a lock
|
||||||
|
on a mutex object for which the thread already owns a lock the operation will
|
||||||
|
<a href="definitions.html#definition-deadlock">deadlock</a>. In general this
|
||||||
|
locking strategy is less safe than a checked or recursive strategy, but it's
|
||||||
|
also a faster strategy and so is employed by many libraries.</p>
|
||||||
|
<p><b>Boost.Threads</b> does not currently provide any mutex objects that use
|
||||||
|
this strategy.</p>
|
||||||
|
<h3><a name="locking-strategy-unspecified"></a>Unspecified</h3>
|
||||||
|
<p>With an unspecified locking strategy, when a thread attempts to acquire a lock
|
||||||
|
on a mutex object for which the thread already owns a lock the operation results
|
||||||
|
in <b>undefined behavior</b>.</p>
|
||||||
|
<p>In general a mutex object with an unspecified locking strategy is unsafe, and
|
||||||
|
it requires programmer discipline to use the mutex object properly. However,
|
||||||
|
this strategy allows an implementation to be as fast as possible with no restrictions
|
||||||
|
on its implementation. This is especially true for portable implementations
|
||||||
|
that wrap the native threading support of a platform. For this reason, the classes
|
||||||
|
<a href="mutex.html#class-mutex">mutex</a>, <a href="mutex.html#class-try_mutex">try_mutex</a>
|
||||||
|
and <a href="mutex.html#class-timed_mutex">timed_mutex</a> use this locking
|
||||||
|
strategy despite the lack of safety.</p>
|
||||||
|
<h2><a name="scheduling-policies"></a>Scheduling Policies</h2>
|
||||||
|
<p>Every mutex object follows one of several scheduling policies. These policies
|
||||||
|
define the semantics when the mutex object is unlocked and there is more than
|
||||||
|
one thread waiting to acquire a lock. In other words, the policy defines which
|
||||||
|
waiting thread shall acquire the lock.</p>
|
||||||
|
<h3><a name="scheduling-policy-FIFO"></a>FIFO</h3>
|
||||||
|
<p>With a FIFO scheduling policy, threads waiting for the lock will acquire it
|
||||||
|
in a first come first serve order (or First In First Out). This can help prevent
|
||||||
|
a high priority thread from starving lower priority threads that are also waiting
|
||||||
|
on the mutex object's lock.</p>
|
||||||
|
<h3><a name="scheduling-policy-priority-driven"></a>Priority Driven</h3>
|
||||||
|
<p>With a Priority Driven scheduling policy, the thread with the highest priority
|
||||||
|
acquires the lock. Note that this means that low-priority threads may never
|
||||||
|
acquire the lock if the mutex object has high contention and there is always
|
||||||
|
at least one high-priority thread waiting. This is known as thread starvation.
|
||||||
|
When multiple threads of the same priority are waiting on the mutex object's
|
||||||
|
lock one of the other scheduling priorities will determine which thread shall
|
||||||
|
acquire the lock.</p>
|
||||||
|
<h3><a name="scheduling-policy-unspecified"></a>Unspecified</h3>
|
||||||
|
<p>The mutex object does not specify a scheduling policy. In order to ensure portability,
|
||||||
|
all <b>Boost.Threads</b> mutex models use an unspecified scheduling policy.</p>
|
||||||
|
<h2><a name="concept-requirements"></a>Concept Requirements</h2>
|
||||||
|
<h3><a name="Mutex-concept"></a>Mutex Concept</h3>
|
||||||
|
<p>A Mutex object has two states: locked and unlocked. Mutex object state can
|
||||||
|
only be determined by an object meeting the <a href="lock_concept.html#ScopedLock">ScopedLock</a>
|
||||||
|
requirements and constructed for the Mutex object.</p>
|
||||||
|
<p>A Mutex is <a href="../../utility/utility.htm#Class noncopyable">NonCopyable</a>.</p>
|
||||||
|
<p>For a Mutex type M and an object m of that type, the following expressions
|
||||||
|
must be well-formed and have the indicated effects.</p>
|
||||||
|
<table summary="Mutex expressions" border="1" cellpadding="5">
|
||||||
|
<tr>
|
||||||
|
<td><b>Expression</b></td>
|
||||||
|
<td><b>Effects</b></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>M m;</code></td>
|
||||||
|
<td>Constructs a mutex object m. Post-condition: m is unlocked.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>(&m)->~M();</code></td>
|
||||||
|
<td>Precondition: m is unlocked. Destroys a mutex object m.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>M::scoped_lock</code></td>
|
||||||
|
<td>A model of <a href="lock_concept.html#ScopedLock">ScopedLock</a>.</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<h3><a name="TryMutex-concept"></a>TryMutex Concept</h3>
|
||||||
|
<p>A TryMutex is a refinement of <a href="#Mutex-concept">Mutex</a>. For a TryMutex
|
||||||
|
type M and an object m of that type, the following expressions must be well-formed
|
||||||
|
and have the indicated effects.</p>
|
||||||
|
<table summary="TryMutex expressions" border="1" cellpadding="5">
|
||||||
|
<tr>
|
||||||
|
<td><b>Expression</b></td>
|
||||||
|
<td><b>Effects</b></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>M::scoped_try_lock</code></td>
|
||||||
|
<td>A model of <a href="lock_concept.html#ScopedTryLock">ScopedTryLock</a>.</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<h3><a name="TimedMutex-concept"></a>TimedMutex Concept</h3>
|
||||||
|
<p>A TimedMutex is a refinement of <a href="#TryMutex-concept">TryMutex</a>. For
|
||||||
|
a TimedMutex type M and an object m of that type, the following expressions
|
||||||
|
must be well-formed and have the indicated effects.</p>
|
||||||
|
<table summary="TimedMutex expressions" border="1" cellpadding="5">
|
||||||
|
<tr>
|
||||||
|
<td><b>Expression</b></td>
|
||||||
|
<td><b>Effects</b></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>M::scoped_timed_lock</code></td>
|
||||||
|
<td>A model of <a href="lock_concept.html#ScopedTimedLock">ScopedTimedLock</a>.</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<h2><a name="models"></a>Models</h2>
|
||||||
|
<p><b>Boost.Threads</b> currently supplies six models of Mutex.</p>
|
||||||
|
<table summary="Mutex concept classes" border="1" cellpadding="5">
|
||||||
|
<tr>
|
||||||
|
<td><b>Concept</b></td>
|
||||||
|
<td><b>Refines</b></td>
|
||||||
|
<td><b>Models</b></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td valign="top"><a href="#Mutex-concept">Mutex</a></td>
|
||||||
|
<td valign="top"> </td>
|
||||||
|
<td><a href="mutex.html">mutex</a><br>
|
||||||
|
<a href="recursive_mutex.html">recursive_mutex</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td valign="top"><a href="#TryMutex-concept">TryMutex</a></td>
|
||||||
|
<td valign="top"><a href="#Mutex-concept">Mutex</a></td>
|
||||||
|
<td><a href="mutex.html">try_mutex<br>
|
||||||
|
</a> <a href="recursive_mutex.html">recursive_try_mutex</a> </td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td valign="top"><a href="#TimedMutex-concept">TimedMutex</a></td>
|
||||||
|
<td valign="top"><a href="#TryMutex-concept">TryMutex</a></td>
|
||||||
|
<td><a href="mutex.html">timed_mutex<br>
|
||||||
|
</a> <a href="recursive_mutex.html"> recursive_timed_mutex</a></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<hr>
|
||||||
|
<p>Revised
|
||||||
|
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
||||||
|
05 November, 2001
|
||||||
|
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
|
||||||
|
</p>
|
||||||
|
<p><i>© Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
|
||||||
|
All Rights Reserved.</i></p>
|
||||||
|
<p>Permission to use, copy, modify, distribute and sell this software and its
|
||||||
|
documentation for any purpose is hereby granted without fee, provided that the
|
||||||
|
above copyright notice appear in all copies and that both that copyright notice
|
||||||
|
and this permission notice appear in supporting documentation. William E. Kempf
|
||||||
|
makes no representations about the suitability of this software for any purpose.
|
||||||
|
It is provided "as is" without express or implied warranty.</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
116
doc/once.html
Normal file
116
doc/once.html
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||||
|
<link rel="stylesheet" type="text/css" href="../../../boost.css">
|
||||||
|
<title>Boost.Threads - Header <boost/thread/once.hpp></title>
|
||||||
|
</head>
|
||||||
|
<body link="#0000ff" vlink="#800080">
|
||||||
|
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
|
||||||
|
"header">
|
||||||
|
<tr>
|
||||||
|
<td valign="top" width="300">
|
||||||
|
<h3><a href="../../../index.htm"><img height="86" width="277" alt="C++ Boost" src="../../../c++boost.gif" border="0"></a></h3>
|
||||||
|
</td>
|
||||||
|
<td valign="top">
|
||||||
|
<h1 align="center">Boost.Threads</h1>
|
||||||
|
<h2 align="center">Header <<a href="../../../boost/thread/once.hpp">boost/thread/once.hpp</a>></h2>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<hr>
|
||||||
|
<h2>Contents</h2>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="#introduction">Introduction</a></dt>
|
||||||
|
<dt><a href="#macros">Macros</a></dt>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="#macro-BOOST_ONCE_INIT">BOOST_ONCE_INIT</a></dt>
|
||||||
|
</dl>
|
||||||
|
<dt><a href="#types">Types</a></dt>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="#type-once_flag">once_flag</a></dt>
|
||||||
|
</dl>
|
||||||
|
<dt><a href="#functions">Functions</a></dt>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="#function-call_once">call_once</a></dt>
|
||||||
|
</dl>
|
||||||
|
<dt><a href="#examples">Example(s)</a></dt>
|
||||||
|
</dl>
|
||||||
|
<hr>
|
||||||
|
<h2><a name="introduction"></a>Introduction</h2>
|
||||||
|
<p>Include the header <<a href="../../../boost/thread/once.hpp">boost/thread/once.hpp</a>>
|
||||||
|
to define the <code>call_once</code> function, <code>once_flag</code> type and
|
||||||
|
<code>BOOST_ONCE_INIT</code> constant.</p>
|
||||||
|
<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
|
||||||
|
once. This can be used to initialize data in a <a href="definitions.html#Thread-safe">
|
||||||
|
thread-safe</a> manner.</p>
|
||||||
|
<h2><a name="macros"></a>Macros</h2>
|
||||||
|
<pre>
|
||||||
|
<a name="macro-BOOST_ONCE_INIT"></a>#define BOOST_ONCE_INIT <i>implementation defined</i>
|
||||||
|
</pre>
|
||||||
|
<p>This is a constant value used to initialize <code>once_flag</code> instances
|
||||||
|
to indicate that the logically associated routine has not been run yet.</p>
|
||||||
|
<h2><a name="types"></a>Types</h2>
|
||||||
|
<pre>
|
||||||
|
<a name="type-once_flag"></a>typedef <i>implementation defined</i> once_flag;
|
||||||
|
</pre>
|
||||||
|
<p>This implementation defined type is used as a flag to insure a routine is called
|
||||||
|
only once. Instances of this type should be statically initialized to <code>BOOST_ONCE_INIT</code>.</p>
|
||||||
|
<h2><a name="functions"></a>Functions</h2>
|
||||||
|
<pre>
|
||||||
|
<a name="function-call_once"></a>void call_once(void (*func)(), once_flag& flag);
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<dt><b>Requires:</b> The function <code>func</code> shall not throw exceptions.</dt>
|
||||||
|
<dt><b>Effects:</b> As if (in an atomic fashion):
|
||||||
|
<pre>
|
||||||
|
if (flag == BOOST_ONCE_INIT)
|
||||||
|
func();
|
||||||
|
</pre>
|
||||||
|
</dt>
|
||||||
|
<dt><b>Postconditions:</b> <code>flag != BOOST_ONCE_INIT</code></dt>
|
||||||
|
</dl>
|
||||||
|
<h2><a name="examples"></a>Example(s)</h2>
|
||||||
|
<pre>
|
||||||
|
#include <a href="../../../boost/thread/thread.hpp"><boost/thread/thread.hpp></a>
|
||||||
|
#include <a href="../../../boost/thread/tss.hpp"><boost/thread/once.hpp></a>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
int value=0;
|
||||||
|
boost::once_flag once = BOOST_ONCE_INIT;
|
||||||
|
|
||||||
|
void init()
|
||||||
|
{
|
||||||
|
++value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void thread_proc()
|
||||||
|
{
|
||||||
|
boost::call_once(&init, once);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
boost::thread_group threads;
|
||||||
|
for (int i=0; i<5; ++i)
|
||||||
|
threads.create_thread(&thread_proc);
|
||||||
|
threads.join_all();
|
||||||
|
assert(value == 1);
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
<hr>
|
||||||
|
<p>Revised
|
||||||
|
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
||||||
|
05 November, 2001
|
||||||
|
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
|
||||||
|
</p>
|
||||||
|
<p><i>© Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
|
||||||
|
All Rights Reserved.</i></p>
|
||||||
|
<p>Permission to use, copy, modify, distribute and sell this software and its
|
||||||
|
documentation for any purpose is hereby granted without fee, provided that the
|
||||||
|
above copyright notice appear in all copies and that both that copyright notice
|
||||||
|
and this permission notice appear in supporting documentation. William E. Kempf
|
||||||
|
makes no representations about the suitability of this software for any purpose.
|
||||||
|
It is provided "as is" without express or implied warranty.</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
173
doc/overview.html
Normal file
173
doc/overview.html
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||||
|
<link rel="stylesheet" type="text/css" href="../../../boost.css">
|
||||||
|
<title>Boost.Threads - 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">Overview</h2>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<hr>
|
||||||
|
<dl class="index">
|
||||||
|
<dt><a href="#introduction">Introduction</a></dt>
|
||||||
|
<dt><a href="#dangers">Dangers</a></dt>
|
||||||
|
<dl class="index">
|
||||||
|
<dt><a href="#testing-debugging">Testing and debugging considerations</a></dt>
|
||||||
|
<dt><a href="#head-start">Getting a head start</a></dt>
|
||||||
|
</dl>
|
||||||
|
<dt><a href="#library">C++ Standard Library usage in multithreaded programs</a></dt>
|
||||||
|
<dl class="index">
|
||||||
|
<dt><a href="#runtime-libraries">Runtime libraries</a></dt>
|
||||||
|
<dt><a href="#non-thread-safe-functions">Potentially non-thread-safe functions</a></dt>
|
||||||
|
</dl>
|
||||||
|
<dt><a href="#common-requirements">Common requirements for all Boost.Threads
|
||||||
|
components</a></dt>
|
||||||
|
<dl class="index">
|
||||||
|
<dt><a href="#exceptions">Exceptions</a></dt>
|
||||||
|
<dt><a href="#non-copyable">NonCopyable requirement</a></dt>
|
||||||
|
</dl>
|
||||||
|
</dl>
|
||||||
|
<h2><a name="introduction"></a>Introduction</h2>
|
||||||
|
<p>Boost.Threads allows C++ programs to execute as multiple, asynchronous, independent,
|
||||||
|
threads-of-execution. Each thread has its own machine state including program
|
||||||
|
instruction counter and registers. Programs which execute as multiple threads
|
||||||
|
are called multithreaded programs to distinguish them from traditional single-threaded
|
||||||
|
programs. <a href="definitions.html">Definitions</a> gives a more complete description
|
||||||
|
of the multithreading execution environment.</p>
|
||||||
|
<p>Multithreading provides several advantages:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Programs which would otherwise block waiting for some external event can
|
||||||
|
continue to respond if the blocking operation is placed in a separate thread.
|
||||||
|
Multithreading is usually an absolute requirement for these programs.</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li>Well-designed multithreaded programs may execute faster than single-threaded
|
||||||
|
programs, particularly on multiprocessor hardware. Note, however, that poorly-designed
|
||||||
|
multithreaded programs are often slower that single-threaded programs.</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li>Some program designs may be easier to formulate using a multithreaded approach.
|
||||||
|
After all, the real world is asynchronous!</li>
|
||||||
|
</ul>
|
||||||
|
<h2><a name="dangers"></a>Dangers</h2>
|
||||||
|
<p>Beyond the errors which can occur in single-threaded programs, multithreaded
|
||||||
|
programs are subject to additional errors:</p>
|
||||||
|
<ul>
|
||||||
|
<li><a href="definitions.html#definition-race-condition">Race conditions</a>.</li>
|
||||||
|
<li><a href="definitions.html#definition-deadlock">Deadlock</a> (sometimes called
|
||||||
|
"deadly embrace")</li>
|
||||||
|
<li><a href="definitions.html#definition-priority-failure">Priority failures</a>
|
||||||
|
(priority inversion, infinite overtaking, starvation, etc.)</li>
|
||||||
|
</ul>
|
||||||
|
<p>Every multithreaded program must be designed carefully to avoid race conditions,
|
||||||
|
priority failures and deadlock. These aren't rare or exotic failures - they
|
||||||
|
are virtually guaranteed to occur unless multithreaded code is designed to avoid
|
||||||
|
them. Priority failures are somewhat less common, but are nonetheless serious.</p>
|
||||||
|
<p>The <a href="introduction.html">Boost.Threads design</a> attempts to minimize
|
||||||
|
these errors, but they will still occur unless the programmer proactively designs
|
||||||
|
to avoid them.</p>
|
||||||
|
<h3><a name="testing-debugging"></a>Testing and debugging considerations</h3>
|
||||||
|
<p>Multithreaded programs are non-deterministic. In other words, the same program
|
||||||
|
with the same input data may follow different execution paths each time it is
|
||||||
|
invoked. That can make testing and debugging a nightmare:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Failures are often not repeatable.</li>
|
||||||
|
<li>Probe effect causes debuggers to produce very different results from non-debug
|
||||||
|
uses.</li>
|
||||||
|
<li>Debuggers require special support to show thread state.</li>
|
||||||
|
<li>Tests on a single processor system may give no indication of serious errors
|
||||||
|
which would appear on multiprocessor systems, and visa versa. Thus test cases
|
||||||
|
should include a varying number of processors.</li>
|
||||||
|
<li>For programs which create a varying number of threads according to workload,
|
||||||
|
tests which don't span the full range of possibilities may miss serious
|
||||||
|
errors.</li>
|
||||||
|
</ul>
|
||||||
|
<h3><a name="head-start"></a>Getting a head start</h3>
|
||||||
|
<p>Although it might appear that multithreaded programs are inherently unreliable,
|
||||||
|
many reliable multithreaded programs do exist. Multithreading techniques are
|
||||||
|
known which lead to reliable programs.</p>
|
||||||
|
<p>Design patterns for reliable multithreaded programs, including the important
|
||||||
|
<i>monitor</i> pattern, are presented in <cite> Pattern-Oriented Software Architecture
|
||||||
|
Volume 2 - Patterns for Concurrent and Networked Objects</cite> [<a href=
|
||||||
|
"bibliography.html#Schmidt-00">Schmidt 00</a>]. Many important multithreading
|
||||||
|
programming considerations (independent of threading library) are discussed
|
||||||
|
in <cite>Programming with POSIX Threads</cite> [<a href="bibliography.html#Butenhof-97">Butenhof
|
||||||
|
97</a>].</p>
|
||||||
|
<p>Doing some reading before attempting multithreaded designs will give you a
|
||||||
|
head start toward reliable multithreaded programs.</p>
|
||||||
|
<h2><a name="library"></a>C++ Standard Library usage in multithreaded programs</h2>
|
||||||
|
<h3><a name="runtime-libraries"></a>Runtime libraries</h3>
|
||||||
|
<p><b>Warning:</b> Multithreaded programs such as those using <b> Boost.Threads</b>
|
||||||
|
must link to <a href="definitions.html#Thread-safe"> thread-safe</a> versions
|
||||||
|
of all runtime libraries used by the program, including the runtime library
|
||||||
|
for the C++ Standard Library. Otherwise <a href="definitions.html#Race condition">race
|
||||||
|
conditions</a> will occur when multiple threads simultaneously execute runtime
|
||||||
|
library functions for <i>new</i>, <i>delete</i>, or other language features
|
||||||
|
which imply shared state.</p>
|
||||||
|
<h3><a name="non-thread-safe-functions"></a>Potentially non-thread-safe functions</h3>
|
||||||
|
<p>Certain C++ Standard Library functions inherited from C are particular problems
|
||||||
|
because they hold internal state between calls:</p>
|
||||||
|
<ul>
|
||||||
|
<li>rand</li>
|
||||||
|
<li>strtok</li>
|
||||||
|
<li>asctime</li>
|
||||||
|
<li>ctime</li>
|
||||||
|
<li>gmtime</li>
|
||||||
|
<li>localtime</li>
|
||||||
|
</ul>
|
||||||
|
<p>It is possible to write thread-safe implementations of these by using <a href="tss.html#class-thread_specific_ptr">thread-specific
|
||||||
|
storage</a>, and several C++ compiler vendors do just that. The technique is
|
||||||
|
well-know and is explained in [<a href=
|
||||||
|
"bibliography.html#Butenhof-97">Buttenhof 97</a>].</p>
|
||||||
|
<p>But at least one vendor (HP-UX) does not provide thread-safe implementations
|
||||||
|
of the above functions in their otherwise thread-safe runtime library. Instead
|
||||||
|
they provide replacement functions with different names and arguments.</p>
|
||||||
|
<p><b>Recommendation:</b> For the most portable, yet thread-safe code, use Boost
|
||||||
|
replacements for the problem functions. See the <a href=
|
||||||
|
"../../random/index.html">Boost Random Number Library</a> and <a href=
|
||||||
|
"../../tokenizer/index.htm">Boost Tokenizer Library</a>.</p>
|
||||||
|
<h2><a name="common-gaurantees"></a>Common guarantees for all Boost.Threads components</h2>
|
||||||
|
<h3><a name="exceptions"></a>Exceptions</h3>
|
||||||
|
<p><b>Boost.Threads</b> destructors never throw exceptions. Unless otherwise specified,
|
||||||
|
other <b>Boost.Threads</b> functions that do not have an exception-specification
|
||||||
|
may throw implementation-defined exceptions.</p>
|
||||||
|
<p>In particular, <b>Boost.Threads</b> reports failure to allocate storage by
|
||||||
|
throwing an exception of type std::bad_alloc, or a class derived from std::bad_alloc,
|
||||||
|
failure to obtain thread resources other than memory by throwing an exception
|
||||||
|
of type <a href="exceptions.html#class-thread_resource_error">boost::thread_resource_error</a>,
|
||||||
|
and certain lock related failures by throwing an exception of type <a href="exceptions.html#class-lock_error">boost::lock_error</a></p>
|
||||||
|
<p><b>Rationale:</b> Follows the C++ Standard Library practice of allowing all
|
||||||
|
functions except destructors or other specified functions to throw exceptions
|
||||||
|
on errors.</p>
|
||||||
|
<h3><a name="non-copyable"></a>NonCopyable requirement</h3>
|
||||||
|
<p><b>Boost.Threads</b> classes documented as meeting the NonCopyable requirement
|
||||||
|
disallow copy construction and copy assignment. For the sake of exposition,
|
||||||
|
the synopsis of such classes show private derivation from <a href="../../utility/utility.htm">
|
||||||
|
boost::noncopyable</a>. Users should not depend on this derivation, however,
|
||||||
|
as implementations are free to meet the NonCopyable requirement in other ways.</p>
|
||||||
|
<hr>
|
||||||
|
<p>Revised
|
||||||
|
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
||||||
|
05 November, 2001
|
||||||
|
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
|
||||||
|
</p>
|
||||||
|
<p><i>© Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
|
||||||
|
All Rights Reserved.</i></p>
|
||||||
|
<p>Permission to use, copy, modify, distribute and sell this software and its
|
||||||
|
documentation for any purpose is hereby granted without fee, provided that the
|
||||||
|
above copyright notice appear in all copies and that both that copyright notice
|
||||||
|
and this permission notice appear in supporting documentation. William E. Kempf
|
||||||
|
makes no representations about the suitability of this software for any purpose.
|
||||||
|
It is provided "as is" without express or implied warranty.</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
399
doc/rationale.html
Normal file
399
doc/rationale.html
Normal file
@@ -0,0 +1,399 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||||
|
<link rel="stylesheet" type="text/css" href="../../../boost.css">
|
||||||
|
<title>Boost.Threads - Rationale</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">Rationale</h2>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<hr>
|
||||||
|
<dl class="index">
|
||||||
|
<dt><a href="#introduction">Introduction</a></dt>
|
||||||
|
<dt><a href="#library">Rationale for the Creation of <b>Boost.Threads</b></a></dt>
|
||||||
|
<dt><a href="#primitives">Rationale for the Low Level Primitives Supported in
|
||||||
|
<b>Boost.Threads</b></a></dt>
|
||||||
|
<dt><a href="#lock_objects">Rationale for the Lock Design</a></dt>
|
||||||
|
<dt><a href="#non-copyable">Rationale for NonCopyable Thread Type</a></dt>
|
||||||
|
<dt><a href="#events">Rationale for not providing <i>Event Variables</i></a></dt>
|
||||||
|
</dl>
|
||||||
|
<h2><a name="introduction"></a>Introduction</h2>
|
||||||
|
<p>This page explains the rationale behind various design decisions in the <b>Boost.Threads</b>
|
||||||
|
library. Having the rationale documented here should explain how we arrived
|
||||||
|
at the current design as well as prevent future rehashing of discussions and
|
||||||
|
thought processes that have already occurred. It can also give users a lot of
|
||||||
|
insight into the design process required for this library.</p>
|
||||||
|
<h2><a name="library"></a>Rationale for the Creation of <b>Boost.Threads</b></h2>
|
||||||
|
<p>Processes often have a degree of "potential parallelism" and it can
|
||||||
|
often be more intuitive to design systems with this in mind. Further, these
|
||||||
|
parallel processes can result in more responsive programs. The benefits for
|
||||||
|
multithreaded programming are quite well known to most modern programmers, yet
|
||||||
|
the C++ language doesn't directly support this concept.</p>
|
||||||
|
<p>Many platforms support multithreaded programming despite the fact that the
|
||||||
|
language doesn't support it. They do this through external libraries, which
|
||||||
|
are, unfortunately, platform specific. POSIX has tried to address this problem
|
||||||
|
through the standardization of a "pthread" library. However, this
|
||||||
|
is a standard only on POSIX platforms, so its portability is limited.</p>
|
||||||
|
<p>Another problem with POSIX and other platform specific thread libraries is
|
||||||
|
that they are almost universally C based libraries. This leaves several C++
|
||||||
|
specific issues unresolved, such as what happens when an exception is thrown
|
||||||
|
in a thread. Further, there are some C++ concepts, such as destructors, that
|
||||||
|
can make usage much easier than what's available in a C library.</p>
|
||||||
|
<p>What's truly needed is C++ language support for threads. However, the C++
|
||||||
|
standards committee needs existing practice or a good proposal as a starting
|
||||||
|
point for adding this to the standard.</p>
|
||||||
|
<p>The <b>Boost.Threads</b> library was developed to provide a C++ developer with
|
||||||
|
a portable interface for writing multithreaded programs on numerous platforms.
|
||||||
|
There's a hope that the library can be the basis for a more detailed proposal
|
||||||
|
for the C++ standards committee to consider for inclusion in the next C++ standard.</p>
|
||||||
|
<h2><a name="primitives"></a>Rationale for the Low Level Primitives Supported
|
||||||
|
in <b>Boost.Threads</b></h2>
|
||||||
|
<p>The <b>Boost.Threads</b> library supplies a set of low level primitives for
|
||||||
|
writing multithreaded programs, such as mutexes and condition variables. In
|
||||||
|
fact, the first release of <b>Boost.Threads</b> supports only these low level
|
||||||
|
primitives. However, computer science research has shown that use of these primitives
|
||||||
|
is difficult since it's difficult to mathematically prove that a usage pattern
|
||||||
|
is correct, meaning it doesn't result in race conditions or deadlocks. There
|
||||||
|
are several algebras (such as CSP, CCS and Join calculus) that have been developed
|
||||||
|
to help write provably correct parallel processes. In order to prove the correctness
|
||||||
|
these processes must be coded using higher level abstractions. So why does <b>Boost.Threads</b>
|
||||||
|
support the lower level concepts?</p>
|
||||||
|
<p>The reason is simple: the higher level concepts need to be implemented using
|
||||||
|
at least some of the lower level concepts. So having portable lower level concepts
|
||||||
|
makes it easier to develop the higher level concepts and will allow researchers
|
||||||
|
to experiment with various techniques.</p>
|
||||||
|
<p>Beyond this theoretical application of higher level concepts, however, the
|
||||||
|
fact remains that many multithreaded programs are written using only the lower
|
||||||
|
level concepts, so they are useful in and of themselves, even if it's hard
|
||||||
|
to prove that their usage is correct. Since many users will be familiar with
|
||||||
|
these lower level concepts but be unfamiliar with any of the higher level concepts
|
||||||
|
there's also an argument for accessibility.</p>
|
||||||
|
<h2><a name="lock_objects"></a>Rationale for the Lock Design</h2>
|
||||||
|
<p>Programmers who are used to multithreaded programming issues will quickly note
|
||||||
|
that the Boost.Thread's design for mutex lock concepts is not <a href="definitions.html#Thread-safe">thread-safe</a>
|
||||||
|
(this is clearly documented as well). At first this may seem like a serious
|
||||||
|
design flaw. Why have a multithreading primitive that's not thread-safe
|
||||||
|
itself?</p>
|
||||||
|
<p>A lock object is not a synchronization primitive. A lock object's sole
|
||||||
|
responsibility is to ensure that a mutex is both locked and unlocked in a manner
|
||||||
|
that won't result in the common error of locking a mutex and then forgetting
|
||||||
|
to unlock it. This means that instances of a lock object are only going to be
|
||||||
|
created, at least in theory, within block scope and won't be shared between
|
||||||
|
threads. Only the mutex objects will be created outside of block scope and/or
|
||||||
|
shared between threads. Though it's possible to create a lock object outside
|
||||||
|
of block scope and to share it between threads to do so would not be a typical
|
||||||
|
usage (in fact, to do so would likely be an error). Nor are there any cases
|
||||||
|
when such usage would be required.</p>
|
||||||
|
<p>Lock objects must maintain some state information. In order to allow a program
|
||||||
|
to determine if a try_lock or timed_lock was successful the lock object must
|
||||||
|
retain state indicating the success or failure of the call made in its constructor.
|
||||||
|
If a lock object were to have such state and remain thread-safe it would need
|
||||||
|
to synchronize access to the state information which would result in roughly
|
||||||
|
doubling the time of most operations. Worse, since checking the state can occur
|
||||||
|
only by a call after construction we'd have a race condition if the lock
|
||||||
|
object were shared between threads.</p>
|
||||||
|
<p>So, to avoid the overhead of synchronizing access to the state information
|
||||||
|
and to avoid the race condition the <b>Boost.Threads</b> library simply does
|
||||||
|
nothing to make lock objects thread-safe. Instead, sharing a lock object between
|
||||||
|
threads results in undefined behavior. Since the only proper usage of lock objects
|
||||||
|
is within block scope this isn't a problem, and so long as the lock object
|
||||||
|
is properly used there's no danger of any multithreading issues.</p>
|
||||||
|
<h2><a name="non-copyable"></a>Rationale for NonCopyable Thread Type</h2>
|
||||||
|
<p>Programmers who are used to C libraries for multithreaded programming are likely
|
||||||
|
to wonder why <b>Boost.Threads</b> uses a noncopyable design for <a href="thread.html">boost::thread</a>.
|
||||||
|
After all, the C thread types are copyable, and you often have a need for copying
|
||||||
|
them within user code. However, careful comparison of C designs to C++ designs
|
||||||
|
shows a flaw in this logic.</p>
|
||||||
|
<p>All C types are copyable. It is, in fact, not possible to make a noncopyable
|
||||||
|
type in C. For this reason types that represent system resources in C are often
|
||||||
|
designed to behave very similarly to a pointer to dynamic memory. There's
|
||||||
|
an API for acquiring the resource and an API for releasing the resources. For
|
||||||
|
memory we have pointers as the type and alloc/free for the acquisition and release
|
||||||
|
APIs. For files we have FILE* as the type and fopen/fclose for the acquisition
|
||||||
|
and release APIs. You can freely copy instances of the types but must manually
|
||||||
|
manage the lifetime of the actual resource through the acquisition and release
|
||||||
|
APIs.</p>
|
||||||
|
<p>C++ designs recognize that the acquisition and release APIs are error prone
|
||||||
|
and try to eliminate possible errors by acquiring the resource in the constructor
|
||||||
|
and releasing it in the destructor. The best example of such a design is the
|
||||||
|
std::iostream set of classes which can represent the same resource as the FILE*
|
||||||
|
type in C. A file is opened in the std::fstream's constructor and closed
|
||||||
|
in its destructor. However, if an iostream were copyable it could lead to a
|
||||||
|
file being closed twice, an obvious error, so the std::iostream types are noncopyable
|
||||||
|
by design. This is the same design used by boost::thread, which is a simple
|
||||||
|
and easy to understand design that's consistent with other C++ standard
|
||||||
|
types.</p>
|
||||||
|
<p>During the design of boost::thread it was pointed out that it would be possible
|
||||||
|
to allow it to be a copyable type if some form of "reference management"
|
||||||
|
were used, such as ref-counting or ref-lists, and many argued for a boost::thread_ref
|
||||||
|
design instead. The reasoning was that copying "thread" objects was
|
||||||
|
a typical need in the C libraries, and so presumably would be in the C++ libraries
|
||||||
|
as well. It was also thought that implementations could provide more efficient
|
||||||
|
reference management than wrappers (such as boost::shared_ptr) around a noncopyable
|
||||||
|
thread concept. Analysis of whether or not these arguments would hold true doesn't
|
||||||
|
appear to bear them out. To illustrate the analysis we'll first provide
|
||||||
|
pseudo-code illustrating the six typical usage patterns of a thread object.</p>
|
||||||
|
<h3>1. Simple creation of a thread.</h3>
|
||||||
|
<pre>
|
||||||
|
void foo()
|
||||||
|
{
|
||||||
|
create_thread(&bar);
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
<h3>2. Creation of a thread that's later joined.</h3>
|
||||||
|
<pre>
|
||||||
|
Void foo()
|
||||||
|
{
|
||||||
|
thread = create_thread(&bar);
|
||||||
|
join(thread);
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
<h3>3. Simple creation of several threads in a loop.</h3>
|
||||||
|
<pre>
|
||||||
|
Void foo()
|
||||||
|
{
|
||||||
|
for (int i=0; i<NUM_THREADS; ++i)
|
||||||
|
create_thread(&bar);
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
<h3>4. Creation of several threads in a loop which are later joined.</h3>
|
||||||
|
<pre>
|
||||||
|
Void foo()
|
||||||
|
{
|
||||||
|
for (int i=0; i<NUM_THREADS; ++i)
|
||||||
|
threads[i] = create_thread(&bar);
|
||||||
|
for (int i=0; i<NUM_THREADS; ++i)
|
||||||
|
threads[i].join();
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
<h3>5. Creation of a thread whose ownership is passed to another object/method.</h3>
|
||||||
|
<pre>
|
||||||
|
Void foo()
|
||||||
|
{
|
||||||
|
thread = create_thread(&bar);
|
||||||
|
manager.owns(thread);
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
<h3>6. Creation of a thread whose ownership is shared between multiple objects.</h3>
|
||||||
|
<pre>
|
||||||
|
Void foo()
|
||||||
|
{
|
||||||
|
thread = create_thread(&bar);
|
||||||
|
manager1.add(thread);
|
||||||
|
manager2.add(thread);
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
<p>Of these usage patterns there's only one that requires reference management
|
||||||
|
(number 6). Hopefully it's fairly obvious that this usage pattern simply
|
||||||
|
won't occur as often as the other usage patterns. So there really isn't
|
||||||
|
a "typical need" for a thread concept, though there is some need.</p>
|
||||||
|
<p>Since the need isn't typical we must use different criteria for deciding
|
||||||
|
on either a thread_ref or thread design. Possible criteria include ease of use
|
||||||
|
and performance. So let's analyze both of these carefully.</p>
|
||||||
|
<p>With ease of use we can look at existing experience. The standard C++ objects
|
||||||
|
that represent a system resource, such as std::iostream, are noncopyable, so
|
||||||
|
we know that C++ programmers must at least be experienced with this design.
|
||||||
|
Most C++ developers are also used to smart pointers such as boost::shared_ptr,
|
||||||
|
so we know they can at least adapt to a thread_ref concept with little effort.
|
||||||
|
So existing experience isn't going to lead us to a choice.</p>
|
||||||
|
<p>The other thing we can look at is how difficult it is to use both types for
|
||||||
|
the six usage patterns above. If we find it overly difficult to use a concept
|
||||||
|
for any of the usage patterns there would be a good argument for choosing the
|
||||||
|
other design. So we'll code all six usage patterns using both designs.</p>
|
||||||
|
<h3>1.</h3>
|
||||||
|
<pre>
|
||||||
|
void foo()
|
||||||
|
{
|
||||||
|
thread thrd(&bar);
|
||||||
|
}
|
||||||
|
|
||||||
|
void foo()
|
||||||
|
{
|
||||||
|
thread_ref thrd = create_thread(&bar);
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
<h3>2.</h3>
|
||||||
|
<pre>
|
||||||
|
void foo()
|
||||||
|
{
|
||||||
|
thread thrd(&bar);
|
||||||
|
thrd.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
void foo()
|
||||||
|
{
|
||||||
|
thread_ref thrd =
|
||||||
|
create_thread(&bar);thrd->join();
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
<h3>3.</h3>
|
||||||
|
<pre>
|
||||||
|
void foo()
|
||||||
|
{
|
||||||
|
for (int i=0; i<NUM_THREADS; ++i)
|
||||||
|
thread thrd(&bar);
|
||||||
|
}
|
||||||
|
|
||||||
|
void foo()
|
||||||
|
{
|
||||||
|
for (int i=0; i<NUM_THREADS; ++i)
|
||||||
|
thread_ref thrd = create_thread(&bar);
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
<h3>4.</h3>
|
||||||
|
<pre>
|
||||||
|
void foo()
|
||||||
|
{
|
||||||
|
std::auto_ptr<thread> threads[NUM_THREADS];
|
||||||
|
for (int i=0; i<NUM_THREADS; ++i)
|
||||||
|
threads[i] = std::auto_ptr<thread>(new thread(&bar));
|
||||||
|
for (int i= 0; i<NUM_THREADS;
|
||||||
|
++i)threads[i]->join();
|
||||||
|
}
|
||||||
|
|
||||||
|
void foo()
|
||||||
|
{
|
||||||
|
thread_ref threads[NUM_THREADS];
|
||||||
|
for (int i=0; i<NUM_THREADS; ++i)
|
||||||
|
threads[i] = create_thread(&bar);
|
||||||
|
for (int i= 0; i<NUM_THREADS;
|
||||||
|
++i)threads[i]->join();
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
<h3>5.</h3>
|
||||||
|
<pre>
|
||||||
|
void foo()
|
||||||
|
{
|
||||||
|
thread thrd* = new thread(&bar);
|
||||||
|
manager.owns(thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
void foo()
|
||||||
|
{
|
||||||
|
thread_ref thrd = create_thread(&bar);
|
||||||
|
manager.owns(thrd);
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
<h3>6.</h3>
|
||||||
|
<pre>
|
||||||
|
void foo()
|
||||||
|
{
|
||||||
|
boost::shared_ptr<thread> thrd(new thread(&bar));
|
||||||
|
manager1.add(thrd);
|
||||||
|
manager2.add(thrd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void foo()
|
||||||
|
{
|
||||||
|
thread_ref thrd = create_thread(&bar);
|
||||||
|
manager1.add(thrd);
|
||||||
|
manager2.add(thrd);
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
<p>This shows the usage patterns being nearly identical in complexity for both
|
||||||
|
designs. The only actual added complexity occurs because of the use of operator
|
||||||
|
new in (4), (5) and (6) and the use of std::auto_ptr and boost::shared_ptr in
|
||||||
|
(4) and (6) respectively. However, that's not really much added complexity,
|
||||||
|
and C++ programmers are used to using these idioms any way. Some may dislike
|
||||||
|
the presence of operator new in user code, but this can be eliminated by proper
|
||||||
|
design of higher level concepts, such as the boost::thread_group class that
|
||||||
|
simplifies example (4) down to:</p>
|
||||||
|
<pre>
|
||||||
|
void foo()
|
||||||
|
{
|
||||||
|
thread_group threads;
|
||||||
|
for (int i=0; i<NUM_THREADS; ++i)
|
||||||
|
threads.create_thread(&bar);
|
||||||
|
threads.join_all();
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
<p>So ease of use is really a wash and not much help in picking a design.</p>
|
||||||
|
<p>So what about performance? If you look at the above code examples we can analyze
|
||||||
|
the theoretical impact to performance that both designs have. For (1) we can
|
||||||
|
see that platforms that don't have a ref-counted native thread type (POSIX,
|
||||||
|
for instance) will be impacted by a thread_ref design. Even if the native thread
|
||||||
|
type is ref-counted there may be an impact if more state information has to
|
||||||
|
be maintained for concepts foreign to the native API, such as clean up stacks
|
||||||
|
for Win32 implementations. For (2) the performance impact will be identical
|
||||||
|
to (1). The same for (3). For (4) things get a little more interesting and we
|
||||||
|
find that theoretically at least the thread_ref may perform faster since the
|
||||||
|
thread design requires dynamic memory allocation/deallocation. However, in practice
|
||||||
|
there may be dynamic allocation for the thread_ref design as well, it will just
|
||||||
|
be hidden from the user. As long as the implementation has to do dynamic allocations
|
||||||
|
the thread_ref loses again because of the reference management. For (5) we see
|
||||||
|
the same impact as we do for (4). For (6) we still have a possible impact to
|
||||||
|
the thread design because of dynamic allocation but thread_ref no longer suffers
|
||||||
|
because of its reference management, and in fact, theoretically at least, the
|
||||||
|
thread_ref may do a better job of managing the references. All of this indicates
|
||||||
|
that thread wins for (1), (2) and (3), with (4) and (5) the winner depends on
|
||||||
|
the implementation and the platform but the thread design probably has a better
|
||||||
|
chance, and with (6) it will again depend on the implementation and platform
|
||||||
|
but this time we favor thread_ref slightly. Given all of this it's a narrow
|
||||||
|
margin, but the thread design prevails.</p>
|
||||||
|
<p>Given this analysis, and the fact that noncopyable objects for system resources
|
||||||
|
are the normal designs that C++ programmers are used to dealing with, the <b>Boost.Threads</b>
|
||||||
|
library has gone with a noncopyable design.</p>
|
||||||
|
<h2><a name="events"></a>Rationale for not providing <i>Event Variables</i></h2>
|
||||||
|
<p><i>Event variables</i> are simply far too error-prone. <a href=
|
||||||
|
"condition.html">Condition variables</a> are a much safer alternative.</p>
|
||||||
|
<p>[Note that Graphical User Interface <i>events</i> are a different concept,
|
||||||
|
and are not what is being discussed here.]</p>
|
||||||
|
<p>Event variables were one of the first synchronization primitives. They are
|
||||||
|
still used today, for example, in the native Windows multithreading API.</p>
|
||||||
|
<p>Yet both respected computer science researchers and experienced multithreading
|
||||||
|
practitioners believe event variables are so inherently error-prone that they
|
||||||
|
should never be used, and thus should not be part of a multithreading library.</p>
|
||||||
|
<p>Per Brinch Hansen <a href="bibliography.html#Brinch-Hansen-73"> [Brinch Hansen
|
||||||
|
73]</a> analyzed event variables in some detail, pointing out [emphasis his]
|
||||||
|
that "<i>event operations force the programmer to be aware of the relative
|
||||||
|
speeds of the sending and receiving processes</i>". His summary:</p>
|
||||||
|
<blockquote>
|
||||||
|
<p>We must therefore conclude that event variables of the previous type are
|
||||||
|
impractical for system design. <i>The effect of an interaction between two
|
||||||
|
processes must be independent of the speed at which it is carried out.</i></p>
|
||||||
|
</blockquote>
|
||||||
|
<p>Experienced programmers using the Windows platform today report that event
|
||||||
|
variables are a continuing source of errors, even after previous bad experiences
|
||||||
|
caused them to be very careful in their use of event variables. Overt problems
|
||||||
|
can be avoided, for example, by teaming the event variable with a mutex, but
|
||||||
|
that may just convert a <a href=
|
||||||
|
"definitions.html#Race condition">race condition</a> into another problem,
|
||||||
|
such as excessive resource use. One of the most distressing aspects of the experience
|
||||||
|
reports is the claim that many defects are latent. That is, the programs appear
|
||||||
|
to work correctly, but contain hidden timing dependencies which will cause them
|
||||||
|
to fail when environmental factors or usage patterns change, altering relative
|
||||||
|
thread timings.</p>
|
||||||
|
<p>The decision to exclude event variables from <b>Boost.Threads</b> has been
|
||||||
|
surprising to some Windows programmers. They have written programs which work
|
||||||
|
using event variables, and wonder what the problem is. It seems similar to the
|
||||||
|
"goto considered harmful" controversy of 30 years ago. It isn't
|
||||||
|
that events, like gotos, can't be made to work, but rather that virtually
|
||||||
|
all programs using alternatives will be easier to write, debug, read, maintain,
|
||||||
|
and be less likely to contain latent defects.</p>
|
||||||
|
<p>[Rationale provided by Beman Dawes]</p>
|
||||||
|
<hr>
|
||||||
|
<p>Revised
|
||||||
|
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
||||||
|
05 November, 2001
|
||||||
|
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
|
||||||
|
</p>
|
||||||
|
<p><i>© Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
|
||||||
|
All Rights Reserved.</i></p>
|
||||||
|
<p>Permission to use, copy, modify, distribute and sell this software and its
|
||||||
|
documentation for any purpose is hereby granted without fee, provided that the
|
||||||
|
above copyright notice appear in all copies and that both that copyright notice
|
||||||
|
and this permission notice appear in supporting documentation. William E. Kempf
|
||||||
|
makes no representations about the suitability of this software for any purpose.
|
||||||
|
It is provided "as is" without express or implied warranty.</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
288
doc/recursive_mutex.html
Normal file
288
doc/recursive_mutex.html
Normal file
@@ -0,0 +1,288 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||||
|
<link rel="stylesheet" type="text/css" href="../../../boost.css">
|
||||||
|
<title>Boost.Threads - Header <boost/thread/recursive_mutex.hpp></title>
|
||||||
|
</head>
|
||||||
|
<body link="#0000ff" vlink="#800080">
|
||||||
|
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
|
||||||
|
"header">
|
||||||
|
<tr>
|
||||||
|
<td valign="top" width="300">
|
||||||
|
<h3><a href="../../../index.htm"><img height="86" width="277" alt="C++ Boost" src="../../../c++boost.gif" border="0"></a></h3>
|
||||||
|
</td>
|
||||||
|
<td valign="top">
|
||||||
|
<h1 align="center">Boost.Threads</h1>
|
||||||
|
<h2 align="center">Header <<a href="../../../boost/thread/recursive_mutex.hpp">boost/thread/recursive_mutex.hpp</a>></h2> </td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<hr>
|
||||||
|
<h2>Contents</h2>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="#introduction">Introduction</a></dt>
|
||||||
|
<dt><a href="#classes">Classes</a></dt>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="#class-recursive_mutex">Class <code>recursive_mutex</code></a></dt>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="#class-recursive_mutex-synopsis">Class <code>recursive_mutex</code>
|
||||||
|
synopsis</a></dt>
|
||||||
|
<dt><a href="#class-recursive_mutex-ctors">Class <code>recursive_mutex</code>
|
||||||
|
constructors and destructor</a></dt>
|
||||||
|
</dl>
|
||||||
|
<dt><a href="#class-recursive_try_mutex">Class <code>recursive_try_mutex</code></a></dt>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="#class-recursive_try_mutex-synopsis">Class <code>recursive_try_mutex</code>
|
||||||
|
synopsis</a></dt>
|
||||||
|
<dt><a href="#class-recursive_try_mutex-ctors">Class <code>recursive_try_mutex</code>
|
||||||
|
constructors and destructor</a></dt>
|
||||||
|
</dl>
|
||||||
|
<dt><a href="#class-recursive_timed_mutex">Class <code>recursive_timed_mutex</code></a></dt>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="#class-recursive_timed_mutex-synopsis">Class <code>recursive_timed_mutex</code>
|
||||||
|
synopsis</a></dt>
|
||||||
|
<dt><a href="#class-recursive_timed_mutex-ctors">Class <code>recursive_timed_mutex</code>
|
||||||
|
constructors and destructor</a></dt>
|
||||||
|
</dl>
|
||||||
|
</dl>
|
||||||
|
<dt><a href="#examples">Example(s)</a></dt>
|
||||||
|
</dl>
|
||||||
|
<hr>
|
||||||
|
<h2><a name="introduction"></a>Introduction</h2>
|
||||||
|
<p>Include the header <<a href="../../../boost/thread/recursive_mutex.hpp">boost/thread/recursive_mutex.hpp</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>
|
||||||
|
<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
|
||||||
|
are models of <a href="mutex_concept.html#Mutex-concept">Mutex</a>, <a href="mutex_concept.html#TryMutex-concept">TryMutex</a>,
|
||||||
|
and <a href="mutex_concept.html#TimedMutex-concept">TimedMutex</a> respectively.
|
||||||
|
These types should be used to synchronize access to shared resources when recursive
|
||||||
|
locking by a single thread is likely to occur. A good example for this is when
|
||||||
|
a class supplies "internal synchronization" to ensure <a href="definitions.html#Thread-safe">
|
||||||
|
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,
|
||||||
|
see <a href="mutex.html">mutexes</a>.</p>
|
||||||
|
<p>Each class supplies one or more typedefs for lock types which model matching
|
||||||
|
lock concepts. For the best possible performance you should use the mutex class
|
||||||
|
that supports the minimum set of lock types that you need.</p>
|
||||||
|
<table summary="lock types" border="1" cellpadding="5">
|
||||||
|
<tr>
|
||||||
|
<td><b>Mutex Class</b></td>
|
||||||
|
<td><b>Lock name</b></td>
|
||||||
|
<td><b>Lock Concept</b></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td valign="top"><a href="#recursive_mutex Synopsis"><code> recursive_mutex</code></a></td>
|
||||||
|
<td valign="middle"><code>scoped_lock</code></td>
|
||||||
|
<td valign="middle"><a href="lock_concept.html#ScopedLock"> ScopedLock</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td valign="top"><code><a href="#recursive_try_mutex Synopsis"> recursive_try_mutex</a></code></td>
|
||||||
|
<td valign="middle"><code>scoped_lock<br>
|
||||||
|
scoped_try_lock</code></td>
|
||||||
|
<td valign="middle"><a href="lock_concept.html#ScopedLock"> ScopedLock</a><br>
|
||||||
|
<a href="lock_concept.html#ScopedTryLock"> ScopedTryLock</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td valign="top"><code><a href=
|
||||||
|
"#recursive_timed_mutex Synopsis"> recursive_timed_mutex</a></code>
|
||||||
|
</td>
|
||||||
|
<td valign="middle"><code>scoped_lock<br>
|
||||||
|
scoped_try_lock<br>
|
||||||
|
scoped_timed_lock</code></td>
|
||||||
|
<td valign="middle"><a href="lock_concept.html#ScopedLock"> ScopedLock</a><br>
|
||||||
|
<a href="lock_concept.html#ScopedTryLock"> ScopedTryLock</a><br>
|
||||||
|
<a href="lock_concept.html#ScopedTimedLock"> ScopedTimedLock</a></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<p>The <code>recursive_mutex</code>, <code>recursive_try_mutex</code> and <code>recursive_timed_mutex</code>
|
||||||
|
employ a <code>Recursive</code> <a href="mutex_concept.html#LockingStrategies">locking
|
||||||
|
strategy</a>, so attempts to recursively lock them succeed and an internal "lock
|
||||||
|
count" is maintained. Attempts to unlock them by a thread that does not
|
||||||
|
own a lock on them will result in <b>undefined behavior</b>.</p>
|
||||||
|
<p>The <code>recursive_mutex</code>, <code>recursive_try_mutex</code> and <code>recursive_timed_mutex</code>
|
||||||
|
leave the <a href=
|
||||||
|
"mutex_concept.html#SchedulingPolicies">scheduling policy</a> as <code>
|
||||||
|
Unspecified</code>. Programmers should assume that threads waiting for a lock
|
||||||
|
on objects of these types acquire the lock in a random order, even though the
|
||||||
|
specific behavior for a given platform may be different.</p>
|
||||||
|
<h2><a name="classes"></a>Classes</h2>
|
||||||
|
<h3><a name="class-recursive_mutex"></a>Class <code>recursive_mutex</code></h3>
|
||||||
|
<p>The <code>recursive_mutex</code> class is a model of <a href="mutex_concept.html#Mutex-concept">Mutex</a>
|
||||||
|
and <a href="overview.html#non-copyable">NonCopyable</a>, and provides no additional
|
||||||
|
facilities beyond the requirements of these concepts.</p>
|
||||||
|
<h4><a name="class-recursive_mutex-synopsis"></a>Class <code>recursive_mutex</code>
|
||||||
|
synopsis</h4>
|
||||||
|
<pre>
|
||||||
|
namespace boost
|
||||||
|
{
|
||||||
|
class recursive_mutex : private boost::noncopyable // Exposition only.
|
||||||
|
// Class recursive_mutex meets the NonCopyable requirement.
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef [implementation defined; see Introduction] scoped_lock;
|
||||||
|
|
||||||
|
recursive_mutex();
|
||||||
|
~recursive_mutex();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
</pre>
|
||||||
|
<h4><a name="class-recursive_mutex-ctors"></a>Class <code>recursive_mutex</code>
|
||||||
|
constructors and destructor</h4>
|
||||||
|
<pre>
|
||||||
|
recursive_mutex();
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<dt><b>Postconditions:</b> <code>*this</code> is in an unlocked state.</dt>
|
||||||
|
</dl>
|
||||||
|
<pre>
|
||||||
|
~recursive_mutex();
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<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
|
||||||
|
resulting in undefined behavior such as a program crash.</dt>
|
||||||
|
</dl>
|
||||||
|
<h3><a name="class-recursive_try_mutex"></a>Class <code>recursive_try_mutex</code></h3>
|
||||||
|
<p>The <code>recursive_try_mutex</code> class is a model of <a href="mutex_concept.html#TryMutex-concept">TryMutex</a>
|
||||||
|
and <a href="overview.html#non-copyable">NonCopyable</a>, and provides no additional
|
||||||
|
facilities beyond the requirements of these concepts.</p>
|
||||||
|
<h4><a name="class-recursive_try_mutex-synopsis"></a>Class <code>recursive_try_mutex</code>
|
||||||
|
synopsis</h4>
|
||||||
|
<pre>
|
||||||
|
namespace boost
|
||||||
|
{
|
||||||
|
class recursive_mutex : private boost::noncopyable // Exposition only.
|
||||||
|
// Class recursive_mutex meets the NonCopyable requirement.
|
||||||
|
{
|
||||||
|
Public:
|
||||||
|
typedef [implementation defined; see Introduction] scoped_lock;
|
||||||
|
typedef [implementation defined; see Introduction] scoped_try_lock;
|
||||||
|
|
||||||
|
recursive_try_mutex();
|
||||||
|
~recursive_try_mutex();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
</pre>
|
||||||
|
<h4><a name="class-recursive_try_mutex-ctors"></a>Class <code>recursive_try_mutex</code>
|
||||||
|
constructors and destructor</h4>
|
||||||
|
<pre>
|
||||||
|
recursive_try_mutex();
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<dt><b>Postconditions:</b> <code>*this</code> is in an unlocked state.</dt>
|
||||||
|
</dl>
|
||||||
|
<pre>
|
||||||
|
~recursive_try_mutex();
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<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
|
||||||
|
resulting in undefined behavior such as a program crash.</dt>
|
||||||
|
</dl>
|
||||||
|
<h3><a name="class-recursive_timed_mutex"></a>Class <code>recursive_timed_mutex</code></h3>
|
||||||
|
<p>The <code>recursive_timed_mutex</code> class is a model of <a href="mutex_concept.html#TimedMutex-concept">TimedMutex</a>
|
||||||
|
and <a href="overview.html#non-copyable">NonCopyable</a>, and provides no additional
|
||||||
|
facilities beyond the requirements of these concepts.</p>
|
||||||
|
<h4><a name="class-recursive_timed_mutex-synopsis"></a>Class <code>recursive_timed_mutex</code>
|
||||||
|
synopsis</h4>
|
||||||
|
<pre>
|
||||||
|
namespace boost
|
||||||
|
{
|
||||||
|
class recursive_timed_mutex : private boost::noncopyable // Exposition only.
|
||||||
|
// Class recursive_mutex meets the NonCopyable requirement.
|
||||||
|
{
|
||||||
|
Public:
|
||||||
|
typedef [implementation defined; see Introduction] scoped_lock;
|
||||||
|
typedef [implementation defined; see Introduction] scoped_try_lock;
|
||||||
|
typedef [implementation defined; see Introduction] scoped_timed_lock;
|
||||||
|
|
||||||
|
recursive_timed_mutex();
|
||||||
|
~recursive_timed_mutex();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
</pre>
|
||||||
|
<h4><a name="class-recursive_timed_mutex-ctors"></a>Class <code>recursive_timed_mutex</code>
|
||||||
|
constructors and destructor</h4>
|
||||||
|
<pre>
|
||||||
|
recursive_timed_mutex();
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<dt><b>Postconditions:</b> <code>*this</code> is in an unlocked state.</dt>
|
||||||
|
</dl>
|
||||||
|
<pre>
|
||||||
|
~recursive_timed_mutex();
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<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
|
||||||
|
resulting in undefined behavior such as a program crash.</dt>
|
||||||
|
</dl>
|
||||||
|
<h2><a name="examples"></a>Example(s)</h2>
|
||||||
|
<pre>
|
||||||
|
#include <a href="../../../boost/thread/recursive_mutex.hpp"><boost/thread/recursive_mutex.hpp></a>
|
||||||
|
#include <a href="../../../boost/thread/thread.hpp"><boost/thread/thread.hpp></a>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
class counter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
counter() : count(0) { }
|
||||||
|
|
||||||
|
int add(int val) {
|
||||||
|
boost::recursive_mutex::scoped_lock scoped_lock(mutex);
|
||||||
|
count += val;
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
int increment() {
|
||||||
|
boost::recursive_mutex::scoped_lock scoped_lock(mutex);
|
||||||
|
return add(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
boost::recursive_mutex mutex;
|
||||||
|
int count;
|
||||||
|
};
|
||||||
|
|
||||||
|
counter c;
|
||||||
|
|
||||||
|
void change_count(void*)
|
||||||
|
{
|
||||||
|
std::cout << "count == " << c.increment() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int, char*[])
|
||||||
|
{
|
||||||
|
const int num_threads=4;
|
||||||
|
|
||||||
|
boost::thread_group threads;
|
||||||
|
for (int i=0; i < num_threads; ++i)
|
||||||
|
threads.create_thread(&change_count, 0);
|
||||||
|
|
||||||
|
threads.join_all();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
<p>The output is:</p>
|
||||||
|
<pre>
|
||||||
|
count == 1
|
||||||
|
count == 2
|
||||||
|
count == 3
|
||||||
|
count == 4
|
||||||
|
</pre>
|
||||||
|
<hr>
|
||||||
|
<p>Revised
|
||||||
|
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
||||||
|
05 November, 2001
|
||||||
|
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
|
||||||
|
</p>
|
||||||
|
<p><i>© Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
|
||||||
|
All Rights Reserved.</i></p>
|
||||||
|
<p>Permission to use, copy, modify, distribute and sell this software and its
|
||||||
|
documentation for any purpose is hereby granted without fee, provided that the
|
||||||
|
above copyright notice appear in all copies and that both that copyright notice
|
||||||
|
and this permission notice appear in supporting documentation. William E. Kempf
|
||||||
|
makes no representations about the suitability of this software for any purpose.
|
||||||
|
It is provided "as is" without express or implied warranty.</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
372
doc/thread.html
Normal file
372
doc/thread.html
Normal file
@@ -0,0 +1,372 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||||
|
<link rel="stylesheet" type="text/css" href="../../../boost.css">
|
||||||
|
<title>Boost.Threads - <boost/thread.hpp></title>
|
||||||
|
</head>
|
||||||
|
<body link="#0000ff" vlink="#800080">
|
||||||
|
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
|
||||||
|
"header">
|
||||||
|
<tr>
|
||||||
|
<td valign="top" width="300">
|
||||||
|
<h3><a href="../../../index.htm"><img height="86" width="277" alt="C++ Boost" src="../../../c++boost.gif" border="0"></a></h3>
|
||||||
|
</td>
|
||||||
|
<td valign="top">
|
||||||
|
<h1 align="center">Boost.Threads</h1>
|
||||||
|
<h2 align="center">Header <<a href="../../../boost/thread/thread.hpp">boost/thread.hpp</a>></h2>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<hr>
|
||||||
|
<h2>Contents</h2>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="#introduction">Introduction</a></dt>
|
||||||
|
<dt><a href="#classes">Classes</a></dt>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="#class-thread">Class <code>thread</code></a></dt>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="#class-thread-synopsis">Class <code>thread</code> synopsis</a></dt>
|
||||||
|
<dt><a href="#class-thread-ctors">Class <code>thread</code> constructors
|
||||||
|
and destructor</a></dt>
|
||||||
|
<dt><a href="#class-thread-comparisons">Class <code>thread</code> comparison
|
||||||
|
functions</a></dt>
|
||||||
|
<dt><a href="#class-thread-modifiers">Class <code>thread</code> modifier
|
||||||
|
functions</a></dt>
|
||||||
|
<dt><a href="#class-thread-statics">Class <code>thread</code> static functions</a></dt>
|
||||||
|
</dl>
|
||||||
|
<dt><a href="#class-thread_group">Class <code>thread_group</code></a></dt>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="#class-thread_group-synopsis">Class <code>thread_group</code>
|
||||||
|
synopsis</a></dt>
|
||||||
|
<dt><a href="#class-thread_group-ctors">Class <code>thread_group</code>
|
||||||
|
constructors and destructor</a></dt>
|
||||||
|
<dt><a href="#class-thread_group-modifiers">Class <code>thread_group</code>
|
||||||
|
modifier functions</a></dt>
|
||||||
|
</dl>
|
||||||
|
</dl>
|
||||||
|
<dt><a href="#examples">Example(s)</a></dt>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="#example-thread">Simple usage of <code>boost::thread</code></a></dt>
|
||||||
|
<dt><a href="#example-thread_group">Simple usage of <code>boost::thread_group</code></a></dt>
|
||||||
|
</dl>
|
||||||
|
</dl>
|
||||||
|
<hr>
|
||||||
|
<h2><a name="introduction"></a>Introduction</h2>
|
||||||
|
<p>The header <<a href="../../../boost/thread/thread.hpp">boost/thread.hpp</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>
|
||||||
|
<h2><a name="classes"></a>Classes</h2>
|
||||||
|
<h3><a name="class-thread"></a>Class <code>thread</code></h3>
|
||||||
|
<p>The <code>thread</code> class represents threads of execution, and provides
|
||||||
|
the functionality to create and manage threads within the <b> Boost.Threads</b>
|
||||||
|
library. See <a href="definitions.html"> Definitions</a> for a precise description
|
||||||
|
of "thread of execution", and for definitions of threading related
|
||||||
|
terms and of thread states such as "blocked".</p>
|
||||||
|
<p>A thread of execution has an initial function. For the program's initial
|
||||||
|
thread, the initial function is <code>main()</code>. For other threads, the
|
||||||
|
initial function is <code>operator()</code> of the function object passed to
|
||||||
|
the class <code>thread</code> constructor.</p>
|
||||||
|
<p>A thread of execution is said to be "finished" or "finished
|
||||||
|
execution" when its initial function returns or is terminated. This includes
|
||||||
|
completion of all thread cleanup handlers, and completion of the normal C++
|
||||||
|
function return behaviors, such as destruction of automatic storage (stack)
|
||||||
|
objects and releasing any associated implementation resources.</p>
|
||||||
|
<p>A thread object has an associated state which is either "joinable"
|
||||||
|
or "non-joinable".</p>
|
||||||
|
<p>Except as described below, the policy used by an implementation of <b>Boost.Threads</b>
|
||||||
|
to schedule transitions between thread states is unspecified.</p>
|
||||||
|
<p><b>Note:</b> Just as the lifetime of a file may be different from the lifetime
|
||||||
|
of an iostream object which represents the file, the lifetime of a thread of
|
||||||
|
execution may be different from the <code> thread</code> object which represents
|
||||||
|
the thread of execution. In particular, after a call to <code>join()</code>,
|
||||||
|
the thread of execution will no longer exist even though the <code>thread</code>
|
||||||
|
object continues to exist until the end of its normal lifetime. The converse
|
||||||
|
is also possible; if a <code>thread</code> object is destroyed without <code>join()</code>
|
||||||
|
having first been called, the thread of execution continues until its initial
|
||||||
|
function completes.</p>
|
||||||
|
<h4><a name="class-thread-synopsis"></a>Class <code>thread</code> synopsis</h4>
|
||||||
|
<pre>
|
||||||
|
namespace boost {
|
||||||
|
class thread : <a href=
|
||||||
|
"../../utility/utility.htm#Class noncopyable">boost::noncopyable</a> // Exposition only.
|
||||||
|
// Class thread meets the <a href=
|
||||||
|
"overview.html#non-copyable">NonCopyable</a> requirement.
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
thread();
|
||||||
|
explicit thread(const boost::function0<void>& threadfunc);
|
||||||
|
~thread();
|
||||||
|
|
||||||
|
bool operator==(const thread& rhs) const;
|
||||||
|
bool operator!=(const thread& rhs) const;
|
||||||
|
|
||||||
|
void join();
|
||||||
|
|
||||||
|
static void sleep(const xtime& xt);
|
||||||
|
static void yield();
|
||||||
|
};
|
||||||
|
} // namespace boost
|
||||||
|
</pre>
|
||||||
|
<h4><a name="class-thread-ctors"></a>Class <code>thread</code> constructors and
|
||||||
|
destructor</h4>
|
||||||
|
<pre>
|
||||||
|
thread();
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<dt><b>Effects:</b> Constructs a <code>thread</code> object representing the
|
||||||
|
current thread of execution.</dt>
|
||||||
|
<dt><b>Postconditions:</b> <code>*this</code> is non-joinable.</dt>
|
||||||
|
<dt><b>Danger:</b> <code>*this</code> is valid only within the current thread.</dt>
|
||||||
|
</dl>
|
||||||
|
<pre>
|
||||||
|
thread(const <a href="../../function/index.html">boost::function0</a><void>& threadfunc);
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<dt><b>Effects:</b> Starts a new thread of execution and constructs a <code>thread</code>
|
||||||
|
object representing it. Copies <code> threadfunc</code> (which in turn copies
|
||||||
|
the function object wrapped by <code>threadfunc</code>) to an internal location
|
||||||
|
which persists for the lifetime of the new thread of execution. Calls <code>operator()</code>
|
||||||
|
on the copy of the <code>threadfunc</code> function object in the new thread
|
||||||
|
of execution.</dt>
|
||||||
|
<dt><b>Postconditions:</b> <code>*this</code> is joinable.</dt>
|
||||||
|
<dt><b>Throws:</b> <code>boost::thread_resource_error</code> if a new thread
|
||||||
|
of execution cannot be started.</dt>
|
||||||
|
</dl>
|
||||||
|
<pre>
|
||||||
|
~Thread();
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<dt><b>Effects:</b> Destroys <code>*this</code>. The actual thread of execution
|
||||||
|
may continue to execute after the <code>thread</code> object has been destroyed.</dt>
|
||||||
|
<dt><b>Note:</b> If <code>*this</code> is joinable the actual thread of execution
|
||||||
|
becomes "detached". Any resources used by the thread will be reclaimed
|
||||||
|
when the thread of execution completes. To ensure such a thread of execution
|
||||||
|
runs to completion before the <code> thread</code> object is destroyed, call
|
||||||
|
<code>join()</code>.</dt>
|
||||||
|
</dl>
|
||||||
|
<h4><a name="class-thread-comparisons"></a>Class <code>thread</code> comparison
|
||||||
|
functions</h4>
|
||||||
|
<pre>
|
||||||
|
bool operator==(const thread& rhs) const;
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<dt><b>Requires:</b> The thread is non-terminated or <code>*this</code> is joinable.</dt>
|
||||||
|
<dt><b>Returns:</b> <code>true</code> if <code>*this</code> and <code> rhs</code>
|
||||||
|
represent the same thread of execution.</dt>
|
||||||
|
</dl>
|
||||||
|
<pre>
|
||||||
|
bool operator!=(const thread& rhs) const;
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<dt><b>Requires:</b> The thread is non-terminated or <code>*this</code> is joinable.</dt>
|
||||||
|
<dt><b>Returns:</b> <code>!(*this==rhs)</code>.</dt>
|
||||||
|
</dl>
|
||||||
|
<h4><a name="class-thread-modifiers"></a>Class <code>thread</code> modifier functions</h4>
|
||||||
|
<pre>
|
||||||
|
void join();
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<dt><b>Requires:</b> <code>*this</code> is joinable.</dt>
|
||||||
|
<dt><b>Effects:</b> The current thread of execution blocks until the initial
|
||||||
|
function of the thread of execution represented by <code> *this</code> finishes
|
||||||
|
and all resources are reclaimed.</dt>
|
||||||
|
<dt><b>Postconditions:</b> <code>*this</code> is non-joinable.</dt>
|
||||||
|
<dt><b>Notes:</b> If <code>*this == thread()</code> the result is implementation
|
||||||
|
defined. If the implementation doesn't detect this the result will be
|
||||||
|
<a href="definitions.html#Deadlock"> deadlock</a>.</dt>
|
||||||
|
</dl>
|
||||||
|
<h4><a name="class-thread-statics"></a>Class <code>thread</code> static functions</h4>
|
||||||
|
<pre>
|
||||||
|
static void sleep(const <a href="xtime.html">xtime</a>& XT);
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<dt><b>Effects:</b> The current thread of execution blocks until <code> XT</code>
|
||||||
|
is reached.</dt>
|
||||||
|
</dl>
|
||||||
|
<pre>
|
||||||
|
static void yield();
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<dt><b>Effects:</b> The current thread of execution is placed in the "ready"
|
||||||
|
state.</dt>
|
||||||
|
<dt><b>Notes:</b> Allow the current thread to give up the rest of its time slice
|
||||||
|
(or other scheduling quota) to another thread. Particularly useful in non-preemptive
|
||||||
|
implementations.</dt>
|
||||||
|
</dl>
|
||||||
|
<h3><a name="class-thread_group"></a>Class <code>thread_group</code></h3>
|
||||||
|
<p>The <tt>thread_group</tt> class provides a container for easy grouping of threads
|
||||||
|
to simplify several common thread creation and management idioms.</p>
|
||||||
|
<p>All <tt>thread_group</tt> member functions are <a href=
|
||||||
|
"definitions.html#thread-safe">thread-safe</a>, except destruction.</p>
|
||||||
|
<h4><a name="class-thread_group-synopsis"></a>Class <code>thread_group</code>
|
||||||
|
synopsis</h4>
|
||||||
|
<pre>
|
||||||
|
namespace boost {
|
||||||
|
class thread_group : <a href=
|
||||||
|
"../../utility/utility.htm#Class noncopyable">boost::noncopyable</a>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
thread_group();
|
||||||
|
~thread_group();
|
||||||
|
|
||||||
|
thread* create_thread(const boost::function0<void>& threadfunc);
|
||||||
|
void add_thread(thread* thrd);
|
||||||
|
void remove_thread(thread* thrd);
|
||||||
|
void join_all();
|
||||||
|
};
|
||||||
|
} // namespace boost
|
||||||
|
</pre>
|
||||||
|
<h4><a name="class-thread_group-ctors"></a>Class <code>thread_group</code> constructors
|
||||||
|
and destructor</h4>
|
||||||
|
<pre>
|
||||||
|
thread_group();
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<dt><b>Effects:</b> Constructs an empty <code>thread_group</code> container.</dt>
|
||||||
|
</dl>
|
||||||
|
<pre>
|
||||||
|
~thread_group();
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<dt><b>Effects:</b> Destroys each contained thread object. Destroys <code>*this</code>.</dt>
|
||||||
|
<dt><b>Notes:</b> Behavior is undefined if another thread references *this during
|
||||||
|
the execution of the destructor.</dt>
|
||||||
|
</dl>
|
||||||
|
<h4><a name="class-thread_group-modifiers"></a>Class <code>thread_group</code>
|
||||||
|
modifier functions</h4>
|
||||||
|
<pre>
|
||||||
|
thread* create_thread(const boost::function0<void>& threadfunc);
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<dt><b>Effects:</b> Creates a new <tt>thread</tt> object that executes <tt>threadfunc</tt>
|
||||||
|
and adds it to the <tt>thread_group</tt> container object's list of managed
|
||||||
|
<tt>thread</tt> objects.</dt>
|
||||||
|
<dt><b>Returns:</b> Pointer to the newly created thread.</dt>
|
||||||
|
</dl>
|
||||||
|
<pre>
|
||||||
|
void add_thread(thread* thrd);
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<dt><b>Effects:</b> Adds <tt>thrd</tt> to the <tt>thread_group</tt> object's
|
||||||
|
list of managed <tt>thread</tt> objects. The <tt>thrd</tt> object must have
|
||||||
|
been allocated via operator new and will be deleted when the group is destroyed.</dt>
|
||||||
|
</dl>
|
||||||
|
<pre>
|
||||||
|
Void remove_thread(thread* thrd);
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<dt><b>Effects:</b> Removes <code>*this</code>'s list of managed <tt>thread</tt>
|
||||||
|
objects.</dt>
|
||||||
|
<dt><b>Throws:</b> ? if <tt>thrd</tt> is not it <code>*this</code>'s list
|
||||||
|
of managed <tt>thread</tt> objects.</dt>
|
||||||
|
</dl>
|
||||||
|
<pre>
|
||||||
|
Void join_all();
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<dt><b>Effects:</b> Calls <code>join()</code> on each of the managed <tt>thread</tt>
|
||||||
|
objects.</dt>
|
||||||
|
</dl>
|
||||||
|
<h2><a name="functions"></a>Functions</h2>
|
||||||
|
<pre>
|
||||||
|
<a name="function-spec"></a>{{function}}
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<dt><b>Requires:</b> {{text}}</dt>
|
||||||
|
<dt><b>Effects:</b> {{text}}</dt>
|
||||||
|
<dt><b>Postconditions:</b> {{text}}</dt>
|
||||||
|
<dt><b>Returns:</b> {{text}}</dt>
|
||||||
|
<dt><b>Throws:</b> {{text}}</dt>
|
||||||
|
<dt><b>Complexity:</b> {{text}}</dt>
|
||||||
|
<dt><b>Rationale:</b> {{text}}</dt>
|
||||||
|
</dl>
|
||||||
|
<h2><a name="objects"></a>Objects</h2>
|
||||||
|
<p><a name="object-spec"></a>{{Object specifications}}</p>
|
||||||
|
<h2><a name="examples"></a>Example(s)</h2>
|
||||||
|
<h3><a name="example-thread"></a>Simple usage of <code>boost::thread</code></h3>
|
||||||
|
<pre>
|
||||||
|
#include <boost/thread/thread.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
struct thread_alarm
|
||||||
|
{
|
||||||
|
thread_alarm(int secs) : m_secs(secs) { }
|
||||||
|
void operator()()
|
||||||
|
{
|
||||||
|
boost::xtime XT;
|
||||||
|
boost::xtime_get(&XT, boost::TIME_UTC);
|
||||||
|
xt.sec += m_secs;
|
||||||
|
|
||||||
|
boost::thread::sleep(XT);
|
||||||
|
|
||||||
|
std::cout << "alarm sounded..." << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
int m_secs;
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
int secs = 5;
|
||||||
|
std::cout << "setting alarm for 5 seconds..." << std::endl;
|
||||||
|
thread_alarm alarm(secs);
|
||||||
|
boost::thread thrd(alarm);
|
||||||
|
thrd.join();
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
<p>The output is:</p>
|
||||||
|
<pre>
|
||||||
|
setting alarm for 5 seconds...
|
||||||
|
alarm sounded...
|
||||||
|
</pre>
|
||||||
|
<h3><a name="example-thread_group"></a>Simple usage of <code>boost::thread_group</code></h3>
|
||||||
|
<pre>
|
||||||
|
#include <boost/thread/thread.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
boost::mutex mutex;
|
||||||
|
|
||||||
|
void increment_count()
|
||||||
|
{
|
||||||
|
boost::mutex::lock lock(mutex);
|
||||||
|
std::cout << "count = " << ++count << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
boost::thread_group threads;
|
||||||
|
for (int i = 0; i < 10; ++i)
|
||||||
|
threads.create_thread(&increment_count);
|
||||||
|
threads.join_all();
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
<p>The output is:</p>
|
||||||
|
<pre>
|
||||||
|
count = 1
|
||||||
|
count = 2
|
||||||
|
count = 3
|
||||||
|
count = 4
|
||||||
|
count = 5
|
||||||
|
count = 6
|
||||||
|
count = 7
|
||||||
|
count = 8
|
||||||
|
count = 9
|
||||||
|
count = 10
|
||||||
|
</pre>
|
||||||
|
<hr>
|
||||||
|
<p>Revised
|
||||||
|
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
||||||
|
05 November, 2001
|
||||||
|
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
|
||||||
|
</p>
|
||||||
|
<p><i>© Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
|
||||||
|
All Rights Reserved.</i></p>
|
||||||
|
<p>Permission to use, copy, modify, distribute and sell this software and its
|
||||||
|
documentation for any purpose is hereby granted without fee, provided that the
|
||||||
|
above copyright notice appear in all copies and that both that copyright notice
|
||||||
|
and this permission notice appear in supporting documentation. William E. Kempf
|
||||||
|
makes no representations about the suitability of this software for any purpose.
|
||||||
|
It is provided "as is" without express or implied warranty.</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
200
doc/tss.html
Normal file
200
doc/tss.html
Normal file
@@ -0,0 +1,200 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||||
|
<link rel="stylesheet" type="text/css" href="../../../boost.css">
|
||||||
|
<title>Boost.Threads - Header <boost/thread/tss.hpp></title>
|
||||||
|
</head>
|
||||||
|
<body link="#0000ff" vlink="#800080">
|
||||||
|
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
|
||||||
|
"header">
|
||||||
|
<tr>
|
||||||
|
<td valign="top" width="300">
|
||||||
|
<h3><a href="../../../index.htm"><img height="86" width="277" alt="C++ Boost" src="../../../c++boost.gif" border="0"></a></h3>
|
||||||
|
</td>
|
||||||
|
<td valign="top">
|
||||||
|
<h1 align="center">Boost.Threads</h1>
|
||||||
|
<h2 align="center">Header <<a href="../../../boost/thread/tss.hpp">boost/thread/tss.hpp</a>></h2>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<hr>
|
||||||
|
<h2>Contents</h2>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="#introduction">Introduction</a></dt>
|
||||||
|
<dt><a href="#classes">Classes</a></dt>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="#class-thread_specific_ptr">Class <code>thread_specific_ptr</code></a></dt>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="#class-thread_specific_ptr-synopsis">Class <code>thread_specific_ptr</code>
|
||||||
|
synopsis</a></dt>
|
||||||
|
<dt><a href="#class-thread_specific_ptr-ctors">Class <code>thread_specific_ptr</code>
|
||||||
|
constructors and destructor</a></dt>
|
||||||
|
<dt><a href="#class-thread_specific_ptr-modifiers">Class <code>thread_specific_ptr</code>
|
||||||
|
modifier functions</a></dt>
|
||||||
|
<dt><a href="#class-thread_specific_ptr-observers">Class <code>thread_specific_ptr</code>
|
||||||
|
observer functions</a></dt>
|
||||||
|
</dl>
|
||||||
|
</dl>
|
||||||
|
<dt><a href="#examples">Example(s)</a></dt>
|
||||||
|
</dl>
|
||||||
|
<hr>
|
||||||
|
<h2><a name="introduction"></a>Introduction</h2>
|
||||||
|
<p>The header <<a href="../../../boost/thread/tss.hpp">boost/thread/tss.hpp</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>
|
||||||
|
<h2><a name="classes"></a>Classes</h2>
|
||||||
|
<h3><a name="class-thread_specific_ptr"></a>Class <code>thread_specific_ptr</code></h3>
|
||||||
|
<p>The <code>thread_specific_ptr</code> class defines an interface for using thread
|
||||||
|
specific storage. Thread specific storage is data associated with individual
|
||||||
|
threads and is often used to make operations <a href="definitions.html#Thread-safe">thread-safe</a>
|
||||||
|
that rely on global data.</p>
|
||||||
|
<p>Template <code>thread_specific_ptr</code> stores a pointer to an object obtained
|
||||||
|
via <code>new</code> on a thread-by-thread basis and calls delete on the contained
|
||||||
|
pointer when the thread terminates. Each thread initially stores the null pointer
|
||||||
|
in each <code> thread_specific_ptr</code> instance.</p>
|
||||||
|
<p>The template <code>thread_specific_ptr</code> is useful in the following cases:</p>
|
||||||
|
<ul>
|
||||||
|
<li>An interface was originally written assuming a single thread of control
|
||||||
|
and is being ported to a multithreaded environment.</li>
|
||||||
|
<li>Each thread of control invokes sequences of methods that share data that
|
||||||
|
must be logically accessed through a globally visible access point, but are
|
||||||
|
physically unique for each thread, instead of being explicitly passed.</li>
|
||||||
|
</ul>
|
||||||
|
<h4><a name="class-thread_specific_ptr-synopsis"></a>Class <code>thread_specific_ptr</code>
|
||||||
|
synopsis</h4>
|
||||||
|
<pre>
|
||||||
|
namespace boost
|
||||||
|
{
|
||||||
|
template <typename T>
|
||||||
|
class thread_specific_ptr : private boost::noncopyable // Exposition only.
|
||||||
|
// Class thread_specific_ptr meets the <a href="overview.html#non-copyable">NonCopyable</a> requirement.
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
thread_specific_ptr();
|
||||||
|
~thread_specific_ptr();
|
||||||
|
|
||||||
|
T* get() const;
|
||||||
|
T* operator->() const;
|
||||||
|
T& operator*() const;
|
||||||
|
T* release();
|
||||||
|
void reset(T* p=0);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
</pre>
|
||||||
|
<h4><a name="class-thread_specific_ptr-ctors"></a>Class <code>thread_specific_ptr</code>
|
||||||
|
constructors and destructor</h4>
|
||||||
|
<pre>
|
||||||
|
thread_specific_ptr();
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<dt><b>Requires:</b> The expression <code>delete get()</code> is well formed.</dt>
|
||||||
|
<dt><b>Postconditions:</b> A thread specific storage has been reserved for use
|
||||||
|
by <code>*this</code> in all threads, with each thread initially storing a
|
||||||
|
null pointer.</dt>
|
||||||
|
<dt><b>Throws:</b> <code>boost::thread_resource_error</code> if the necessary
|
||||||
|
resources can not be obtained.</dt>
|
||||||
|
<dt><b>Note:</b> There is an implementation specific limit to the number of
|
||||||
|
thread specific storage objects that can be created, and this limit may be
|
||||||
|
small.</dt>
|
||||||
|
</dl>
|
||||||
|
<pre>
|
||||||
|
~thread_specific_ptr();
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<dt><b>Note:</b> Does not destroy any data that may be stored in any thread's
|
||||||
|
thread specific storage. For this reason you should not destroy a <code>thread_specific_ptr</code>
|
||||||
|
object until you are certain there are no threads running that have made use
|
||||||
|
of its thread specific storage.</dt>
|
||||||
|
</dl>
|
||||||
|
<h4><a name="class-thread_specific_ptr-modifiers"></a>Class <code>thread_specific_ptr</code>
|
||||||
|
modifier functions</h4>
|
||||||
|
<pre>
|
||||||
|
T* release();
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<dt><b>Postconditions:</b> <code>*this</code> holds the null pointer for the
|
||||||
|
current thread.</dt>
|
||||||
|
<dt><b>Returns:</b> <code>this->get()</code> prior to the call.</dt>
|
||||||
|
</dl>
|
||||||
|
<pre>
|
||||||
|
void reset(T* p=0);
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<dt><b>Effects:</b> If <code>this->get()!= p</code> then <code>delete this->get()</code>.
|
||||||
|
</dt>
|
||||||
|
<dt><b>Postconditions:</b> <code>*this</code> holds the pointer <code> p</code>
|
||||||
|
for the current thread.</dt>
|
||||||
|
<dt><b>Note:</b> The pointer will be deleted when the thread terminates.</dt>
|
||||||
|
</dl>
|
||||||
|
<h4><a name="class-thread_specific_ptr-observers"></a>Class <code>thread_specific_ptr</code>
|
||||||
|
observer functions</h4>
|
||||||
|
<pre>
|
||||||
|
T* get() const;
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<dt><b>Returns:</b> The object stored in thread specific storage for the current
|
||||||
|
thread for <code>*this</code>.</dt>
|
||||||
|
<dt><b>Note:</b> Each thread initially returns 0.</dt>
|
||||||
|
</dl>
|
||||||
|
<pre>
|
||||||
|
T* operator->() const;
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<dt><b>Returns:</b> <code>this-<get()</code>.</dt>
|
||||||
|
</dl>
|
||||||
|
<pre>
|
||||||
|
T& operator*() const;
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<dt><b>Requires:</b> <code>this-<get() != 0</code></dt>
|
||||||
|
<dt><b>Returns:</b> <code>this-<get()</code>.</dt>
|
||||||
|
</dl>
|
||||||
|
<h2><a name="examples"></a>Example(s)</h2>
|
||||||
|
<pre>
|
||||||
|
#include <a href="../../../boost/thread/thread.hpp"><boost/thread/thread.hpp></a>
|
||||||
|
#include <a href="../../../boost/thread/tss.hpp"><boost/thread/tss.hpp></a>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
boost::thread_specific_ptr<int> value;
|
||||||
|
|
||||||
|
void increment()
|
||||||
|
{
|
||||||
|
int* p = value.get();
|
||||||
|
++*p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void thread_proc()
|
||||||
|
{
|
||||||
|
value.reset(new int(0)); // initialize the thread's storage
|
||||||
|
for (int i=0; i<10; ++i)
|
||||||
|
{
|
||||||
|
increment();
|
||||||
|
int* p = value.get();
|
||||||
|
assert(*p == i+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
boost::thread_group threads;
|
||||||
|
for (int i=0; i<5; ++i)
|
||||||
|
threads.create_thread(&thread_proc);
|
||||||
|
threads.join_all();
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
<hr>
|
||||||
|
<p>Revised
|
||||||
|
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
||||||
|
05 November, 2001
|
||||||
|
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
|
||||||
|
</p>
|
||||||
|
<p><i>© Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
|
||||||
|
All Rights Reserved.</i></p>
|
||||||
|
<p>Permission to use, copy, modify, distribute and sell this software and its
|
||||||
|
documentation for any purpose is hereby granted without fee, provided that the
|
||||||
|
above copyright notice appear in all copies and that both that copyright notice
|
||||||
|
and this permission notice appear in supporting documentation. William E. Kempf
|
||||||
|
makes no representations about the suitability of this software for any purpose.
|
||||||
|
It is provided "as is" without express or implied warranty.</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
121
doc/xtime.html
Normal file
121
doc/xtime.html
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||||
|
<link rel="stylesheet" type="text/css" href="../../../boost.css">
|
||||||
|
<title>Boost.Threads - Header <boost/thread/xtime.hpp></title>
|
||||||
|
</head>
|
||||||
|
<body link="#0000ff" vlink="#800080">
|
||||||
|
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
|
||||||
|
"header">
|
||||||
|
<tr>
|
||||||
|
<td valign="top" width="300">
|
||||||
|
<h3><a href="../../../index.htm"><img height="86" width="277" alt="C++ Boost" src="../../../c++boost.gif" border="0"></a></h3>
|
||||||
|
</td>
|
||||||
|
<td valign="top">
|
||||||
|
<h1 align="center">Boost.Threads</h1>
|
||||||
|
<h2 align="center">Header <<a href="../../../boost/thread/xtime.hpp">boost/thread/xtime.hpp</a>></h2>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<hr>
|
||||||
|
<h2>Contents</h2>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="#introduction">Introduction</a></dt>
|
||||||
|
<dt><a href="#values">Values</a></dt>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="#value-spec">TIME_UTC</a></dt>
|
||||||
|
</dl>
|
||||||
|
<dt><a href="#classes">Classes</a></dt>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="#class-spec">Struct <code>xtime</code></a></dt>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="#class-xtime-synopsis">Struct <code>xtime</code> synopsis</a></dt>
|
||||||
|
</dl>
|
||||||
|
</dl>
|
||||||
|
<dt><a href="#functions">Functions</a></dt>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="#function-xtime_get"><code>xtime_get</code></a></dt>
|
||||||
|
</dl>
|
||||||
|
<dt><a href="#examples">Example(s)</a></dt>
|
||||||
|
</dl>
|
||||||
|
<hr>
|
||||||
|
<h2><a name="introduction"></a>Introduction</h2>
|
||||||
|
<p>The header <<a href="../../../boost/thread/xtime.hpp">boost/thread/xtime.hpp</a>>
|
||||||
|
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
|
||||||
|
once available in Boost.</p>
|
||||||
|
<h2><a name="values"></a>Values</h2>
|
||||||
|
<pre><a name="value-spec"></a>
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
TIME_UTC
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
<p>The clock type for Coordinated Universal Time (UTC). The epoch for this clock
|
||||||
|
type is 1970-01-01 00:00:00. This is the only clock type supported by <b>Boost.Threads</b>.</p>
|
||||||
|
<h2><a name="classes"></a>Classes</h2>
|
||||||
|
<h3><a name="class-xtime"></a>Struct <code>xtime</code></h3>
|
||||||
|
<p>The <code>xtime</code> type is used to represent a point on some time scale
|
||||||
|
or a duration in time. This type may be proposed for the C standard by Markus
|
||||||
|
Kuhn. <b>Boost.Threads</b> provides only a very minimal implementation of this
|
||||||
|
proposal and it's expected that a full implementation (or some other time
|
||||||
|
library) will be provided in Boost as a separate library, at which time <b>Boost.Threads</b>
|
||||||
|
will deprecate its implementation.</p>
|
||||||
|
<h4><a name="class-xtime-synopsis"></a>Struct <code>xtime</code> synopsis</h4>
|
||||||
|
<pre>
|
||||||
|
namespace boost
|
||||||
|
{
|
||||||
|
struct xtime
|
||||||
|
{
|
||||||
|
#if defined(BOOST_NO_INT64_T)
|
||||||
|
int_fast32_t sec;
|
||||||
|
#else
|
||||||
|
int_fast64_t sec;
|
||||||
|
#endif
|
||||||
|
int_fast32_t nsec;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
</pre>
|
||||||
|
<h2><a name="functions"></a>Functions</h2>
|
||||||
|
<pre>
|
||||||
|
<a name="function-xtime_get"></a>int xtime_get(struct xtime* xtp, int clock_type);
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<dt><b>Postconditions:</b> <code>xtp</code> represents the current point in
|
||||||
|
time as a duration since the epoch specified by the <code> clock_type</code>.</dt>
|
||||||
|
<dt><b>Returns:</b> <code>clock_type</code> if successful, otherwise 0.</dt>
|
||||||
|
<dt><b>Note:</b> The resolution is implementation specific. For many implementations
|
||||||
|
the best resolution of time is far more than one nanosecond, and even when
|
||||||
|
the resolution is reasonably good, the latency of a call to <code>xtime_get()</code>
|
||||||
|
may be significant. For maximum portability, avoid durations of less than
|
||||||
|
one second.</dt>
|
||||||
|
</dl>
|
||||||
|
<h2><a name="examples"></a>Example(s)</h2>
|
||||||
|
<pre>
|
||||||
|
#include <a href="../../../boost/thread/thread.hpp"><boost/thread/thread.hpp></a>
|
||||||
|
#include <a href="../../../boost/thread/tss.hpp"><boost/thread/xtime.hpp></a>
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
boost::xtime xt;
|
||||||
|
boost::xtime_get(&XT, boost::TIME_UTC);
|
||||||
|
xt.sec += 1;
|
||||||
|
boost::thread::sleep(XT); // Sleep for 1 second
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
<hr>
|
||||||
|
<p>Revised
|
||||||
|
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
||||||
|
05 November, 2001
|
||||||
|
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
|
||||||
|
</p>
|
||||||
|
<p><i>© Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
|
||||||
|
All Rights Reserved.</i></p>
|
||||||
|
<p>Permission to use, copy, modify, distribute and sell this software and its
|
||||||
|
documentation for any purpose is hereby granted without fee, provided that the
|
||||||
|
above copyright notice appear in all copies and that both that copyright notice
|
||||||
|
and this permission notice appear in supporting documentation. William E. Kempf
|
||||||
|
makes no representations about the suitability of this software for any purpose.
|
||||||
|
It is provided "as is" without express or implied warranty.</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
2
example/.cvsignore
Normal file
2
example/.cvsignore
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
bin
|
||||||
|
*.pdb
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
# (C) Copyright William E. Kempf 2001. Permission to copy, use, modify, sell and
|
||||||
|
# distribute this software is granted provided this copyright notice appears
|
||||||
|
# in all copies. This software is provided "as is" without express or implied
|
||||||
|
# warranty, and with no claim as to its suitability for any purpose.
|
||||||
|
#
|
||||||
|
# Boost.Threads build and test Jamfile
|
||||||
|
#
|
||||||
|
# Declares the following targets:
|
||||||
|
# 1. monitor, an example program.
|
||||||
|
# 2. starvephil, an example program.
|
||||||
|
# 3. tennis, an example program.
|
||||||
|
# Additional configuration variables used:
|
||||||
|
# 1. PTW32 may be used on Win32 platforms to specify that the pthreads-win32
|
||||||
|
# library should be used instead of "native" threads. This feature is
|
||||||
|
# mostly used for testing and it's generally recommended you use the
|
||||||
|
# native threading libraries instead. PTW32 should be set to be a list
|
||||||
|
# of two strings, the first specifying the installation path of the
|
||||||
|
# pthreads-win32 library and the second specifying which library
|
||||||
|
# variant to link against (see the pthreads-win32 documentation).
|
||||||
|
# Example: jam -sPTW32="c:\pthreads-win32 pthreadVCE.lib"
|
||||||
|
|
||||||
|
# Declare the location of this subproject relative to the root.
|
||||||
|
subproject libs/thread/example ;
|
||||||
|
|
||||||
|
# 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 ;
|
||||||
|
|
||||||
|
#######################
|
||||||
|
# Declare the Boost.Threads example program monitor.
|
||||||
|
|
||||||
|
exe monitor
|
||||||
|
: monitor/monitor.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 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
|
||||||
|
;
|
||||||
|
|||||||
1
example/monitor/Carbon.r
Normal file
1
example/monitor/Carbon.r
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/*
|
||||||
106
example/monitor/monitor.cpp
Normal file
106
example/monitor/monitor.cpp
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
#include <vector>
|
||||||
|
#include <iostream>
|
||||||
|
#include <boost/thread/condition.hpp>
|
||||||
|
#include <boost/thread/mutex.hpp>
|
||||||
|
#include <boost/thread/recursive_mutex.hpp>
|
||||||
|
#include <boost/thread/thread.hpp>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
const int ITERS = 100;
|
||||||
|
boost::mutex io_mutex;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename M>
|
||||||
|
class buffer_t
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef typename M::scoped_lock scoped_lock;
|
||||||
|
|
||||||
|
buffer_t(int n)
|
||||||
|
: p(0), c(0), full(0), buf(n)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void send(int m)
|
||||||
|
{
|
||||||
|
scoped_lock lk(mutex);
|
||||||
|
while (full == buf.size())
|
||||||
|
cond.wait(lk);
|
||||||
|
buf[p] = m;
|
||||||
|
p = (p+1) % buf.size();
|
||||||
|
++full;
|
||||||
|
cond.notify_one();
|
||||||
|
}
|
||||||
|
int receive()
|
||||||
|
{
|
||||||
|
scoped_lock lk(mutex);
|
||||||
|
while (full == 0)
|
||||||
|
cond.wait(lk);
|
||||||
|
int i = buf[c];
|
||||||
|
c = (c+1) % buf.size();
|
||||||
|
--full;
|
||||||
|
cond.notify_one();
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
static buffer_t& get_buffer()
|
||||||
|
{
|
||||||
|
static buffer_t buf(2);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void do_sender_thread()
|
||||||
|
{
|
||||||
|
for (int n = 0; n < ITERS; ++n)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(io_mutex);
|
||||||
|
std::cout << "sending: " << n << std::endl;
|
||||||
|
}
|
||||||
|
get_buffer().send(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void do_receiver_thread()
|
||||||
|
{
|
||||||
|
for (int x=0; x < (ITERS/2); ++x)
|
||||||
|
{
|
||||||
|
int n = get_buffer().receive();
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(io_mutex);
|
||||||
|
std::cout << "received: " << n << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
M mutex;
|
||||||
|
boost::condition cond;
|
||||||
|
unsigned int p, c, full;
|
||||||
|
std::vector<int> buf;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename M>
|
||||||
|
void do_test(M* dummy=0)
|
||||||
|
{
|
||||||
|
typedef buffer_t<M> buffer_type;
|
||||||
|
buffer_type::get_buffer();
|
||||||
|
boost::thread thrd1(&buffer_type::do_receiver_thread);
|
||||||
|
boost::thread thrd2(&buffer_type::do_receiver_thread);
|
||||||
|
boost::thread thrd3(&buffer_type::do_sender_thread);
|
||||||
|
thrd1.join();
|
||||||
|
thrd2.join();
|
||||||
|
thrd3.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_buffer()
|
||||||
|
{
|
||||||
|
do_test<boost::mutex>();
|
||||||
|
do_test<boost::recursive_mutex>();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
test_buffer();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
BIN
example/monitor/monitor.mcp
Normal file
BIN
example/monitor/monitor.mcp
Normal file
Binary file not shown.
1
example/starvephil/Carbon.r
Normal file
1
example/starvephil/Carbon.r
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/*
|
||||||
171
example/starvephil/starvephil.cpp
Normal file
171
example/starvephil/starvephil.cpp
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
#include <boost/thread/mutex.hpp>
|
||||||
|
#include <boost/thread/condition.hpp>
|
||||||
|
#include <boost/thread/thread.hpp>
|
||||||
|
#include <boost/thread/xtime.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
boost::mutex iomx;
|
||||||
|
}
|
||||||
|
|
||||||
|
class canteen
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
canteen() : m_chickens(0) { }
|
||||||
|
|
||||||
|
void get(int id)
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(m_mutex);
|
||||||
|
while (m_chickens == 0)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(iomx);
|
||||||
|
std::cout << "(" << clock() << ") Phil" << id <<
|
||||||
|
": wot, no chickens? I'll WAIT ..." << std::endl;
|
||||||
|
}
|
||||||
|
m_condition.wait(lock);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(iomx);
|
||||||
|
std::cout << "(" << clock() << ") Phil" << id <<
|
||||||
|
": those chickens look good ... one please ..." << std::endl;
|
||||||
|
}
|
||||||
|
m_chickens--;
|
||||||
|
}
|
||||||
|
void put(int value)
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(m_mutex);
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(iomx);
|
||||||
|
std::cout << "(" << clock() <<
|
||||||
|
") Chef: ouch ... make room ... this dish is very hot ..." << std::endl;
|
||||||
|
}
|
||||||
|
boost::xtime xt;
|
||||||
|
boost::xtime_get(&xt, boost::TIME_UTC);
|
||||||
|
xt.sec += 3;
|
||||||
|
boost::thread::sleep(xt);
|
||||||
|
m_chickens += value;
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(iomx);
|
||||||
|
std::cout << "(" << clock() <<
|
||||||
|
") Chef: more chickens ... " << m_chickens <<
|
||||||
|
" now available ... NOTIFYING ..." << std::endl;
|
||||||
|
}
|
||||||
|
m_condition.notify_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
boost::mutex m_mutex;
|
||||||
|
boost::condition m_condition;
|
||||||
|
int m_chickens;
|
||||||
|
};
|
||||||
|
|
||||||
|
canteen g_canteen;
|
||||||
|
|
||||||
|
void chef()
|
||||||
|
{
|
||||||
|
const int chickens = 4;
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(iomx);
|
||||||
|
std::cout << "(" << clock() << ") Chef: starting ..." << std::endl;
|
||||||
|
}
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(iomx);
|
||||||
|
std::cout << "(" << clock() << ") Chef: cooking ..." << std::endl;
|
||||||
|
}
|
||||||
|
boost::xtime xt;
|
||||||
|
boost::xtime_get(&xt, boost::TIME_UTC);
|
||||||
|
xt.sec += 2;
|
||||||
|
boost::thread::sleep(xt);
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(iomx);
|
||||||
|
std::cout << "(" << clock() << ") Chef: " << chickens
|
||||||
|
<< " chickens, ready-to-go ..." << std::endl;
|
||||||
|
}
|
||||||
|
g_canteen.put(chickens);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct phil
|
||||||
|
{
|
||||||
|
phil(int id) : m_id(id) { }
|
||||||
|
void run() {
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(iomx);
|
||||||
|
std::cout << "(" << clock() << ") Phil" << m_id << ": starting ..." << std::endl;
|
||||||
|
}
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
if (m_id > 0)
|
||||||
|
{
|
||||||
|
boost::xtime xt;
|
||||||
|
boost::xtime_get(&xt, boost::TIME_UTC);
|
||||||
|
xt.sec += 3;
|
||||||
|
boost::thread::sleep(xt);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(iomx);
|
||||||
|
std::cout << "(" << clock() << ") Phil" << m_id
|
||||||
|
<< ": gotta eat ..." << std::endl;
|
||||||
|
}
|
||||||
|
g_canteen.get(m_id);
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(iomx);
|
||||||
|
std::cout << "(" << clock() << ") Phil" << m_id
|
||||||
|
<< ": mmm ... that's good ..." << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void do_thread(void* param) {
|
||||||
|
static_cast<phil*>(param)->run();
|
||||||
|
}
|
||||||
|
|
||||||
|
int m_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct thread_adapt
|
||||||
|
{
|
||||||
|
thread_adapt(void (*func)(void*), void* param) : _func(func), _param(param) { }
|
||||||
|
int operator()() const
|
||||||
|
{
|
||||||
|
_func(_param);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void (*_func)(void*);
|
||||||
|
void* _param;
|
||||||
|
};
|
||||||
|
|
||||||
|
class thread_adapter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
thread_adapter(void (*func)(void*), void* param) : _func(func), _param(param) { }
|
||||||
|
void operator()() const { _func(_param); }
|
||||||
|
private:
|
||||||
|
void (*_func)(void*);
|
||||||
|
void* _param;
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
boost::thread thrd_chef(&chef);
|
||||||
|
phil p[] = { phil(0), phil(1), phil(2), phil(3), phil(4) };
|
||||||
|
boost::thread thrd_phil0(thread_adapter(&phil::do_thread, &p[0]));
|
||||||
|
boost::thread thrd_phil1(thread_adapter(&phil::do_thread, &p[1]));
|
||||||
|
boost::thread thrd_phil2(thread_adapter(&phil::do_thread, &p[2]));
|
||||||
|
boost::thread thrd_phil3(thread_adapter(&phil::do_thread, &p[3]));
|
||||||
|
boost::thread thrd_phil4(thread_adapter(&phil::do_thread, &p[4]));
|
||||||
|
|
||||||
|
thrd_chef.join();
|
||||||
|
thrd_phil0.join();
|
||||||
|
thrd_phil1.join();
|
||||||
|
thrd_phil2.join();
|
||||||
|
thrd_phil3.join();
|
||||||
|
thrd_phil4.join();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
BIN
example/starvephil/starvephil.mcp
Normal file
BIN
example/starvephil/starvephil.mcp
Normal file
Binary file not shown.
1
example/tennis/Carbon.r
Normal file
1
example/tennis/Carbon.r
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/*
|
||||||
120
example/tennis/tennis.cpp
Normal file
120
example/tennis/tennis.cpp
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
#include <boost/thread/mutex.hpp>
|
||||||
|
#include <boost/thread/condition.hpp>
|
||||||
|
#include <boost/thread/thread.hpp>
|
||||||
|
#include <boost/thread/xtime.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
# include <windows.h>
|
||||||
|
# include <process.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum game_state
|
||||||
|
{
|
||||||
|
START,
|
||||||
|
PLAYER_A,
|
||||||
|
PLAYER_B,
|
||||||
|
GAME_OVER,
|
||||||
|
ONE_PLAYER_GONE,
|
||||||
|
BOTH_PLAYERS_GONE
|
||||||
|
};
|
||||||
|
|
||||||
|
int state;
|
||||||
|
boost::mutex mutex;
|
||||||
|
boost::condition cond;
|
||||||
|
|
||||||
|
char* player_name(int state)
|
||||||
|
{
|
||||||
|
if (state == PLAYER_A)
|
||||||
|
return "PLAYER-A";
|
||||||
|
if (state == PLAYER_B)
|
||||||
|
return "PLAYER-B";
|
||||||
|
throw "bad player";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void player(void* param)
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(mutex);
|
||||||
|
|
||||||
|
int active = (int)param;
|
||||||
|
int other = active == PLAYER_A ? PLAYER_B : PLAYER_A;
|
||||||
|
|
||||||
|
while (state < GAME_OVER)
|
||||||
|
{
|
||||||
|
std::cout << player_name(active) << ": Play." << std::endl;
|
||||||
|
state = other;
|
||||||
|
cond.notify_all();
|
||||||
|
do
|
||||||
|
{
|
||||||
|
cond.wait(lock);
|
||||||
|
if (state == other)
|
||||||
|
std::cout << "---" << player_name(active) << ": Spurious wakeup!" << std::endl;
|
||||||
|
} while (state == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
++state;
|
||||||
|
std::cout << player_name(active) << ": Gone." << std::endl;
|
||||||
|
cond.notify_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct thread_adapt
|
||||||
|
{
|
||||||
|
thread_adapt(void (*func)(void*), void* param) : _func(func), _param(param) { }
|
||||||
|
int operator()() const
|
||||||
|
{
|
||||||
|
_func(_param);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void (*_func)(void*);
|
||||||
|
void* _param;
|
||||||
|
};
|
||||||
|
|
||||||
|
class thread_adapter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
thread_adapter(void (*func)(void*), void* param) : _func(func), _param(param) { }
|
||||||
|
void operator()() const { _func(_param); }
|
||||||
|
private:
|
||||||
|
void (*_func)(void*);
|
||||||
|
void* _param;
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
state = START;
|
||||||
|
|
||||||
|
boost::thread thrda(thread_adapter(&player, (void*)PLAYER_A));
|
||||||
|
boost::thread thrdb(thread_adapter(&player, (void*)PLAYER_B));
|
||||||
|
|
||||||
|
boost::xtime xt;
|
||||||
|
boost::xtime_get(&xt, boost::TIME_UTC);
|
||||||
|
xt.sec += 1;
|
||||||
|
boost::thread::sleep(xt);
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(mutex);
|
||||||
|
std::cout << "---Noise ON..." << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 1000000; ++i)
|
||||||
|
cond.notify_all();
|
||||||
|
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(mutex);
|
||||||
|
std::cout << "---Noise OFF..." << std::endl;
|
||||||
|
state = GAME_OVER;
|
||||||
|
cond.notify_all();
|
||||||
|
do
|
||||||
|
{
|
||||||
|
cond.wait(lock);
|
||||||
|
} while (state != BOTH_PLAYERS_GONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "GAME OVER" << std::endl;
|
||||||
|
|
||||||
|
thrda.join();
|
||||||
|
thrdb.join();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
BIN
example/tennis/tennis.mcp
Normal file
BIN
example/tennis/tennis.mcp
Normal file
Binary file not shown.
170
include/boost/thread/condition.hpp
Normal file
170
include/boost/thread/condition.hpp
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// William E. Kempf
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
|
// and its documentation for any purpose is hereby granted without fee,
|
||||||
|
// provided that the above copyright notice appear in all copies and
|
||||||
|
// that both that copyright notice and this permission notice appear
|
||||||
|
// in supporting documentation. 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_CONDITION_WEK070601_HPP
|
||||||
|
#define BOOST_CONDITION_WEK070601_HPP
|
||||||
|
|
||||||
|
#include <boost/config.hpp>
|
||||||
|
#ifndef BOOST_HAS_THREADS
|
||||||
|
# error Thread support is unavailable!
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <boost/thread/exceptions.hpp>
|
||||||
|
#include <boost/utility.hpp>
|
||||||
|
#include <boost/thread/detail/lock.hpp>
|
||||||
|
|
||||||
|
#if defined(BOOST_HAS_PTHREADS)
|
||||||
|
# include <pthread.h>
|
||||||
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
|
# include "scoped_critical_region.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
struct xtime;
|
||||||
|
|
||||||
|
class condition : private noncopyable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
condition();
|
||||||
|
~condition();
|
||||||
|
|
||||||
|
void notify_one();
|
||||||
|
void notify_all();
|
||||||
|
|
||||||
|
template <typename L>
|
||||||
|
void wait(L& lock)
|
||||||
|
{
|
||||||
|
if (!lock)
|
||||||
|
throw lock_error();
|
||||||
|
|
||||||
|
do_wait(lock.m_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename L, typename Pr>
|
||||||
|
void wait(L& lock, Pr pred)
|
||||||
|
{
|
||||||
|
if (!lock)
|
||||||
|
throw lock_error();
|
||||||
|
|
||||||
|
while (!pred())
|
||||||
|
do_wait(lock.m_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename L>
|
||||||
|
bool timed_wait(L& lock, const xtime& xt)
|
||||||
|
{
|
||||||
|
if (!lock)
|
||||||
|
throw lock_error();
|
||||||
|
|
||||||
|
return do_timed_wait(lock.m_mutex, xt);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename L, typename Pr>
|
||||||
|
bool timed_wait(L& lock, const xtime& xt, Pr pred)
|
||||||
|
{
|
||||||
|
if (!lock)
|
||||||
|
throw lock_error();
|
||||||
|
|
||||||
|
while (!pred())
|
||||||
|
{
|
||||||
|
if (!do_timed_wait(lock.m_mutex, xt))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <typename M>
|
||||||
|
void do_wait(M& mutex)
|
||||||
|
{
|
||||||
|
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||||
|
enter_wait();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef typename detail::thread::lock_ops<M> lock_ops;
|
||||||
|
typename lock_ops::lock_state state;
|
||||||
|
lock_ops::unlock(mutex, state);
|
||||||
|
|
||||||
|
#if defined(BOOST_HAS_PTHREADS)
|
||||||
|
do_wait(state.pmutex);
|
||||||
|
#elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||||
|
do_wait();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
lock_ops::lock(mutex, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename M>
|
||||||
|
bool do_timed_wait(M& mutex, const xtime& xt)
|
||||||
|
{
|
||||||
|
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||||
|
enter_wait();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef typename detail::thread::lock_ops<M> lock_ops;
|
||||||
|
typename lock_ops::lock_state state;
|
||||||
|
lock_ops::unlock(mutex, state);
|
||||||
|
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
|
#if defined(BOOST_HAS_PTHREADS)
|
||||||
|
ret = do_timed_wait(xt, state.pmutex);
|
||||||
|
#elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||||
|
ret = do_timed_wait(xt);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
lock_ops::lock(mutex, state);
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
// Change Log:
|
||||||
|
// 8 Feb 01 WEKEMPF Initial version.
|
||||||
|
// 22 May 01 WEKEMPF Modified to use xtime for time outs.
|
||||||
|
// 23 May 01 WEKEMPF Removed "duration" timed_waits, as they are too difficult
|
||||||
|
// to use with spurious wakeups.
|
||||||
|
|
||||||
|
#endif // BOOST_CONDITION_WEK070601_HPP
|
||||||
44
include/boost/thread/detail/force_cast.hpp
Normal file
44
include/boost/thread/detail/force_cast.hpp
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// Mac Murrett
|
||||||
|
//
|
||||||
|
// 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. Mac Murrett makes no representations
|
||||||
|
// about the suitability of this software for any purpose. It is
|
||||||
|
// provided "as is" without express or implied warranty.
|
||||||
|
//
|
||||||
|
// See http://www.boost.org for most recent version including documentation.
|
||||||
|
|
||||||
|
#ifndef BOOST_FORCE_CAST_MJM012402_HPP
|
||||||
|
#define BOOST_FORCE_CAST_MJM012402_HPP
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
namespace thread {
|
||||||
|
|
||||||
|
|
||||||
|
// force_cast will convert anything to anything.
|
||||||
|
|
||||||
|
// general case
|
||||||
|
template<class Return_Type, class Argument_Type>
|
||||||
|
inline Return_Type &force_cast(Argument_Type &rSrc)
|
||||||
|
{ return(*reinterpret_cast<Return_Type *>(&rSrc)); }
|
||||||
|
|
||||||
|
// specialization for const
|
||||||
|
template<class Return_Type, class Argument_Type>
|
||||||
|
inline const Return_Type &force_cast(const Argument_Type &rSrc)
|
||||||
|
{ return(*reinterpret_cast<const Return_Type *>(&rSrc)); }
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace thread
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BOOST_FORCE_CAST_MJM012402_HPP
|
||||||
207
include/boost/thread/detail/lock.hpp
Normal file
207
include/boost/thread/detail/lock.hpp
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// William E. Kempf
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
|
// and its documentation for any purpose is hereby granted without fee,
|
||||||
|
// provided that the above copyright notice appear in all copies and
|
||||||
|
// that both that copyright notice and this permission notice appear
|
||||||
|
// in supporting documentation. 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_XLOCK_WEK070601_HPP
|
||||||
|
#define BOOST_XLOCK_WEK070601_HPP
|
||||||
|
|
||||||
|
#include <boost/utility.hpp>
|
||||||
|
#include <boost/thread/exceptions.hpp>
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
class condition;
|
||||||
|
struct xtime;
|
||||||
|
|
||||||
|
namespace detail { namespace thread {
|
||||||
|
|
||||||
|
template <typename Mutex>
|
||||||
|
class lock_ops : private noncopyable
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
lock_ops() { }
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef typename Mutex::cv_state lock_state;
|
||||||
|
|
||||||
|
static void lock(Mutex& m)
|
||||||
|
{
|
||||||
|
m.do_lock();
|
||||||
|
}
|
||||||
|
static bool trylock(Mutex& m)
|
||||||
|
{
|
||||||
|
return m.do_trylock();
|
||||||
|
}
|
||||||
|
static bool timedlock(Mutex& m, const xtime& xt)
|
||||||
|
{
|
||||||
|
return m.do_timedlock(xt);
|
||||||
|
}
|
||||||
|
static void unlock(Mutex& m)
|
||||||
|
{
|
||||||
|
m.do_unlock();
|
||||||
|
}
|
||||||
|
static void lock(Mutex& m, lock_state& state)
|
||||||
|
{
|
||||||
|
m.do_lock(state);
|
||||||
|
}
|
||||||
|
static void unlock(Mutex& m, lock_state& state)
|
||||||
|
{
|
||||||
|
m.do_unlock(state);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Mutex>
|
||||||
|
class scoped_lock : private noncopyable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef Mutex mutex_type;
|
||||||
|
|
||||||
|
explicit scoped_lock(Mutex& mx, bool initially_locked=true)
|
||||||
|
: m_mutex(mx), m_locked(false)
|
||||||
|
{
|
||||||
|
if (initially_locked) lock();
|
||||||
|
}
|
||||||
|
~scoped_lock()
|
||||||
|
{
|
||||||
|
if (m_locked) unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void lock()
|
||||||
|
{
|
||||||
|
if (m_locked) throw lock_error();
|
||||||
|
lock_ops<Mutex>::lock(m_mutex);
|
||||||
|
m_locked = true;
|
||||||
|
}
|
||||||
|
void unlock()
|
||||||
|
{
|
||||||
|
if (!m_locked) throw lock_error();
|
||||||
|
lock_ops<Mutex>::unlock(m_mutex);
|
||||||
|
m_locked = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool locked() const { return m_locked; }
|
||||||
|
operator const void*() const { return m_locked ? this : 0; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class boost::condition;
|
||||||
|
|
||||||
|
Mutex& m_mutex;
|
||||||
|
bool m_locked;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename TryMutex>
|
||||||
|
class scoped_try_lock : private noncopyable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef TryMutex mutex_type;
|
||||||
|
|
||||||
|
explicit scoped_try_lock(TryMutex& mx)
|
||||||
|
: m_mutex(mx), m_locked(false)
|
||||||
|
{
|
||||||
|
try_lock();
|
||||||
|
}
|
||||||
|
scoped_try_lock(TryMutex& mx, bool initially_locked)
|
||||||
|
: m_mutex(mx), m_locked(false)
|
||||||
|
{
|
||||||
|
if (initially_locked) lock();
|
||||||
|
}
|
||||||
|
~scoped_try_lock()
|
||||||
|
{
|
||||||
|
if (m_locked) unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void lock()
|
||||||
|
{
|
||||||
|
if (m_locked) throw lock_error();
|
||||||
|
lock_ops<TryMutex>::lock(m_mutex);
|
||||||
|
m_locked = true;
|
||||||
|
}
|
||||||
|
bool try_lock()
|
||||||
|
{
|
||||||
|
if (m_locked) throw lock_error();
|
||||||
|
return (m_locked = lock_ops<TryMutex>::trylock(m_mutex));
|
||||||
|
}
|
||||||
|
void unlock()
|
||||||
|
{
|
||||||
|
if (!m_locked) throw lock_error();
|
||||||
|
lock_ops<TryMutex>::unlock(m_mutex);
|
||||||
|
m_locked = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool locked() const { return m_locked; }
|
||||||
|
operator const void*() const { return m_locked ? this : 0; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class boost::condition;
|
||||||
|
|
||||||
|
TryMutex& m_mutex;
|
||||||
|
bool m_locked;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename TimedMutex>
|
||||||
|
class scoped_timed_lock : private noncopyable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef TimedMutex mutex_type;
|
||||||
|
|
||||||
|
scoped_timed_lock(TimedMutex& mx, const xtime& xt)
|
||||||
|
: m_mutex(mx), m_locked(false)
|
||||||
|
{
|
||||||
|
timed_lock(xt);
|
||||||
|
}
|
||||||
|
scoped_timed_lock(TimedMutex& mx, bool initially_locked)
|
||||||
|
: m_mutex(mx), m_locked(false)
|
||||||
|
{
|
||||||
|
if (initially_locked) lock();
|
||||||
|
}
|
||||||
|
~scoped_timed_lock()
|
||||||
|
{
|
||||||
|
if (m_locked) unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void lock()
|
||||||
|
{
|
||||||
|
if (m_locked) throw lock_error();
|
||||||
|
lock_ops<TimedMutex>::lock(m_mutex);
|
||||||
|
m_locked = true;
|
||||||
|
}
|
||||||
|
bool timed_lock(const xtime& xt)
|
||||||
|
{
|
||||||
|
if (m_locked) throw lock_error();
|
||||||
|
return (m_locked = lock_ops<TimedMutex>::timedlock(m_mutex, xt));
|
||||||
|
}
|
||||||
|
void unlock()
|
||||||
|
{
|
||||||
|
if (!m_locked) throw lock_error();
|
||||||
|
lock_ops<TimedMutex>::unlock(m_mutex);
|
||||||
|
m_locked = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool locked() const { return m_locked; }
|
||||||
|
operator const void*() const { return m_locked ? this : 0; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class boost::condition;
|
||||||
|
|
||||||
|
TimedMutex& m_mutex;
|
||||||
|
bool m_locked;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace thread
|
||||||
|
} // namespace detail
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
// Change Log:
|
||||||
|
// 8 Feb 01 WEKEMPF Initial version.
|
||||||
|
// 22 May 01 WEKEMPF Modified to use xtime for time outs.
|
||||||
|
// 30 Jul 01 WEKEMPF Moved lock types into boost::detail::thread. Renamed some types.
|
||||||
|
// Added locked() methods.
|
||||||
|
|
||||||
|
#endif // BOOST_XLOCK_WEK070601_HPP
|
||||||
64
include/boost/thread/detail/singleton.hpp
Normal file
64
include/boost/thread/detail/singleton.hpp
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// Mac Murrett
|
||||||
|
//
|
||||||
|
// 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. Mac Murrett makes no representations
|
||||||
|
// about the suitability of this software for any purpose. It is
|
||||||
|
// provided "as is" without express or implied warranty.
|
||||||
|
//
|
||||||
|
// See http://www.boost.org for most recent version including documentation.
|
||||||
|
|
||||||
|
#ifndef BOOST_SINGLETON_MJM012402_HPP
|
||||||
|
#define BOOST_SINGLETON_MJM012402_HPP
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
namespace thread {
|
||||||
|
|
||||||
|
// class singleton has the same goal as all singletons: create one instance of a
|
||||||
|
// class on demand, then dish it out as requested.
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
class singleton: private T
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
singleton();
|
||||||
|
~singleton();
|
||||||
|
|
||||||
|
public:
|
||||||
|
static T &instance();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
inline singleton<T>::singleton()
|
||||||
|
{ /* no-op */ }
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
inline singleton<T>::~singleton()
|
||||||
|
{ /* no-op */ }
|
||||||
|
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
/*static*/ T &singleton<T>::instance()
|
||||||
|
{
|
||||||
|
// function-local static to force this to work correctly at static initialization
|
||||||
|
// time.
|
||||||
|
static singleton<T> s_oT;
|
||||||
|
return(s_oT);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace thread
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BOOST_SINGLETON_MJM012402_HPP
|
||||||
39
include/boost/thread/exceptions.hpp
Normal file
39
include/boost/thread/exceptions.hpp
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// William E. Kempf
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
|
// and its documentation for any purpose is hereby granted without fee,
|
||||||
|
// provided that the above copyright notice appear in all copies and
|
||||||
|
// that both that copyright notice and this permission notice appear
|
||||||
|
// in supporting documentation. 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_EXCEPTIONS_PDM070801_H
|
||||||
|
#define BOOST_THREAD_EXCEPTIONS_PDM070801_H
|
||||||
|
|
||||||
|
// pdm: Sorry, but this class is used all over the place & I end up
|
||||||
|
// with recursive headers if I don't separate it
|
||||||
|
// wek: Not sure why recursive headers would cause compilation problems
|
||||||
|
// given the include guards, but regardless it makes sense to
|
||||||
|
// seperate this out any way.
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
class lock_error : public std::logic_error
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
lock_error();
|
||||||
|
};
|
||||||
|
|
||||||
|
class thread_resource_error : public std::runtime_error
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
thread_resource_error();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
#endif // BOOST_THREAD_CONFIG_PDM070801_H
|
||||||
164
include/boost/thread/mutex.hpp
Normal file
164
include/boost/thread/mutex.hpp
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// William E. Kempf
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
|
// and its documentation for any purpose is hereby granted without fee,
|
||||||
|
// provided that the above copyright notice appear in all copies and
|
||||||
|
// that both that copyright notice and this permission notice appear
|
||||||
|
// in supporting documentation. William E. Kempf makes no representations
|
||||||
|
// about the suitability of this software for any purpose.
|
||||||
|
// It is provided "as is" without express or implied warranty.
|
||||||
|
|
||||||
|
#ifndef BOOST_MUTEX_WEK070601_HPP
|
||||||
|
#define BOOST_MUTEX_WEK070601_HPP
|
||||||
|
|
||||||
|
#include <boost/config.hpp>
|
||||||
|
#ifndef BOOST_HAS_THREADS
|
||||||
|
# error Thread support is unavailable!
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <boost/utility.hpp>
|
||||||
|
#include <boost/thread/detail/lock.hpp>
|
||||||
|
|
||||||
|
#if defined(BOOST_HAS_PTHREADS)
|
||||||
|
# include <pthread.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(BOOST_HAS_MPTASKS)
|
||||||
|
# include "scoped_critical_region.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
struct xtime;
|
||||||
|
|
||||||
|
class mutex : private noncopyable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
friend class detail::thread::lock_ops<mutex>;
|
||||||
|
|
||||||
|
typedef detail::thread::scoped_lock<mutex> scoped_lock;
|
||||||
|
|
||||||
|
mutex();
|
||||||
|
~mutex();
|
||||||
|
|
||||||
|
private:
|
||||||
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
typedef void* cv_state;
|
||||||
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
|
struct cv_state
|
||||||
|
{
|
||||||
|
pthread_mutex_t* pmutex;
|
||||||
|
};
|
||||||
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
|
struct cv_state
|
||||||
|
{
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
void do_lock();
|
||||||
|
void do_unlock();
|
||||||
|
void do_lock(cv_state& state);
|
||||||
|
void do_unlock(cv_state& state);
|
||||||
|
|
||||||
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
void* m_mutex;
|
||||||
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
|
pthread_mutex_t m_mutex;
|
||||||
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
|
threads::mac::detail::scoped_critical_region m_mutex;
|
||||||
|
threads::mac::detail::scoped_critical_region m_mutex_mutex;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
class try_mutex : private noncopyable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
friend class detail::thread::lock_ops<try_mutex>;
|
||||||
|
|
||||||
|
typedef detail::thread::scoped_lock<try_mutex> scoped_lock;
|
||||||
|
typedef detail::thread::scoped_try_lock<try_mutex> scoped_try_lock;
|
||||||
|
|
||||||
|
try_mutex();
|
||||||
|
~try_mutex();
|
||||||
|
|
||||||
|
private:
|
||||||
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
typedef void* cv_state;
|
||||||
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
|
struct cv_state
|
||||||
|
{
|
||||||
|
pthread_mutex_t* pmutex;
|
||||||
|
};
|
||||||
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
|
struct cv_state
|
||||||
|
{
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
void do_lock();
|
||||||
|
bool do_trylock();
|
||||||
|
void do_unlock();
|
||||||
|
void do_lock(cv_state& state);
|
||||||
|
void do_unlock(cv_state& state);
|
||||||
|
|
||||||
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
void* m_mutex;
|
||||||
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
|
pthread_mutex_t m_mutex;
|
||||||
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
|
threads::mac::detail::scoped_critical_region m_mutex;
|
||||||
|
threads::mac::detail::scoped_critical_region m_mutex_mutex;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
class timed_mutex : private noncopyable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
friend class detail::thread::lock_ops<timed_mutex>;
|
||||||
|
|
||||||
|
typedef detail::thread::scoped_lock<timed_mutex> scoped_lock;
|
||||||
|
typedef detail::thread::scoped_try_lock<timed_mutex> scoped_try_lock;
|
||||||
|
typedef detail::thread::scoped_timed_lock<timed_mutex> scoped_timed_lock;
|
||||||
|
|
||||||
|
timed_mutex();
|
||||||
|
~timed_mutex();
|
||||||
|
|
||||||
|
private:
|
||||||
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
typedef void* cv_state;
|
||||||
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
|
struct cv_state
|
||||||
|
{
|
||||||
|
pthread_mutex_t* pmutex;
|
||||||
|
};
|
||||||
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
|
struct cv_state
|
||||||
|
{
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
void do_lock();
|
||||||
|
bool do_trylock();
|
||||||
|
bool do_timedlock(const xtime& xt);
|
||||||
|
void do_unlock();
|
||||||
|
void do_lock(cv_state& state);
|
||||||
|
void do_unlock(cv_state& state);
|
||||||
|
|
||||||
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
void* m_mutex;
|
||||||
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
|
pthread_mutex_t m_mutex;
|
||||||
|
pthread_cond_t m_condition;
|
||||||
|
bool m_locked;
|
||||||
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
|
threads::mac::detail::scoped_critical_region m_mutex;
|
||||||
|
threads::mac::detail::scoped_critical_region m_mutex_mutex;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
// Change Log:
|
||||||
|
// 8 Feb 01 WEKEMPF Initial version.
|
||||||
|
// 22 May 01 WEKEMPF Modified to use xtime for time outs. Factored out
|
||||||
|
// to three classes, mutex, try_mutex and timed_mutex.
|
||||||
|
|
||||||
|
#endif // BOOST_MUTEX_WEK070601_HPP
|
||||||
45
include/boost/thread/once.hpp
Normal file
45
include/boost/thread/once.hpp
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// William E. Kempf
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
|
// and its documentation for any purpose is hereby granted without fee,
|
||||||
|
// provided that the above copyright notice appear in all copies and
|
||||||
|
// that both that copyright notice and this permission notice appear
|
||||||
|
// in supporting documentation. 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_ONCE_WEK080101_HPP
|
||||||
|
#define BOOST_ONCE_WEK080101_HPP
|
||||||
|
|
||||||
|
#include <boost/config.hpp>
|
||||||
|
#ifndef BOOST_HAS_THREADS
|
||||||
|
# error Thread support is unavailable!
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(BOOST_HAS_PTHREADS)
|
||||||
|
# include <pthread.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
#if defined(BOOST_HAS_PTHREADS)
|
||||||
|
|
||||||
|
typedef pthread_once_t once_flag;
|
||||||
|
#define BOOST_ONCE_INIT PTHREAD_ONCE_INIT
|
||||||
|
|
||||||
|
#elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||||
|
|
||||||
|
typedef bool once_flag;
|
||||||
|
#define BOOST_ONCE_INIT false
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void call_once(void (*func)(), once_flag& flag);
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
// Change Log:
|
||||||
|
// 1 Aug 01 WEKEMPF Initial version.
|
||||||
|
|
||||||
|
#endif // BOOST_ONCE_WEK080101_HPP
|
||||||
174
include/boost/thread/recursive_mutex.hpp
Normal file
174
include/boost/thread/recursive_mutex.hpp
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// William E. Kempf
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
|
// and its documentation for any purpose is hereby granted without fee,
|
||||||
|
// provided that the above copyright notice appear in all copies and
|
||||||
|
// that both that copyright notice and this permission notice appear
|
||||||
|
// in supporting documentation. 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_RECURSIVE_MUTEX_WEK070601_HPP
|
||||||
|
#define BOOST_RECURSIVE_MUTEX_WEK070601_HPP
|
||||||
|
|
||||||
|
#include <boost/config.hpp>
|
||||||
|
#ifndef BOOST_HAS_THREADS
|
||||||
|
# error Thread support is unavailable!
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <boost/utility.hpp>
|
||||||
|
#include <boost/thread/detail/lock.hpp>
|
||||||
|
|
||||||
|
#if defined(BOOST_HAS_PTHREADS)
|
||||||
|
# include <pthread.h>
|
||||||
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
|
# include "scoped_critical_region.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
struct xtime;
|
||||||
|
|
||||||
|
class recursive_mutex : private noncopyable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
friend class detail::thread::lock_ops<recursive_mutex>;
|
||||||
|
|
||||||
|
typedef detail::thread::scoped_lock<recursive_mutex> scoped_lock;
|
||||||
|
|
||||||
|
recursive_mutex();
|
||||||
|
~recursive_mutex();
|
||||||
|
|
||||||
|
private:
|
||||||
|
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||||
|
typedef std::size_t cv_state;
|
||||||
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
|
struct cv_state
|
||||||
|
{
|
||||||
|
long count;
|
||||||
|
pthread_mutex_t* pmutex;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
void do_lock();
|
||||||
|
void do_unlock();
|
||||||
|
void do_lock(cv_state& state);
|
||||||
|
void do_unlock(cv_state& state);
|
||||||
|
|
||||||
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
void* m_mutex;
|
||||||
|
unsigned long m_count;
|
||||||
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
|
pthread_mutex_t m_mutex;
|
||||||
|
unsigned m_count;
|
||||||
|
# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
|
||||||
|
pthread_cond_t m_unlocked;
|
||||||
|
pthread_t m_thread_id;
|
||||||
|
bool m_valid_id;
|
||||||
|
# endif
|
||||||
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
|
threads::mac::detail::scoped_critical_region m_mutex;
|
||||||
|
threads::mac::detail::scoped_critical_region m_mutex_mutex;
|
||||||
|
std::size_t m_count;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
class recursive_try_mutex : private noncopyable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
friend class detail::thread::lock_ops<recursive_try_mutex>;
|
||||||
|
|
||||||
|
typedef detail::thread::scoped_lock<recursive_try_mutex> scoped_lock;
|
||||||
|
typedef detail::thread::scoped_try_lock<recursive_try_mutex> scoped_try_lock;
|
||||||
|
|
||||||
|
recursive_try_mutex();
|
||||||
|
~recursive_try_mutex();
|
||||||
|
|
||||||
|
private:
|
||||||
|
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||||
|
typedef std::size_t cv_state;
|
||||||
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
|
struct cv_state
|
||||||
|
{
|
||||||
|
long count;
|
||||||
|
pthread_mutex_t* pmutex;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
void do_lock();
|
||||||
|
bool do_trylock();
|
||||||
|
void do_unlock();
|
||||||
|
void do_lock(cv_state& state);
|
||||||
|
void do_unlock(cv_state& state);
|
||||||
|
|
||||||
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
void* m_mutex;
|
||||||
|
unsigned long m_count;
|
||||||
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
|
pthread_mutex_t m_mutex;
|
||||||
|
unsigned m_count;
|
||||||
|
# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
|
||||||
|
pthread_cond_t m_unlocked;
|
||||||
|
pthread_t m_thread_id;
|
||||||
|
bool m_valid_id;
|
||||||
|
# endif
|
||||||
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
|
threads::mac::detail::scoped_critical_region m_mutex;
|
||||||
|
threads::mac::detail::scoped_critical_region m_mutex_mutex;
|
||||||
|
std::size_t m_count;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
class recursive_timed_mutex : private noncopyable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
friend class detail::thread::lock_ops<recursive_timed_mutex>;
|
||||||
|
|
||||||
|
typedef detail::thread::scoped_lock<recursive_timed_mutex> scoped_lock;
|
||||||
|
typedef detail::thread::scoped_try_lock<recursive_timed_mutex> scoped_try_lock;
|
||||||
|
typedef detail::thread::scoped_timed_lock<recursive_timed_mutex> scoped_timed_lock;
|
||||||
|
|
||||||
|
recursive_timed_mutex();
|
||||||
|
~recursive_timed_mutex();
|
||||||
|
|
||||||
|
private:
|
||||||
|
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||||
|
typedef std::size_t cv_state;
|
||||||
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
|
struct cv_state
|
||||||
|
{
|
||||||
|
long count;
|
||||||
|
pthread_mutex_t* pmutex;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
void do_lock();
|
||||||
|
bool do_trylock();
|
||||||
|
bool do_timedlock(const xtime& xt);
|
||||||
|
void do_unlock();
|
||||||
|
void do_lock(cv_state& state);
|
||||||
|
void do_unlock(cv_state& state);
|
||||||
|
|
||||||
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
void* m_mutex;
|
||||||
|
unsigned long m_count;
|
||||||
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
|
pthread_mutex_t m_mutex;
|
||||||
|
pthread_cond_t m_unlocked;
|
||||||
|
pthread_t m_thread_id;
|
||||||
|
bool m_valid_id;
|
||||||
|
unsigned m_count;
|
||||||
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
|
threads::mac::detail::scoped_critical_region m_mutex;
|
||||||
|
threads::mac::detail::scoped_critical_region m_mutex_mutex;
|
||||||
|
std::size_t m_count;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
// Change Log:
|
||||||
|
// 8 Feb 01 WEKEMPF Initial version.
|
||||||
|
// 1 Jun 01 WEKEMPF Modified to use xtime for time outs. Factored out
|
||||||
|
// to three classes, mutex, try_mutex and timed_mutex.
|
||||||
|
// 11 Jun 01 WEKEMPF Modified to use PTHREAD_MUTEX_RECURSIVE if available.
|
||||||
|
|
||||||
|
#endif // BOOST_RECURSIVE_MUTEX_WEK070601_HPP
|
||||||
89
include/boost/thread/thread.hpp
Normal file
89
include/boost/thread/thread.hpp
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// William E. Kempf
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
|
// and its documentation for any purpose is hereby granted without fee,
|
||||||
|
// provided that the above copyright notice appear in all copies and
|
||||||
|
// that both that copyright notice and this permission notice appear
|
||||||
|
// in supporting documentation. 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_WEK070601_HPP
|
||||||
|
#define BOOST_THREAD_WEK070601_HPP
|
||||||
|
|
||||||
|
#include <boost/config.hpp>
|
||||||
|
#ifndef BOOST_HAS_THREADS
|
||||||
|
# error Thread support is unavailable!
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <boost/utility.hpp>
|
||||||
|
#include <boost/function.hpp>
|
||||||
|
#include <boost/thread/mutex.hpp>
|
||||||
|
#include <list>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#if defined(BOOST_HAS_PTHREADS)
|
||||||
|
# include <pthread.h>
|
||||||
|
# include <boost/thread/condition.hpp>
|
||||||
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
|
# include <Multiprocessing.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
struct xtime;
|
||||||
|
|
||||||
|
class thread : private noncopyable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
thread();
|
||||||
|
explicit thread(const function0<void>& threadfunc);
|
||||||
|
~thread();
|
||||||
|
|
||||||
|
bool operator==(const thread& other) const;
|
||||||
|
bool operator!=(const thread& other) const;
|
||||||
|
|
||||||
|
void join();
|
||||||
|
|
||||||
|
static void sleep(const xtime& xt);
|
||||||
|
static void yield();
|
||||||
|
|
||||||
|
private:
|
||||||
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
void* m_thread;
|
||||||
|
unsigned int m_id;
|
||||||
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
|
private:
|
||||||
|
pthread_t m_thread;
|
||||||
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
|
MPQueueID m_pJoinQueueID;
|
||||||
|
MPTaskID m_pTaskID;
|
||||||
|
#endif
|
||||||
|
bool m_joinable;
|
||||||
|
};
|
||||||
|
|
||||||
|
class thread_group : private noncopyable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
thread_group();
|
||||||
|
~thread_group();
|
||||||
|
|
||||||
|
thread* create_thread(const function0<void>& threadfunc);
|
||||||
|
void add_thread(thread* thrd);
|
||||||
|
void remove_thread(thread* thrd);
|
||||||
|
void join_all();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::list<thread*> m_threads;
|
||||||
|
mutex m_mutex;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
// Change Log:
|
||||||
|
// 8 Feb 01 WEKEMPF Initial version.
|
||||||
|
// 1 Jun 01 WEKEMPF Added boost::thread initial implementation.
|
||||||
|
// 3 Jul 01 WEKEMPF Redesigned boost::thread to be noncopyable.
|
||||||
|
|
||||||
|
#endif // BOOST_THREAD_WEK070601_HPP
|
||||||
81
include/boost/thread/tss.hpp
Normal file
81
include/boost/thread/tss.hpp
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// William E. Kempf
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
|
// and its documentation for any purpose is hereby granted without fee,
|
||||||
|
// provided that the above copyright notice appear in all copies and
|
||||||
|
// that both that copyright notice and this permission notice appear
|
||||||
|
// in supporting documentation. 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_TSS_WEK070601_HPP
|
||||||
|
#define BOOST_TSS_WEK070601_HPP
|
||||||
|
|
||||||
|
#include <boost/config.hpp>
|
||||||
|
#ifndef BOOST_HAS_THREADS
|
||||||
|
# error Thread support is unavailable!
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <boost/utility.hpp>
|
||||||
|
|
||||||
|
#if defined(BOOST_HAS_PTHREADS)
|
||||||
|
# include <pthread.h>
|
||||||
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
|
# include <Multiprocessing.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
class tss : private noncopyable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
tss(void (*cleanup)(void*)=0);
|
||||||
|
~tss();
|
||||||
|
|
||||||
|
void* get() const;
|
||||||
|
bool set(void* value);
|
||||||
|
|
||||||
|
private:
|
||||||
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
unsigned long m_key;
|
||||||
|
void (*m_cleanup)(void*);
|
||||||
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
|
pthread_key_t m_key;
|
||||||
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
|
TaskStorageIndex m_key;
|
||||||
|
void (*m_cleanup)(void*);
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(BOOST_HAS_MPTASKS)
|
||||||
|
void thread_cleanup();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class thread_specific_ptr : private noncopyable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
thread_specific_ptr() : m_tss(&thread_specific_ptr<T>::cleanup) { }
|
||||||
|
|
||||||
|
T* get() const { return static_cast<T*>(m_tss.get()); }
|
||||||
|
T* operator->() const { return get(); }
|
||||||
|
T& operator*() const { return *get(); }
|
||||||
|
T* release() { T* temp = get(); m_tss.set(0); return temp; }
|
||||||
|
void reset(T* p=0) { T* cur = get(); if (cur == p) return; delete cur; m_tss.set(p); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void cleanup(void* p) { delete static_cast<T*>(p); }
|
||||||
|
|
||||||
|
mutable detail::tss m_tss;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
// Change Log:
|
||||||
|
// 6 Jun 01 WEKEMPF Initial version.
|
||||||
|
|
||||||
|
#endif // BOOST_TSS_WEK070601_HPP
|
||||||
|
|
||||||
57
include/boost/thread/xtime.hpp
Normal file
57
include/boost/thread/xtime.hpp
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// William E. Kempf
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
|
// and its documentation for any purpose is hereby granted without fee,
|
||||||
|
// provided that the above copyright notice appear in all copies and
|
||||||
|
// that both that copyright notice and this permission notice appear
|
||||||
|
// in supporting documentation. 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_XTIME_WEK070601_HPP
|
||||||
|
#define BOOST_XTIME_WEK070601_HPP
|
||||||
|
|
||||||
|
#include <boost/cstdint.hpp>
|
||||||
|
#include <boost/config.hpp>
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
TIME_UTC=1,
|
||||||
|
TIME_TAI,
|
||||||
|
TIME_MONOTONIC,
|
||||||
|
TIME_PROCESS,
|
||||||
|
TIME_THREAD,
|
||||||
|
TIME_LOCAL,
|
||||||
|
TIME_SYNC,
|
||||||
|
TIME_RESOLUTION
|
||||||
|
};
|
||||||
|
|
||||||
|
struct xtime
|
||||||
|
{
|
||||||
|
#if defined(BOOST_NO_INT64_T)
|
||||||
|
int_fast32_t sec;
|
||||||
|
#else
|
||||||
|
int_fast64_t sec;
|
||||||
|
#endif
|
||||||
|
int_fast32_t nsec;
|
||||||
|
};
|
||||||
|
|
||||||
|
int xtime_get(struct xtime* xtp, int clock_type);
|
||||||
|
inline int xtime_cmp(const xtime& xt1, const xtime& xt2)
|
||||||
|
{
|
||||||
|
int res = (int)(xt1.sec - xt2.sec);
|
||||||
|
if (res == 0)
|
||||||
|
res = (int)(xt1.nsec - xt2.nsec);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
// Change Log:
|
||||||
|
// 8 Feb 01 WEKEMPF Initial version.
|
||||||
|
|
||||||
|
#endif // BOOST_XTIME_WEK070601_HPP
|
||||||
|
|
||||||
646
src/condition.cpp
Normal file
646
src/condition.cpp
Normal file
@@ -0,0 +1,646 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// William E. Kempf
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
|
// and its documentation for any purpose is hereby granted without fee,
|
||||||
|
// provided that the above copyright notice appear in all copies and
|
||||||
|
// that both that copyright notice and this permission notice appear
|
||||||
|
// in supporting documentation. 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/xtime.hpp>
|
||||||
|
#include <boost/thread/thread.hpp>
|
||||||
|
#include <boost/thread/exceptions.hpp>
|
||||||
|
#include <boost/limits.hpp>
|
||||||
|
#include <cassert>
|
||||||
|
#include "timeconv.inl"
|
||||||
|
|
||||||
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
# ifndef NOMINMAX
|
||||||
|
# define NOMINMAX
|
||||||
|
# endif
|
||||||
|
# include <windows.h>
|
||||||
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
|
# include <errno.h>
|
||||||
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
|
# include <MacErrors.h>
|
||||||
|
# include "mac/init.hpp"
|
||||||
|
# include "mac/safe.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
condition::condition()
|
||||||
|
: m_gone(0), m_blocked(0), m_waiting(0)
|
||||||
|
{
|
||||||
|
m_gate = reinterpret_cast<void*>(CreateSemaphore(0, 1, 1, 0));
|
||||||
|
m_queue = reinterpret_cast<void*>(CreateSemaphore(0, 0, std::numeric_limits<long>::max(), 0));
|
||||||
|
m_mutex = reinterpret_cast<void*>(CreateMutex(0, 0, 0));
|
||||||
|
|
||||||
|
if (!m_gate || !m_queue || !m_mutex)
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
if (m_gate)
|
||||||
|
{
|
||||||
|
res = CloseHandle(reinterpret_cast<HANDLE>(m_gate));
|
||||||
|
assert(res);
|
||||||
|
}
|
||||||
|
if (m_queue)
|
||||||
|
{
|
||||||
|
res = CloseHandle(reinterpret_cast<HANDLE>(m_queue));
|
||||||
|
assert(res);
|
||||||
|
}
|
||||||
|
if (m_mutex)
|
||||||
|
{
|
||||||
|
res = CloseHandle(reinterpret_cast<HANDLE>(m_mutex));
|
||||||
|
assert(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw thread_resource_error();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
condition::~condition()
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = CloseHandle(reinterpret_cast<HANDLE>(m_gate));
|
||||||
|
assert(res);
|
||||||
|
res = CloseHandle(reinterpret_cast<HANDLE>(m_queue));
|
||||||
|
assert(res);
|
||||||
|
res = CloseHandle(reinterpret_cast<HANDLE>(m_mutex));
|
||||||
|
assert(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
void condition::notify_one()
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
--m_blocked;
|
||||||
|
signals = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
|
||||||
|
assert(res == WAIT_OBJECT_0);
|
||||||
|
if (m_blocked > m_gone)
|
||||||
|
{
|
||||||
|
if (m_gone != 0)
|
||||||
|
{
|
||||||
|
m_blocked -= m_gone;
|
||||||
|
m_gone = 0;
|
||||||
|
}
|
||||||
|
signals = m_waiting = 1;
|
||||||
|
--m_blocked;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||||
|
assert(res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||||
|
assert(res);
|
||||||
|
|
||||||
|
if (signals)
|
||||||
|
{
|
||||||
|
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_queue), signals, 0);
|
||||||
|
assert(res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void condition::notify_all()
|
||||||
|
{
|
||||||
|
unsigned signals = 0;
|
||||||
|
|
||||||
|
int res = 0;
|
||||||
|
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), INFINITE);
|
||||||
|
assert(res == WAIT_OBJECT_0);
|
||||||
|
|
||||||
|
if (m_waiting != 0) // the m_gate is already closed
|
||||||
|
{
|
||||||
|
if (m_blocked == 0)
|
||||||
|
{
|
||||||
|
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||||
|
assert(res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_waiting += (signals = m_blocked);
|
||||||
|
m_blocked = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
|
||||||
|
assert(res == WAIT_OBJECT_0);
|
||||||
|
if (m_blocked > m_gone)
|
||||||
|
{
|
||||||
|
if (m_gone != 0)
|
||||||
|
{
|
||||||
|
m_blocked -= m_gone;
|
||||||
|
m_gone = 0;
|
||||||
|
}
|
||||||
|
signals = m_waiting = m_blocked;
|
||||||
|
m_blocked = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||||
|
assert(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||||
|
assert(res);
|
||||||
|
|
||||||
|
if (signals)
|
||||||
|
{
|
||||||
|
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_queue), signals, 0);
|
||||||
|
assert(res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void condition::enter_wait()
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
|
||||||
|
assert(res == WAIT_OBJECT_0);
|
||||||
|
++m_blocked;
|
||||||
|
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||||
|
assert(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
void condition::do_wait()
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue), INFINITE);
|
||||||
|
assert(res == WAIT_OBJECT_0);
|
||||||
|
|
||||||
|
unsigned was_waiting=0;
|
||||||
|
unsigned was_gone=0;
|
||||||
|
|
||||||
|
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), INFINITE);
|
||||||
|
assert(res == WAIT_OBJECT_0);
|
||||||
|
was_waiting = m_waiting;
|
||||||
|
was_gone = m_gone;
|
||||||
|
if (was_waiting != 0)
|
||||||
|
{
|
||||||
|
if (--m_waiting == 0)
|
||||||
|
{
|
||||||
|
if (m_blocked != 0)
|
||||||
|
{
|
||||||
|
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0); // open m_gate
|
||||||
|
assert(res);
|
||||||
|
was_waiting = 0;
|
||||||
|
}
|
||||||
|
else if (m_gone != 0)
|
||||||
|
m_gone = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (++m_gone == (std::numeric_limits<unsigned>::max() / 2))
|
||||||
|
{
|
||||||
|
// timeout occured, normalize the m_gone count
|
||||||
|
// this may occur if many calls to wait with a timeout are made and
|
||||||
|
// no call to notify_* is made
|
||||||
|
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
|
||||||
|
assert(res == WAIT_OBJECT_0);
|
||||||
|
m_blocked -= m_gone;
|
||||||
|
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||||
|
assert(res);
|
||||||
|
m_gone = 0;
|
||||||
|
}
|
||||||
|
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||||
|
assert(res);
|
||||||
|
|
||||||
|
if (was_waiting == 1)
|
||||||
|
{
|
||||||
|
for (/**/ ; was_gone; --was_gone)
|
||||||
|
{
|
||||||
|
// better now than spurious later
|
||||||
|
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue), INFINITE);
|
||||||
|
assert(res == WAIT_OBJECT_0);
|
||||||
|
}
|
||||||
|
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||||
|
assert(res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool condition::do_timed_wait(const xtime& xt)
|
||||||
|
{
|
||||||
|
int milliseconds;
|
||||||
|
to_duration(xt, milliseconds);
|
||||||
|
|
||||||
|
unsigned int res = 0;
|
||||||
|
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue), milliseconds);
|
||||||
|
assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
|
||||||
|
|
||||||
|
bool ret = (res == WAIT_OBJECT_0);
|
||||||
|
|
||||||
|
unsigned was_waiting=0;
|
||||||
|
unsigned was_gone=0;
|
||||||
|
|
||||||
|
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), INFINITE);
|
||||||
|
assert(res == WAIT_OBJECT_0);
|
||||||
|
was_waiting = m_waiting;
|
||||||
|
was_gone = m_gone;
|
||||||
|
if (was_waiting != 0)
|
||||||
|
{
|
||||||
|
if (!ret) // timeout
|
||||||
|
{
|
||||||
|
if (m_blocked != 0)
|
||||||
|
--m_blocked;
|
||||||
|
else
|
||||||
|
++m_gone; // count spurious wakeups
|
||||||
|
}
|
||||||
|
if (--m_waiting == 0)
|
||||||
|
{
|
||||||
|
if (m_blocked != 0)
|
||||||
|
{
|
||||||
|
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0); // open m_gate
|
||||||
|
assert(res);
|
||||||
|
was_waiting = 0;
|
||||||
|
}
|
||||||
|
else if (m_gone != 0)
|
||||||
|
m_gone = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (++m_gone == (std::numeric_limits<unsigned>::max() / 2))
|
||||||
|
{
|
||||||
|
// timeout occured, normalize the m_gone count
|
||||||
|
// this may occur if many calls to wait with a timeout are made and
|
||||||
|
// no call to notify_* is made
|
||||||
|
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
|
||||||
|
assert(res == WAIT_OBJECT_0);
|
||||||
|
m_blocked -= m_gone;
|
||||||
|
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||||
|
assert(res);
|
||||||
|
m_gone = 0;
|
||||||
|
}
|
||||||
|
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||||
|
assert(res);
|
||||||
|
|
||||||
|
if (was_waiting == 1)
|
||||||
|
{
|
||||||
|
for (/**/ ; was_gone; --was_gone)
|
||||||
|
{
|
||||||
|
// better now than spurious later
|
||||||
|
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue), INFINITE);
|
||||||
|
assert(res == WAIT_OBJECT_0);
|
||||||
|
}
|
||||||
|
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||||
|
assert(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
|
condition::condition()
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = pthread_cond_init(&m_condition, 0);
|
||||||
|
if (res != 0)
|
||||||
|
throw thread_resource_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
condition::~condition()
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = pthread_cond_destroy(&m_condition);
|
||||||
|
assert(res == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void condition::notify_one()
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = pthread_cond_signal(&m_condition);
|
||||||
|
assert(res == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void condition::notify_all()
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = pthread_cond_broadcast(&m_condition);
|
||||||
|
assert(res == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void condition::do_wait(pthread_mutex_t* pmutex)
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = pthread_cond_wait(&m_condition, pmutex);
|
||||||
|
assert(res == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool condition::do_timed_wait(const xtime& xt, pthread_mutex_t* pmutex)
|
||||||
|
{
|
||||||
|
timespec ts;
|
||||||
|
to_timespec(xt, ts);
|
||||||
|
|
||||||
|
int res = 0;
|
||||||
|
res = pthread_cond_timedwait(&m_condition, pmutex, &ts);
|
||||||
|
assert(res == 0 || res == ETIMEDOUT);
|
||||||
|
|
||||||
|
return res != ETIMEDOUT;
|
||||||
|
}
|
||||||
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
|
|
||||||
|
using threads::mac::detail::safe_enter_critical_region;
|
||||||
|
using threads::mac::detail::safe_wait_on_semaphore;
|
||||||
|
|
||||||
|
condition::condition()
|
||||||
|
: m_gone(0), m_blocked(0), m_waiting(0)
|
||||||
|
{
|
||||||
|
threads::mac::detail::thread_init();
|
||||||
|
|
||||||
|
OSStatus lStatus = noErr;
|
||||||
|
|
||||||
|
lStatus = MPCreateSemaphore(1, 1, &m_gate);
|
||||||
|
if(lStatus == noErr)
|
||||||
|
lStatus = MPCreateSemaphore(ULONG_MAX, 0, &m_queue);
|
||||||
|
|
||||||
|
if(lStatus != noErr || !m_gate || !m_queue)
|
||||||
|
{
|
||||||
|
if (m_gate)
|
||||||
|
{
|
||||||
|
lStatus = MPDeleteSemaphore(m_gate);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
}
|
||||||
|
if (m_queue)
|
||||||
|
{
|
||||||
|
lStatus = MPDeleteSemaphore(m_queue);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw thread_resource_error();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
condition::~condition()
|
||||||
|
{
|
||||||
|
OSStatus lStatus = noErr;
|
||||||
|
lStatus = MPDeleteSemaphore(m_gate);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
lStatus = MPDeleteSemaphore(m_queue);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void condition::notify_one()
|
||||||
|
{
|
||||||
|
unsigned signals = 0;
|
||||||
|
|
||||||
|
OSStatus lStatus = noErr;
|
||||||
|
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
|
||||||
|
if (m_waiting != 0) // the m_gate is already closed
|
||||||
|
{
|
||||||
|
if (m_blocked == 0)
|
||||||
|
{
|
||||||
|
lStatus = MPExitCriticalRegion(m_mutex);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
++m_waiting;
|
||||||
|
--m_blocked;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
if (m_blocked > m_gone)
|
||||||
|
{
|
||||||
|
if (m_gone != 0)
|
||||||
|
{
|
||||||
|
m_blocked -= m_gone;
|
||||||
|
m_gone = 0;
|
||||||
|
}
|
||||||
|
signals = m_waiting = 1;
|
||||||
|
--m_blocked;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
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::notify_all()
|
||||||
|
{
|
||||||
|
unsigned signals = 0;
|
||||||
|
|
||||||
|
OSStatus lStatus = noErr;
|
||||||
|
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
|
||||||
|
if (m_waiting != 0) // the m_gate is already closed
|
||||||
|
{
|
||||||
|
if (m_blocked == 0)
|
||||||
|
{
|
||||||
|
lStatus = MPExitCriticalRegion(m_mutex);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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::enter_wait()
|
||||||
|
{
|
||||||
|
OSStatus lStatus = noErr;
|
||||||
|
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
++m_blocked;
|
||||||
|
lStatus = MPSignalSemaphore(m_gate);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void condition::do_wait()
|
||||||
|
{
|
||||||
|
OSStatus lStatus = noErr;
|
||||||
|
lStatus = safe_wait_on_semaphore(m_queue, kDurationForever);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
|
||||||
|
unsigned was_waiting=0;
|
||||||
|
unsigned was_gone=0;
|
||||||
|
|
||||||
|
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
was_waiting = m_waiting;
|
||||||
|
was_gone = m_gone;
|
||||||
|
if (was_waiting != 0)
|
||||||
|
{
|
||||||
|
if (--m_waiting == 0)
|
||||||
|
{
|
||||||
|
if (m_blocked != 0)
|
||||||
|
{
|
||||||
|
lStatus = MPSignalSemaphore(m_gate); // open m_gate
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
was_waiting = 0;
|
||||||
|
}
|
||||||
|
else if (m_gone != 0)
|
||||||
|
m_gone = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (++m_gone == (std::numeric_limits<unsigned>::max() / 2))
|
||||||
|
{
|
||||||
|
// timeout occured, normalize the m_gone count
|
||||||
|
// this may occur if many calls to wait with a timeout are made and
|
||||||
|
// no call to notify_* is made
|
||||||
|
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
m_blocked -= m_gone;
|
||||||
|
lStatus = MPSignalSemaphore(m_gate);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
m_gone = 0;
|
||||||
|
}
|
||||||
|
lStatus = MPExitCriticalRegion(m_mutex);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
|
||||||
|
if (was_waiting == 1)
|
||||||
|
{
|
||||||
|
for (/**/ ; was_gone; --was_gone)
|
||||||
|
{
|
||||||
|
// better now than spurious later
|
||||||
|
lStatus = safe_wait_on_semaphore(m_queue, kDurationForever);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
}
|
||||||
|
lStatus = MPSignalSemaphore(m_gate);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool condition::do_timed_wait(const xtime& xt)
|
||||||
|
{
|
||||||
|
int milliseconds;
|
||||||
|
to_duration(xt, milliseconds);
|
||||||
|
|
||||||
|
OSStatus lStatus = noErr;
|
||||||
|
lStatus = safe_wait_on_semaphore(m_queue, milliseconds);
|
||||||
|
assert(lStatus == noErr || lStatus == kMPTimeoutErr);
|
||||||
|
|
||||||
|
bool ret = (lStatus == noErr);
|
||||||
|
|
||||||
|
unsigned was_waiting=0;
|
||||||
|
unsigned was_gone=0;
|
||||||
|
|
||||||
|
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
was_waiting = m_waiting;
|
||||||
|
was_gone = m_gone;
|
||||||
|
if (was_waiting != 0)
|
||||||
|
{
|
||||||
|
if (!ret) // timeout
|
||||||
|
{
|
||||||
|
if (m_blocked != 0)
|
||||||
|
--m_blocked;
|
||||||
|
else
|
||||||
|
++m_gone; // count spurious wakeups
|
||||||
|
}
|
||||||
|
if (--m_waiting == 0)
|
||||||
|
{
|
||||||
|
if (m_blocked != 0)
|
||||||
|
{
|
||||||
|
lStatus = MPSignalSemaphore(m_gate); // open m_gate
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
was_waiting = 0;
|
||||||
|
}
|
||||||
|
else if (m_gone != 0)
|
||||||
|
m_gone = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (++m_gone == (std::numeric_limits<unsigned>::max() / 2))
|
||||||
|
{
|
||||||
|
// timeout occured, normalize the m_gone count
|
||||||
|
// this may occur if many calls to wait with a timeout are made and
|
||||||
|
// no call to notify_* is made
|
||||||
|
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
m_blocked -= m_gone;
|
||||||
|
lStatus = MPSignalSemaphore(m_gate);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
m_gone = 0;
|
||||||
|
}
|
||||||
|
lStatus = MPExitCriticalRegion(m_mutex);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
|
||||||
|
if (was_waiting == 1)
|
||||||
|
{
|
||||||
|
for (/**/ ; was_gone; --was_gone)
|
||||||
|
{
|
||||||
|
// better now than spurious later
|
||||||
|
lStatus = safe_wait_on_semaphore(m_queue, kDurationForever);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
}
|
||||||
|
lStatus = MPSignalSemaphore(m_gate);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
// Change Log:
|
||||||
|
// 8 Feb 01 WEKEMPF Initial version.
|
||||||
|
// 22 May 01 WEKEMPF Modified to use xtime for time outs.
|
||||||
25
src/exceptions.cpp
Normal file
25
src/exceptions.cpp
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// William E. Kempf
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
|
// and its documentation for any purpose is hereby granted without fee,
|
||||||
|
// provided that the above copyright notice appear in all copies and
|
||||||
|
// that both that copyright notice and this permission notice appear
|
||||||
|
// in supporting documentation. 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/exceptions.hpp>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
lock_error::lock_error() : std::logic_error("thread lock error")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
thread_resource_error::thread_resource_error() : std::runtime_error("thread resource error")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
14
src/mac/debug_prefix.hpp
Normal file
14
src/mac/debug_prefix.hpp
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// Mac Murrett
|
||||||
|
//
|
||||||
|
// 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. Mac Murrett makes no representations
|
||||||
|
// about the suitability of this software for any purpose. It is
|
||||||
|
// provided "as is" without express or implied warranty.
|
||||||
|
//
|
||||||
|
// See http://www.boost.org for most recent version including documentation.
|
||||||
|
|
||||||
|
#define TARGET_CARBON 1
|
||||||
72
src/mac/delivery_man.cpp
Normal file
72
src/mac/delivery_man.cpp
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// Mac Murrett
|
||||||
|
//
|
||||||
|
// 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. Mac Murrett makes no representations
|
||||||
|
// about the suitability of this software for any purpose. It is
|
||||||
|
// provided "as is" without express or implied warranty.
|
||||||
|
//
|
||||||
|
// See http://www.boost.org for most recent version including documentation.
|
||||||
|
|
||||||
|
#include "delivery_man.hpp"
|
||||||
|
|
||||||
|
#include "os.hpp"
|
||||||
|
#include "execution_context.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
namespace threads {
|
||||||
|
|
||||||
|
namespace mac {
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
|
||||||
|
delivery_man::delivery_man():
|
||||||
|
m_pPackage(NULL),
|
||||||
|
m_pSemaphore(kInvalidID),
|
||||||
|
m_bPackageWaiting(false)
|
||||||
|
{
|
||||||
|
assert(at_st());
|
||||||
|
|
||||||
|
OSStatus lStatus = MPCreateSemaphore(1UL, 0UL, &m_pSemaphore);
|
||||||
|
// TODO - throw on error here
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
}
|
||||||
|
|
||||||
|
delivery_man::~delivery_man()
|
||||||
|
{
|
||||||
|
assert(m_bPackageWaiting == false);
|
||||||
|
|
||||||
|
OSStatus lStatus = MPDeleteSemaphore(m_pSemaphore);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void delivery_man::accept_deliveries()
|
||||||
|
{
|
||||||
|
if(m_bPackageWaiting)
|
||||||
|
{
|
||||||
|
assert(m_pPackage != NULL);
|
||||||
|
m_pPackage->accept();
|
||||||
|
m_pPackage = NULL;
|
||||||
|
m_bPackageWaiting = false;
|
||||||
|
|
||||||
|
// signal to the thread making the call that we're done
|
||||||
|
OSStatus lStatus = MPSignalSemaphore(m_pSemaphore);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
} // namespace mac
|
||||||
|
|
||||||
|
} // namespace threads
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
90
src/mac/delivery_man.hpp
Normal file
90
src/mac/delivery_man.hpp
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// Mac Murrett
|
||||||
|
//
|
||||||
|
// 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. Mac Murrett makes no representations
|
||||||
|
// about the suitability of this software for any purpose. It is
|
||||||
|
// provided "as is" without express or implied warranty.
|
||||||
|
//
|
||||||
|
// See http://www.boost.org for most recent version including documentation.
|
||||||
|
|
||||||
|
#ifndef BOOST_DELIVERY_MAN_MJM012402_HPP
|
||||||
|
#define BOOST_DELIVERY_MAN_MJM012402_HPP
|
||||||
|
|
||||||
|
|
||||||
|
#include <boost/function.hpp>
|
||||||
|
#include <boost/utility.hpp>
|
||||||
|
|
||||||
|
#include <boost/thread/mutex.hpp>
|
||||||
|
|
||||||
|
#include "package.hpp"
|
||||||
|
|
||||||
|
#include <Multiprocessing.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
namespace threads {
|
||||||
|
|
||||||
|
namespace mac {
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
|
||||||
|
// class delivery_man is intended to move boost::function objects from MP tasks to
|
||||||
|
// other execution contexts (such as deferred task time or system task time).
|
||||||
|
|
||||||
|
class delivery_man: private noncopyable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
delivery_man();
|
||||||
|
~delivery_man();
|
||||||
|
|
||||||
|
public:
|
||||||
|
template<class R>
|
||||||
|
R deliver(function<R> &rFunctor);
|
||||||
|
|
||||||
|
void accept_deliveries();
|
||||||
|
|
||||||
|
private:
|
||||||
|
base_package *m_pPackage;
|
||||||
|
mutex m_oMutex;
|
||||||
|
MPSemaphoreID m_pSemaphore;
|
||||||
|
bool m_bPackageWaiting;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<class R>
|
||||||
|
R delivery_man::deliver(function<R> &rFunctor)
|
||||||
|
{
|
||||||
|
assert(at_mp());
|
||||||
|
|
||||||
|
// lock our mutex
|
||||||
|
mutex::scoped_lock oLock(m_oMutex);
|
||||||
|
|
||||||
|
// create a package and save it
|
||||||
|
package<R> oPackage(rFunctor);
|
||||||
|
m_pPackage = &oPackage;
|
||||||
|
m_bPackageWaiting = true;
|
||||||
|
|
||||||
|
// wait on the semaphore
|
||||||
|
OSStatus lStatus = MPWaitOnSemaphore(m_pSemaphore, kDurationForever);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
|
||||||
|
return(oPackage.return_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
} // namespace mac
|
||||||
|
|
||||||
|
} // namespace threads
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BOOST_DELIVERY_MAN_MJM012402_HPP
|
||||||
99
src/mac/dt_scheduler.cpp
Normal file
99
src/mac/dt_scheduler.cpp
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// Mac Murrett
|
||||||
|
//
|
||||||
|
// 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. Mac Murrett makes no representations
|
||||||
|
// about the suitability of this software for any purpose. It is
|
||||||
|
// provided "as is" without express or implied warranty.
|
||||||
|
//
|
||||||
|
// See http://www.boost.org for most recent version including documentation.
|
||||||
|
|
||||||
|
#include "dt_scheduler.hpp"
|
||||||
|
|
||||||
|
#include "ot_context.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
#include <boost/thread/detail/singleton.hpp>
|
||||||
|
|
||||||
|
#include <OpenTransportProtocol.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
namespace threads {
|
||||||
|
|
||||||
|
namespace mac {
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
|
||||||
|
const OTTimeout k_ulTimerTaskDelay = 1UL;
|
||||||
|
|
||||||
|
|
||||||
|
dt_scheduler::dt_scheduler():
|
||||||
|
m_bReschedule(false),
|
||||||
|
m_uppTask(NULL),
|
||||||
|
m_lTask(0UL)
|
||||||
|
{
|
||||||
|
using ::boost::detail::thread::singleton;
|
||||||
|
|
||||||
|
ot_context &rContext(singleton<ot_context>::instance());
|
||||||
|
|
||||||
|
m_uppTask = NewOTProcessUPP(task_entry);
|
||||||
|
m_lTask = OTCreateTimerTaskInContext(m_uppTask, this, rContext.get_context());
|
||||||
|
}
|
||||||
|
|
||||||
|
dt_scheduler::~dt_scheduler()
|
||||||
|
{
|
||||||
|
OTDestroyTimerTask(m_lTask);
|
||||||
|
m_lTask = 0UL;
|
||||||
|
DisposeOTProcessUPP(m_uppTask);
|
||||||
|
m_uppTask = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void dt_scheduler::start_polling()
|
||||||
|
{
|
||||||
|
m_bReschedule = true;
|
||||||
|
schedule_task();
|
||||||
|
}
|
||||||
|
|
||||||
|
void dt_scheduler::stop_polling()
|
||||||
|
{
|
||||||
|
m_bReschedule = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void dt_scheduler::schedule_task()
|
||||||
|
{
|
||||||
|
if(m_bReschedule)
|
||||||
|
{
|
||||||
|
OTScheduleTimerTask(m_lTask, k_ulTimerTaskDelay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*static*/ pascal void dt_scheduler::task_entry(void *pRefCon)
|
||||||
|
{
|
||||||
|
dt_scheduler *pThis = reinterpret_cast<dt_scheduler *>(pRefCon);
|
||||||
|
assert(pThis != NULL);
|
||||||
|
pThis->task();
|
||||||
|
}
|
||||||
|
|
||||||
|
void dt_scheduler::task()
|
||||||
|
{
|
||||||
|
periodic_function();
|
||||||
|
schedule_task();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
} // namespace mac
|
||||||
|
|
||||||
|
} // namespace threads
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
69
src/mac/dt_scheduler.hpp
Normal file
69
src/mac/dt_scheduler.hpp
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// Mac Murrett
|
||||||
|
//
|
||||||
|
// 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. Mac Murrett makes no representations
|
||||||
|
// about the suitability of this software for any purpose. It is
|
||||||
|
// provided "as is" without express or implied warranty.
|
||||||
|
//
|
||||||
|
// See http://www.boost.org for most recent version including documentation.
|
||||||
|
|
||||||
|
#ifndef BOOST_DT_SCHEDULER_MJM012402_HPP
|
||||||
|
#define BOOST_DT_SCHEDULER_MJM012402_HPP
|
||||||
|
|
||||||
|
|
||||||
|
#include "periodical.hpp"
|
||||||
|
|
||||||
|
#include <OpenTransport.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
namespace threads {
|
||||||
|
|
||||||
|
namespace mac {
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
|
||||||
|
// class dt_scheduler calls its pure-virtual periodic_function method periodically at
|
||||||
|
// deferred task time. This is generally 1kHz under Mac OS 9.
|
||||||
|
|
||||||
|
class dt_scheduler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
dt_scheduler();
|
||||||
|
virtual ~dt_scheduler();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void start_polling();
|
||||||
|
void stop_polling();
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual void periodic_function() = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void schedule_task();
|
||||||
|
static pascal void task_entry(void *pRefCon);
|
||||||
|
void task();
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_bReschedule;
|
||||||
|
OTProcessUPP m_uppTask;
|
||||||
|
long m_lTask;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
} // namespace mac
|
||||||
|
|
||||||
|
} // namespace threads
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BOOST_DT_SCHEDULER_MJM012402_HPP
|
||||||
66
src/mac/execution_context.cpp
Normal file
66
src/mac/execution_context.cpp
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// Mac Murrett
|
||||||
|
//
|
||||||
|
// 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. Mac Murrett makes no representations
|
||||||
|
// about the suitability of this software for any purpose. It is
|
||||||
|
// provided "as is" without express or implied warranty.
|
||||||
|
//
|
||||||
|
// See http://www.boost.org for most recent version including documentation.
|
||||||
|
|
||||||
|
#include <Debugging.h>
|
||||||
|
#include <Multiprocessing.h>
|
||||||
|
|
||||||
|
#include "execution_context.hpp"
|
||||||
|
#include "init.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
namespace threads {
|
||||||
|
|
||||||
|
namespace mac {
|
||||||
|
|
||||||
|
|
||||||
|
execution_context_t execution_context()
|
||||||
|
{
|
||||||
|
// make sure that MP services are available the first time through
|
||||||
|
static bool bIgnored = detail::thread_init();
|
||||||
|
|
||||||
|
// first check if we're an MP task
|
||||||
|
if(MPTaskIsPreemptive(kInvalidID))
|
||||||
|
{
|
||||||
|
return(k_eExecutionContextMPTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if TARGET_CARBON
|
||||||
|
// Carbon has TaskLevel
|
||||||
|
UInt32 ulLevel = TaskLevel();
|
||||||
|
|
||||||
|
if(ulLevel == 0UL)
|
||||||
|
{
|
||||||
|
return(k_eExecutionContextSystemTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ulLevel & kInDeferredTaskMask)
|
||||||
|
{
|
||||||
|
return(k_eExecutionContextDeferredTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
return(k_eExecutionContextOther);
|
||||||
|
#else
|
||||||
|
// this can be implemented using TaskLevel if you don't mind linking against
|
||||||
|
// DebugLib (and therefore breaking Mac OS 8.6 support), or CurrentExecutionLevel.
|
||||||
|
# error execution_context unimplimented
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace mac
|
||||||
|
|
||||||
|
} // namespace threads
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
53
src/mac/execution_context.hpp
Normal file
53
src/mac/execution_context.hpp
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// Mac Murrett
|
||||||
|
//
|
||||||
|
// 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. Mac Murrett makes no representations
|
||||||
|
// about the suitability of this software for any purpose. It is
|
||||||
|
// provided "as is" without express or implied warranty.
|
||||||
|
//
|
||||||
|
// See http://www.boost.org for most recent version including documentation.
|
||||||
|
|
||||||
|
#ifndef BOOST_EXECUTION_CONTEXT_MJM012402_HPP
|
||||||
|
#define BOOST_EXECUTION_CONTEXT_MJM012402_HPP
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
namespace threads {
|
||||||
|
|
||||||
|
namespace mac {
|
||||||
|
|
||||||
|
|
||||||
|
// utility functions for figuring out what context your code is executing in.
|
||||||
|
// Bear in mind that at_mp and in_blue are the only functions guarenteed by
|
||||||
|
// Apple to work. There is simply no way of being sure that you will not get
|
||||||
|
// false readings about task level at interrupt time in blue.
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
k_eExecutionContextSystemTask,
|
||||||
|
k_eExecutionContextDeferredTask,
|
||||||
|
k_eExecutionContextMPTask,
|
||||||
|
k_eExecutionContextOther
|
||||||
|
} execution_context_t;
|
||||||
|
|
||||||
|
execution_context_t execution_context();
|
||||||
|
|
||||||
|
inline bool at_st()
|
||||||
|
{ return(execution_context() == k_eExecutionContextSystemTask); }
|
||||||
|
|
||||||
|
inline bool at_mp()
|
||||||
|
{ return(execution_context() == k_eExecutionContextMPTask); }
|
||||||
|
inline bool in_blue()
|
||||||
|
{ return(!at_mp()); }
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace mac
|
||||||
|
|
||||||
|
} // namespace threads
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
#endif // BOOST_EXECUTION_CONTEXT_MJM012402_HPP
|
||||||
64
src/mac/init.cpp
Normal file
64
src/mac/init.cpp
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// Mac Murrett
|
||||||
|
//
|
||||||
|
// 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. Mac Murrett makes no representations
|
||||||
|
// about the suitability of this software for any purpose. It is
|
||||||
|
// provided "as is" without express or implied warranty.
|
||||||
|
//
|
||||||
|
// See http://www.boost.org for most recent version including documentation.
|
||||||
|
|
||||||
|
#include "init.hpp"
|
||||||
|
|
||||||
|
#include "remote_call_manager.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
#include <boost/thread/detail/singleton.hpp>
|
||||||
|
|
||||||
|
#include <Multiprocessing.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
namespace threads {
|
||||||
|
|
||||||
|
namespace mac {
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// force these to get called by the end of static initialization time.
|
||||||
|
static bool g_bInitialized = (thread_init() && create_singletons());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool thread_init()
|
||||||
|
{
|
||||||
|
static bool bResult = MPLibraryIsLoaded();
|
||||||
|
|
||||||
|
return(bResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool create_singletons()
|
||||||
|
{
|
||||||
|
using ::boost::detail::thread::singleton;
|
||||||
|
|
||||||
|
singleton<remote_call_manager>::instance();
|
||||||
|
|
||||||
|
return(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
} // namespace mac
|
||||||
|
|
||||||
|
} // namespace threads
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
40
src/mac/init.hpp
Normal file
40
src/mac/init.hpp
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// Mac Murrett
|
||||||
|
//
|
||||||
|
// 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. Mac Murrett makes no representations
|
||||||
|
// about the suitability of this software for any purpose. It is
|
||||||
|
// provided "as is" without express or implied warranty.
|
||||||
|
//
|
||||||
|
// See http://www.boost.org for most recent version including documentation.
|
||||||
|
|
||||||
|
#ifndef BOOST_INIT_MJM012402_HPP
|
||||||
|
#define BOOST_INIT_MJM012402_HPP
|
||||||
|
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
namespace threads {
|
||||||
|
|
||||||
|
namespace mac {
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
|
||||||
|
bool thread_init();
|
||||||
|
bool create_singletons();
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
} // namespace mac
|
||||||
|
|
||||||
|
} // namespace threads
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BOOST_INIT_MJM012402_HPP
|
||||||
30
src/mac/msl_replacements/assert.cpp
Normal file
30
src/mac/msl_replacements/assert.cpp
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// Mac Murrett
|
||||||
|
//
|
||||||
|
// 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. Mac Murrett makes no representations
|
||||||
|
// about the suitability of this software for any purpose. It is
|
||||||
|
// provided "as is" without express or implied warranty.
|
||||||
|
//
|
||||||
|
// See http://www.boost.org for most recent version including documentation.
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
#include <MacTypes.h>
|
||||||
|
|
||||||
|
#include "remote_calls.hpp"
|
||||||
|
|
||||||
|
// this function will be called when an assertion fails. We redirect the assertion
|
||||||
|
// to DebugStr (MacsBug under Mac OS 1.x-9.x, Console under Mac OS X).
|
||||||
|
void __assertion_failed(char const *pszAssertion, char const *pszFile, int nLine)
|
||||||
|
{
|
||||||
|
using std::snprintf;
|
||||||
|
unsigned char strlDebug[sizeof(Str255) + 1];
|
||||||
|
char *pszDebug = reinterpret_cast<char *>(&strlDebug[1]);
|
||||||
|
strlDebug[0] = snprintf(pszDebug, sizeof(Str255), "assertion failed: \"%s\", %s, line %d", pszAssertion, pszFile, nLine);
|
||||||
|
boost::threads::mac::dt_remote_call(DebugStr, static_cast<ConstStringPtr>(strlDebug));
|
||||||
|
}
|
||||||
134
src/mac/msl_replacements/console_io.cpp
Normal file
134
src/mac/msl_replacements/console_io.cpp
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// Mac Murrett
|
||||||
|
//
|
||||||
|
// 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. Mac Murrett makes no representations
|
||||||
|
// about the suitability of this software for any purpose. It is
|
||||||
|
// provided "as is" without express or implied warranty.
|
||||||
|
//
|
||||||
|
// See http://www.boost.org for most recent version including documentation.
|
||||||
|
|
||||||
|
//
|
||||||
|
// includes
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <abort_exit.h>
|
||||||
|
#include <console.h>
|
||||||
|
#include <console_io.h>
|
||||||
|
#include <misc_io.h>
|
||||||
|
#include <SIOUX.h>
|
||||||
|
|
||||||
|
#include "remote_calls.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// using declarations
|
||||||
|
//
|
||||||
|
|
||||||
|
using std::__file_handle;
|
||||||
|
using std::__idle_proc;
|
||||||
|
using std::__io_error;
|
||||||
|
using std::__no_io_error;
|
||||||
|
using std::size_t;
|
||||||
|
|
||||||
|
using boost::threads::mac::st_remote_call;
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// prototypes
|
||||||
|
//
|
||||||
|
|
||||||
|
static bool check_console();
|
||||||
|
static int do_read_console(__file_handle ulHandle, unsigned char *pBuffer, size_t *pCount, __idle_proc pfnIdleProc);
|
||||||
|
static int do_write_console(__file_handle ulHandle, unsigned char *pBuffer, size_t *pCount, __idle_proc pfnIdleProc);
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// MSL function replacements
|
||||||
|
//
|
||||||
|
|
||||||
|
// these two functions are called by cin and cout, respectively, as well as by (all?)
|
||||||
|
// other functions in MSL that do console I/O. All that they do is as the remote
|
||||||
|
// call manager to ensure that their guts are called at system task time.
|
||||||
|
int __read_console(__file_handle handle, unsigned char * buffer, size_t * count, __idle_proc idle_proc)
|
||||||
|
{
|
||||||
|
return(st_remote_call(do_read_console, handle, buffer, count, idle_proc));
|
||||||
|
}
|
||||||
|
|
||||||
|
int __write_console(__file_handle handle, unsigned char * buffer, size_t * count, __idle_proc idle_proc)
|
||||||
|
{
|
||||||
|
return(st_remote_call(do_write_console, handle, buffer, count, idle_proc));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// implementations
|
||||||
|
//
|
||||||
|
|
||||||
|
static bool check_console()
|
||||||
|
{
|
||||||
|
static bool s_bHaveConsole(false);
|
||||||
|
static bool s_bWontHaveConsole(false);
|
||||||
|
|
||||||
|
if(s_bHaveConsole)
|
||||||
|
{
|
||||||
|
return(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(s_bWontHaveConsole == false)
|
||||||
|
{
|
||||||
|
__stdio_atexit();
|
||||||
|
|
||||||
|
if(InstallConsole(0) != 0)
|
||||||
|
{
|
||||||
|
s_bWontHaveConsole = true;
|
||||||
|
return(false);
|
||||||
|
}
|
||||||
|
__console_exit = RemoveConsole;
|
||||||
|
s_bHaveConsole = true;
|
||||||
|
return(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int do_read_console(__file_handle /*ulHandle*/, unsigned char *pBuffer, size_t *pCount, __idle_proc /*pfnIdleProc*/)
|
||||||
|
{
|
||||||
|
assert(pCount != NULL);
|
||||||
|
assert(pBuffer != NULL || *pCount == 0UL);
|
||||||
|
|
||||||
|
if(check_console() == false)
|
||||||
|
{
|
||||||
|
return(__io_error);
|
||||||
|
}
|
||||||
|
std::fflush(stdout);
|
||||||
|
long lCount = ReadCharsFromConsole(reinterpret_cast<char *>(pBuffer), static_cast<long>(*pCount));
|
||||||
|
*pCount = static_cast<size_t>(lCount);
|
||||||
|
if(lCount == -1L)
|
||||||
|
{
|
||||||
|
return(__io_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return(__no_io_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
int do_write_console(__file_handle /*ulHandle*/, unsigned char *pBuffer, size_t *pCount, __idle_proc /*pfnIdleProc*/)
|
||||||
|
{
|
||||||
|
if(check_console() == false)
|
||||||
|
{
|
||||||
|
return(__io_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
long lCount = WriteCharsToConsole(reinterpret_cast<char *>(pBuffer), static_cast<long>(*pCount));
|
||||||
|
*pCount = static_cast<size_t>(lCount);
|
||||||
|
if(lCount == -1L)
|
||||||
|
{
|
||||||
|
return(__io_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return(__no_io_error);
|
||||||
|
}
|
||||||
58
src/mac/msl_replacements/malloc.cpp
Normal file
58
src/mac/msl_replacements/malloc.cpp
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// Mac Murrett
|
||||||
|
//
|
||||||
|
// 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. Mac Murrett makes no representations
|
||||||
|
// about the suitability of this software for any purpose. It is
|
||||||
|
// provided "as is" without express or implied warranty.
|
||||||
|
//
|
||||||
|
// See http://www.boost.org for most recent version including documentation.
|
||||||
|
|
||||||
|
//
|
||||||
|
// includes
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
#include <Multiprocessing.h>
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// using declarations
|
||||||
|
//
|
||||||
|
|
||||||
|
using std::size_t;
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
//
|
||||||
|
// prototypes
|
||||||
|
//
|
||||||
|
|
||||||
|
void *malloc(size_t ulSize);
|
||||||
|
void free(void *pBlock);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// MSL function replacements
|
||||||
|
//
|
||||||
|
|
||||||
|
// all allocation/deallocation currently goes through MPAllocateAligned/MPFree. This
|
||||||
|
// solution is sub-optimal at best, but will have to do for now.
|
||||||
|
void *malloc(size_t ulSize)
|
||||||
|
{
|
||||||
|
static bool bIgnored = MPLibraryIsLoaded();
|
||||||
|
return(MPAllocateAligned(ulSize, kMPAllocateDefaultAligned, 0UL));
|
||||||
|
}
|
||||||
|
|
||||||
|
void free(void *pBlock)
|
||||||
|
{
|
||||||
|
if(pBlock == NULL) return;
|
||||||
|
MPFree(pBlock);
|
||||||
|
}
|
||||||
105
src/mac/msl_replacements/news_and_deletes.cpp
Normal file
105
src/mac/msl_replacements/news_and_deletes.cpp
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// Mac Murrett
|
||||||
|
//
|
||||||
|
// 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. Mac Murrett makes no representations
|
||||||
|
// about the suitability of this software for any purpose. It is
|
||||||
|
// provided "as is" without express or implied warranty.
|
||||||
|
//
|
||||||
|
// See http://www.boost.org for most recent version including documentation.
|
||||||
|
|
||||||
|
//
|
||||||
|
// includes
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
#include <Multiprocessing.h>
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// using declarations
|
||||||
|
//
|
||||||
|
|
||||||
|
using std::size_t;
|
||||||
|
using std::bad_alloc;
|
||||||
|
using std::nothrow_t;
|
||||||
|
using std::nothrow;
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// local utility functions
|
||||||
|
//
|
||||||
|
|
||||||
|
// all allocation/deallocation currently goes through MPAllocateAligned/MPFree. This
|
||||||
|
// solution is sub-optimal at best, but will have to do for now.
|
||||||
|
inline static void *allocate(size_t ulSize, const nothrow_t &)
|
||||||
|
{
|
||||||
|
static bool bIgnored = MPLibraryIsLoaded();
|
||||||
|
return(MPAllocateAligned(ulSize, kMPAllocateDefaultAligned, 0UL));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static void *allocate(size_t ulSize)
|
||||||
|
{
|
||||||
|
void *pBlock = allocate(ulSize, nothrow);
|
||||||
|
if(pBlock == NULL)
|
||||||
|
throw(bad_alloc());
|
||||||
|
return(pBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static void deallocate(void *pBlock)
|
||||||
|
{
|
||||||
|
if(pBlock == NULL) return;
|
||||||
|
MPFree(pBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// global operators
|
||||||
|
//
|
||||||
|
|
||||||
|
void *operator new(size_t ulSize)
|
||||||
|
{
|
||||||
|
return(allocate(ulSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
void *operator new[](size_t ulSize)
|
||||||
|
{
|
||||||
|
return(allocate(ulSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void *operator new(size_t ulSize, const nothrow_t &rNoThrow)
|
||||||
|
{
|
||||||
|
return(allocate(ulSize, rNoThrow));
|
||||||
|
}
|
||||||
|
|
||||||
|
void *operator new[](size_t ulSize, const nothrow_t &rNoThrow)
|
||||||
|
{
|
||||||
|
return(allocate(ulSize, rNoThrow));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void operator delete(void *pBlock)
|
||||||
|
{
|
||||||
|
deallocate(pBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator delete[](void *pBlock)
|
||||||
|
{
|
||||||
|
deallocate(pBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void operator delete(void *pBlock, const nothrow_t &)
|
||||||
|
{
|
||||||
|
deallocate(pBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator delete[](void *pBlock, const nothrow_t &)
|
||||||
|
{
|
||||||
|
deallocate(pBlock);
|
||||||
|
}
|
||||||
156
src/mac/msl_replacements/time.cpp
Normal file
156
src/mac/msl_replacements/time.cpp
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// Mac Murrett
|
||||||
|
//
|
||||||
|
// 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. Mac Murrett makes no representations
|
||||||
|
// about the suitability of this software for any purpose. It is
|
||||||
|
// provided "as is" without express or implied warranty.
|
||||||
|
//
|
||||||
|
// See http://www.boost.org for most recent version including documentation.
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
// we include timesize.mac.h to get whether or not __TIMESIZE_DOUBLE__ is
|
||||||
|
// defined. This is not safe, given that __TIMESIZE_DOUBLE__ affects MSL
|
||||||
|
// at MSL's compile time, not ours, so be forgiving if you have changed it
|
||||||
|
// since you have built MSL.
|
||||||
|
#include <timesize.mac.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include <boost/thread/detail/force_cast.hpp>
|
||||||
|
#include <boost/thread/xtime.hpp>
|
||||||
|
|
||||||
|
#include "execution_context.hpp"
|
||||||
|
|
||||||
|
#include <DriverServices.h>
|
||||||
|
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
clock_t __get_clock();
|
||||||
|
time_t __get_time();
|
||||||
|
int __to_gm_time(time_t *pTime);
|
||||||
|
int __is_dst();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline uint64_t get_nanoseconds()
|
||||||
|
{
|
||||||
|
using boost::detail::thread::force_cast;
|
||||||
|
return(force_cast<uint64_t>(AbsoluteToNanoseconds(UpTime())));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __TIMESIZE_DOUBLE__
|
||||||
|
|
||||||
|
// return number of microseconds since startup as a double
|
||||||
|
clock_t __get_clock()
|
||||||
|
{
|
||||||
|
static const double k_dNanosecondsPerMicrosecond(1000.0);
|
||||||
|
|
||||||
|
return(get_nanoseconds() / k_dNanosecondsPerMicrosecond);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
// return number of ticks (60th of a second) since startup as a long
|
||||||
|
clock_t __get_clock()
|
||||||
|
{
|
||||||
|
static const uint64_t k_ullTicksPerSecond(60ULL);
|
||||||
|
static const uint64_t k_ullNanosecondsPerSecond(1000ULL * 1000ULL * 1000ULL);
|
||||||
|
static const uint64_t k_ullNanosecondsPerTick(k_ullNanosecondsPerSecond / k_ullTicksPerSecond);
|
||||||
|
|
||||||
|
return(get_nanoseconds() / k_ullNanosecondsPerTick);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// return number of seconds elapsed since Jan 1, 1970
|
||||||
|
time_t __get_time()
|
||||||
|
{
|
||||||
|
boost::xtime sTime;
|
||||||
|
int nType = boost::xtime_get(&sTime, boost::TIME_UTC);
|
||||||
|
assert(nType == boost::TIME_UTC);
|
||||||
|
return(static_cast<time_t>(sTime.sec));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline MachineLocation &read_location()
|
||||||
|
{
|
||||||
|
static MachineLocation s_sLocation;
|
||||||
|
assert(boost::threads::mac::at_st());
|
||||||
|
ReadLocation(&s_sLocation);
|
||||||
|
return(s_sLocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline MachineLocation &get_location()
|
||||||
|
{
|
||||||
|
static MachineLocation &s_rLocation(read_location());
|
||||||
|
return(s_rLocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// force the machine location to be cached at static initlialization
|
||||||
|
static MachineLocation &g_rIgnored(get_location());
|
||||||
|
|
||||||
|
static inline long calculate_delta()
|
||||||
|
{
|
||||||
|
MachineLocation &rLocation(get_location());
|
||||||
|
|
||||||
|
// gmtDelta is a 24-bit, signed integer. We need to strip out the lower 24 bits,
|
||||||
|
// then sign-extend what we have.
|
||||||
|
long lDelta = rLocation.u.gmtDelta & 0x00ffffffL;
|
||||||
|
if((lDelta & 0x00800000L) != 0L)
|
||||||
|
{
|
||||||
|
lDelta |= 0xFF000000;
|
||||||
|
}
|
||||||
|
return(lDelta);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool check_if_location_is_broken()
|
||||||
|
{
|
||||||
|
MachineLocation &rLocation(get_location());
|
||||||
|
if(rLocation.latitude == 0 && rLocation.longitude == 0 && rLocation.u.gmtDelta == 0)
|
||||||
|
return(true);
|
||||||
|
return(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool location_is_broken()
|
||||||
|
{
|
||||||
|
static bool s_bLocationIsBroken(check_if_location_is_broken());
|
||||||
|
return(s_bLocationIsBroken);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// translate time to GMT
|
||||||
|
int __to_gm_time(time_t *pTime)
|
||||||
|
{
|
||||||
|
if(location_is_broken())
|
||||||
|
{
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static long s_lDelta(calculate_delta());
|
||||||
|
*pTime -= s_lDelta;
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline bool is_daylight_savings_time()
|
||||||
|
{
|
||||||
|
MachineLocation &rLocation(get_location());
|
||||||
|
return(rLocation.u.dlsDelta != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if we're in daylight savings time
|
||||||
|
int __is_dst()
|
||||||
|
{
|
||||||
|
if(location_is_broken())
|
||||||
|
{
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
static bool bIsDaylightSavingsTime(is_daylight_savings_time());
|
||||||
|
return(static_cast<int>(bIsDaylightSavingsTime));
|
||||||
|
}
|
||||||
63
src/mac/os.cpp
Normal file
63
src/mac/os.cpp
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// Mac Murrett
|
||||||
|
//
|
||||||
|
// 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. Mac Murrett makes no representations
|
||||||
|
// about the suitability of this software for any purpose. It is
|
||||||
|
// provided "as is" without express or implied warranty.
|
||||||
|
//
|
||||||
|
// See http://www.boost.org for most recent version including documentation.
|
||||||
|
|
||||||
|
#include "os.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#include <Gestalt.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
namespace threads {
|
||||||
|
|
||||||
|
namespace mac {
|
||||||
|
|
||||||
|
namespace os {
|
||||||
|
|
||||||
|
|
||||||
|
// read the OS version from Gestalt
|
||||||
|
static inline long get_version()
|
||||||
|
{
|
||||||
|
long lVersion;
|
||||||
|
OSErr nErr = Gestalt(gestaltSystemVersion, &lVersion);
|
||||||
|
assert(nErr == noErr);
|
||||||
|
return(lVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// check if we're running under Mac OS X and cache that information
|
||||||
|
bool x()
|
||||||
|
{
|
||||||
|
static bool bX = (version() >= 0x1000);
|
||||||
|
return(bX);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// read the OS version and cache it
|
||||||
|
long version()
|
||||||
|
{
|
||||||
|
static long lVersion = get_version();
|
||||||
|
return(lVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace os
|
||||||
|
|
||||||
|
} // namespace mac
|
||||||
|
|
||||||
|
} // namespace threads
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
43
src/mac/os.hpp
Normal file
43
src/mac/os.hpp
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// Mac Murrett
|
||||||
|
//
|
||||||
|
// 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. Mac Murrett makes no representations
|
||||||
|
// about the suitability of this software for any purpose. It is
|
||||||
|
// provided "as is" without express or implied warranty.
|
||||||
|
//
|
||||||
|
// See http://www.boost.org for most recent version including documentation.
|
||||||
|
|
||||||
|
#ifndef BOOST_OS_MJM012402_HPP
|
||||||
|
#define BOOST_OS_MJM012402_HPP
|
||||||
|
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
namespace threads {
|
||||||
|
|
||||||
|
namespace mac {
|
||||||
|
|
||||||
|
namespace os {
|
||||||
|
|
||||||
|
|
||||||
|
// functions to determine the OS environment. With namespaces, you get a cute call:
|
||||||
|
// mac::os::x
|
||||||
|
|
||||||
|
bool x();
|
||||||
|
long version();
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace os
|
||||||
|
|
||||||
|
} // namespace mac
|
||||||
|
|
||||||
|
} // namespace threads
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BOOST_OS_MJM012402_HPP
|
||||||
52
src/mac/ot_context.cpp
Normal file
52
src/mac/ot_context.cpp
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// Mac Murrett
|
||||||
|
//
|
||||||
|
// 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. Mac Murrett makes no representations
|
||||||
|
// about the suitability of this software for any purpose. It is
|
||||||
|
// provided "as is" without express or implied warranty.
|
||||||
|
//
|
||||||
|
// See http://www.boost.org for most recent version including documentation.
|
||||||
|
|
||||||
|
#include "ot_context.hpp"
|
||||||
|
|
||||||
|
#include "execution_context.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
namespace threads {
|
||||||
|
|
||||||
|
namespace mac {
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
|
||||||
|
ot_context::ot_context()
|
||||||
|
{
|
||||||
|
assert(at_st());
|
||||||
|
|
||||||
|
OSStatus lStatus = InitOpenTransportInContext(0UL, &m_pContext);
|
||||||
|
// TODO - throw on error
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
}
|
||||||
|
|
||||||
|
ot_context::~ot_context()
|
||||||
|
{
|
||||||
|
CloseOpenTransportInContext(m_pContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
} // namespace mac
|
||||||
|
|
||||||
|
} // namespace threads
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
64
src/mac/ot_context.hpp
Normal file
64
src/mac/ot_context.hpp
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// Mac Murrett
|
||||||
|
//
|
||||||
|
// 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. Mac Murrett makes no representations
|
||||||
|
// about the suitability of this software for any purpose. It is
|
||||||
|
// provided "as is" without express or implied warranty.
|
||||||
|
//
|
||||||
|
// See http://www.boost.org for most recent version including documentation.
|
||||||
|
|
||||||
|
#ifndef BOOST_OT_CONTEXT_MJM012402_HPP
|
||||||
|
#define BOOST_OT_CONTEXT_MJM012402_HPP
|
||||||
|
|
||||||
|
|
||||||
|
#include <OpenTransport.h>
|
||||||
|
|
||||||
|
#include <boost/utility.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
namespace threads {
|
||||||
|
|
||||||
|
namespace mac {
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
|
||||||
|
// class ot_context is intended to be used only as a singleton. All that this class
|
||||||
|
// does is ask OpenTransport to create him an OTClientContextPtr, and then doles
|
||||||
|
// this out to anyone who wants it. ot_context should only be instantiated at
|
||||||
|
// system task time.
|
||||||
|
|
||||||
|
class ot_context: private noncopyable
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
ot_context();
|
||||||
|
~ot_context();
|
||||||
|
|
||||||
|
public:
|
||||||
|
OTClientContextPtr get_context();
|
||||||
|
|
||||||
|
private:
|
||||||
|
OTClientContextPtr m_pContext;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
inline OTClientContextPtr ot_context::get_context()
|
||||||
|
{ return(m_pContext); }
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
} // namespace mac
|
||||||
|
|
||||||
|
} // namespace threads
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BOOST_OT_CONTEXT_MJM012402_HPP
|
||||||
82
src/mac/package.hpp
Normal file
82
src/mac/package.hpp
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// Mac Murrett
|
||||||
|
//
|
||||||
|
// 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. Mac Murrett makes no representations
|
||||||
|
// about the suitability of this software for any purpose. It is
|
||||||
|
// provided "as is" without express or implied warranty.
|
||||||
|
//
|
||||||
|
// See http://www.boost.org for most recent version including documentation.
|
||||||
|
|
||||||
|
#ifndef BOOST_PACKAGE_MJM012402_HPP
|
||||||
|
#define BOOST_PACKAGE_MJM012402_HPP
|
||||||
|
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
namespace threads {
|
||||||
|
|
||||||
|
namespace mac {
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
|
||||||
|
class base_package: private noncopyable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void accept() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class R>
|
||||||
|
class package: public base_package
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
inline package(function<R> &rFunctor):
|
||||||
|
m_rFunctor(rFunctor)
|
||||||
|
{ /* no-op */ }
|
||||||
|
inline ~package()
|
||||||
|
{ /* no-op */ }
|
||||||
|
|
||||||
|
virtual void accept()
|
||||||
|
{ m_oR = m_rFunctor(); }
|
||||||
|
inline R return_value()
|
||||||
|
{ return(m_oR); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
function<R> &m_rFunctor;
|
||||||
|
R m_oR;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
class package<void>: public base_package
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
inline package(function<void> &rFunctor):
|
||||||
|
m_rFunctor(rFunctor)
|
||||||
|
{ /* no-op */ }
|
||||||
|
inline ~package()
|
||||||
|
{ /* no-op */ }
|
||||||
|
|
||||||
|
virtual void accept()
|
||||||
|
{ m_rFunctor(); }
|
||||||
|
inline void return_value()
|
||||||
|
{ return; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
function<void> &m_rFunctor;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
} // namespace mac
|
||||||
|
|
||||||
|
} // namespace threads
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BOOST_PACKAGE_MJM012402_HPP
|
||||||
103
src/mac/periodical.hpp
Normal file
103
src/mac/periodical.hpp
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// Mac Murrett
|
||||||
|
//
|
||||||
|
// 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. Mac Murrett makes no representations
|
||||||
|
// about the suitability of this software for any purpose. It is
|
||||||
|
// provided "as is" without express or implied warranty.
|
||||||
|
//
|
||||||
|
// See http://www.boost.org for most recent version including documentation.
|
||||||
|
|
||||||
|
#ifndef BOOST_PERIODICAL_MJM012402_HPP
|
||||||
|
#define BOOST_PERIODICAL_MJM012402_HPP
|
||||||
|
|
||||||
|
|
||||||
|
#include <boost/function.hpp>
|
||||||
|
#include <boost/utility.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
namespace threads {
|
||||||
|
|
||||||
|
namespace mac {
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
|
||||||
|
// class periodical inherits from its template parameter, which should follow the
|
||||||
|
// pattern set by classes dt_scheduler and st_scheduler. periodical knows how to
|
||||||
|
// call a boost::function, where the xx_scheduler classes only know to to call a
|
||||||
|
// member periodically.
|
||||||
|
|
||||||
|
template<class Scheduler>
|
||||||
|
class periodical: private noncopyable, private Scheduler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
periodical(function<void> &rFunction);
|
||||||
|
~periodical();
|
||||||
|
|
||||||
|
public:
|
||||||
|
void start();
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void periodic_function();
|
||||||
|
|
||||||
|
private:
|
||||||
|
function<void> m_oFunction;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<class Scheduler>
|
||||||
|
periodical<Scheduler>::periodical(function<void> &rFunction):
|
||||||
|
m_oFunction(rFunction)
|
||||||
|
{
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Scheduler>
|
||||||
|
periodical<Scheduler>::~periodical()
|
||||||
|
{
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Scheduler>
|
||||||
|
void periodical<Scheduler>::start()
|
||||||
|
{
|
||||||
|
start_polling();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Scheduler>
|
||||||
|
void periodical<Scheduler>::stop()
|
||||||
|
{
|
||||||
|
stop_polling();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class Scheduler>
|
||||||
|
inline void periodical<Scheduler>::periodic_function()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
m_oFunction();
|
||||||
|
}
|
||||||
|
catch(...)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
} // namespace mac
|
||||||
|
|
||||||
|
} // namespace threads
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BOOST_PERIODICAL_MJM012402_HPP
|
||||||
15
src/mac/prefix.hpp
Normal file
15
src/mac/prefix.hpp
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// Mac Murrett
|
||||||
|
//
|
||||||
|
// 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. Mac Murrett makes no representations
|
||||||
|
// about the suitability of this software for any purpose. It is
|
||||||
|
// provided "as is" without express or implied warranty.
|
||||||
|
//
|
||||||
|
// See http://www.boost.org for most recent version including documentation.
|
||||||
|
|
||||||
|
#define NDEBUG
|
||||||
|
#define TARGET_CARBON 1
|
||||||
54
src/mac/remote_call_manager.cpp
Normal file
54
src/mac/remote_call_manager.cpp
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// Mac Murrett
|
||||||
|
//
|
||||||
|
// 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. Mac Murrett makes no representations
|
||||||
|
// about the suitability of this software for any purpose. It is
|
||||||
|
// provided "as is" without express or implied warranty.
|
||||||
|
//
|
||||||
|
// See http://www.boost.org for most recent version including documentation.
|
||||||
|
|
||||||
|
#include "remote_call_manager.hpp"
|
||||||
|
|
||||||
|
#include <boost/bind.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
namespace threads {
|
||||||
|
|
||||||
|
namespace mac {
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
|
||||||
|
using detail::delivery_man;
|
||||||
|
|
||||||
|
|
||||||
|
remote_call_manager::remote_call_manager():
|
||||||
|
m_oDTDeliveryMan(),
|
||||||
|
m_oSTDeliveryMan(),
|
||||||
|
m_oDTFunction(bind(&delivery_man::accept_deliveries, &m_oDTDeliveryMan)),
|
||||||
|
m_oSTFunction(bind(&delivery_man::accept_deliveries, &m_oSTDeliveryMan)),
|
||||||
|
m_oDTPeriodical(m_oDTFunction),
|
||||||
|
m_oSTPeriodical(m_oSTFunction)
|
||||||
|
{
|
||||||
|
m_oDTPeriodical.start();
|
||||||
|
m_oSTPeriodical.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
remote_call_manager::~remote_call_manager()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
} // namespace mac
|
||||||
|
|
||||||
|
} // namespace threads
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
108
src/mac/remote_call_manager.hpp
Normal file
108
src/mac/remote_call_manager.hpp
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// Mac Murrett
|
||||||
|
//
|
||||||
|
// 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. Mac Murrett makes no representations
|
||||||
|
// about the suitability of this software for any purpose. It is
|
||||||
|
// provided "as is" without express or implied warranty.
|
||||||
|
//
|
||||||
|
// See http://www.boost.org for most recent version including documentation.
|
||||||
|
|
||||||
|
#ifndef BOOST_REMOTE_CALL_MANAGER_MJM012402_HPP
|
||||||
|
#define BOOST_REMOTE_CALL_MANAGER_MJM012402_HPP
|
||||||
|
|
||||||
|
|
||||||
|
#include <boost/utility.hpp>
|
||||||
|
|
||||||
|
#include "delivery_man.hpp"
|
||||||
|
#include "dt_scheduler.hpp"
|
||||||
|
#include "periodical.hpp"
|
||||||
|
#include "execution_context.hpp"
|
||||||
|
#include "st_scheduler.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
namespace threads {
|
||||||
|
|
||||||
|
namespace mac {
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
|
||||||
|
// class remote_call_manager is used by the remote call functions (dt_remote_call and
|
||||||
|
// st_remote_call) to execute functions in non-MP contexts.
|
||||||
|
|
||||||
|
class remote_call_manager: private noncopyable
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
remote_call_manager();
|
||||||
|
~remote_call_manager();
|
||||||
|
|
||||||
|
public:
|
||||||
|
template<class R>
|
||||||
|
R execute_at_dt(function<R> &rFunctor);
|
||||||
|
template<class R>
|
||||||
|
R execute_at_st(function<R> &rFunctor);
|
||||||
|
|
||||||
|
private:
|
||||||
|
template<class R>
|
||||||
|
static R execute_now(function<R> &rFunctor);
|
||||||
|
|
||||||
|
private:
|
||||||
|
delivery_man m_oDTDeliveryMan;
|
||||||
|
delivery_man m_oSTDeliveryMan;
|
||||||
|
function<void> m_oDTFunction;
|
||||||
|
function<void> m_oSTFunction;
|
||||||
|
periodical<dt_scheduler> m_oDTPeriodical;
|
||||||
|
periodical<st_scheduler> m_oSTPeriodical;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<class R>
|
||||||
|
/*static*/ inline R remote_call_manager::execute_now(function<R> &rFunctor)
|
||||||
|
{
|
||||||
|
return(rFunctor());
|
||||||
|
}
|
||||||
|
template<>
|
||||||
|
/*static*/ inline void remote_call_manager::execute_now<void>(function<void> &rFunctor)
|
||||||
|
{
|
||||||
|
rFunctor();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class R>
|
||||||
|
inline R remote_call_manager::execute_at_dt(function<R> &rFunctor)
|
||||||
|
{
|
||||||
|
if(at_mp())
|
||||||
|
{
|
||||||
|
return(m_oDTDeliveryMan.deliver(rFunctor));
|
||||||
|
}
|
||||||
|
return(execute_now(rFunctor));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class R>
|
||||||
|
inline R remote_call_manager::execute_at_st(function<R> &rFunctor)
|
||||||
|
{
|
||||||
|
if(at_mp())
|
||||||
|
{
|
||||||
|
return(m_oSTDeliveryMan.deliver(rFunctor));
|
||||||
|
}
|
||||||
|
assert(at_st());
|
||||||
|
return(execute_now(rFunctor));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
} // namespace mac
|
||||||
|
|
||||||
|
} // namespace threads
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BOOST_REMOTE_CALL_MANAGER_MJM012402_HPP
|
||||||
163
src/mac/remote_calls.hpp
Normal file
163
src/mac/remote_calls.hpp
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// Mac Murrett
|
||||||
|
//
|
||||||
|
// 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. Mac Murrett makes no representations
|
||||||
|
// about the suitability of this software for any purpose. It is
|
||||||
|
// provided "as is" without express or implied warranty.
|
||||||
|
//
|
||||||
|
// See http://www.boost.org for most recent version including documentation.
|
||||||
|
|
||||||
|
#ifndef BOOST_REMOTE_CALLS_MJM012402_HPP
|
||||||
|
#define BOOST_REMOTE_CALLS_MJM012402_HPP
|
||||||
|
|
||||||
|
|
||||||
|
#include <boost/bind.hpp>
|
||||||
|
|
||||||
|
#include "remote_call_manager.hpp"
|
||||||
|
#include <boost/thread/detail/singleton.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
// this file contains macros to generate functions with the signatures:
|
||||||
|
// ReturnType st_remote_call([pascal] ReturnType (*pfnFunction)(
|
||||||
|
// [Argument1Type[, Argument2Type[...]]])
|
||||||
|
// [, Argument1Type oArgument1[, Argument2Type oArgument2[...]]])
|
||||||
|
// and
|
||||||
|
// ReturnType dt_remote_call([pascal] ReturnType (*pfnFunction)(
|
||||||
|
// [Argument1Type[, Argument2Type[...]]])
|
||||||
|
// [, Argument1Type oArgument1[, Argument2Type oArgument2[...]]])
|
||||||
|
// in other words, identical to the function pointer versions of boost::bind, but
|
||||||
|
// with the return type returned. The purpose of these functions is to be able to
|
||||||
|
// request that a function be called at system task time or deferred task time, then
|
||||||
|
// sleep until it is called, and finally get back its return value.
|
||||||
|
|
||||||
|
#define BOOST_REMOTE_CALL_CLASS_LIST_0
|
||||||
|
#define BOOST_REMOTE_CALL_CLASS_LIST_1 BOOST_REMOTE_CALL_CLASS_LIST_0, class A1
|
||||||
|
#define BOOST_REMOTE_CALL_CLASS_LIST_2 BOOST_REMOTE_CALL_CLASS_LIST_1, class A2
|
||||||
|
#define BOOST_REMOTE_CALL_CLASS_LIST_3 BOOST_REMOTE_CALL_CLASS_LIST_2, class A3
|
||||||
|
#define BOOST_REMOTE_CALL_CLASS_LIST_4 BOOST_REMOTE_CALL_CLASS_LIST_3, class A4
|
||||||
|
#define BOOST_REMOTE_CALL_CLASS_LIST_5 BOOST_REMOTE_CALL_CLASS_LIST_4, class A5
|
||||||
|
#define BOOST_REMOTE_CALL_CLASS_LIST_6 BOOST_REMOTE_CALL_CLASS_LIST_5, class A6
|
||||||
|
#define BOOST_REMOTE_CALL_CLASS_LIST_7 BOOST_REMOTE_CALL_CLASS_LIST_6, class A7
|
||||||
|
#define BOOST_REMOTE_CALL_CLASS_LIST_8 BOOST_REMOTE_CALL_CLASS_LIST_7, class A8
|
||||||
|
#define BOOST_REMOTE_CALL_CLASS_LIST_9 BOOST_REMOTE_CALL_CLASS_LIST_8, class A9
|
||||||
|
|
||||||
|
|
||||||
|
#define BOOST_REMOTE_CALL_ARGUMENT_LIST_0
|
||||||
|
#define BOOST_REMOTE_CALL_ARGUMENT_LIST_1 BOOST_REMOTE_CALL_ARGUMENT_LIST_0 A1 oA1
|
||||||
|
#define BOOST_REMOTE_CALL_ARGUMENT_LIST_2 BOOST_REMOTE_CALL_ARGUMENT_LIST_1, A2 oA2
|
||||||
|
#define BOOST_REMOTE_CALL_ARGUMENT_LIST_3 BOOST_REMOTE_CALL_ARGUMENT_LIST_2, A3 oA3
|
||||||
|
#define BOOST_REMOTE_CALL_ARGUMENT_LIST_4 BOOST_REMOTE_CALL_ARGUMENT_LIST_3, A4 oA4
|
||||||
|
#define BOOST_REMOTE_CALL_ARGUMENT_LIST_5 BOOST_REMOTE_CALL_ARGUMENT_LIST_4, A5 oA5
|
||||||
|
#define BOOST_REMOTE_CALL_ARGUMENT_LIST_6 BOOST_REMOTE_CALL_ARGUMENT_LIST_5, A6 oA6
|
||||||
|
#define BOOST_REMOTE_CALL_ARGUMENT_LIST_7 BOOST_REMOTE_CALL_ARGUMENT_LIST_6, A7 oA7
|
||||||
|
#define BOOST_REMOTE_CALL_ARGUMENT_LIST_8 BOOST_REMOTE_CALL_ARGUMENT_LIST_7, A8 oA8
|
||||||
|
#define BOOST_REMOTE_CALL_ARGUMENT_LIST_9 BOOST_REMOTE_CALL_ARGUMENT_LIST_8, A9 oA9
|
||||||
|
|
||||||
|
|
||||||
|
#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_0
|
||||||
|
#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_1 BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_0, oA1
|
||||||
|
#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_2 BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_1, oA2
|
||||||
|
#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_3 BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_2, oA3
|
||||||
|
#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_4 BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_3, oA4
|
||||||
|
#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_5 BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_4, oA5
|
||||||
|
#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_6 BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_5, oA6
|
||||||
|
#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_7 BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_6, oA7
|
||||||
|
#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_8 BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_7, oA8
|
||||||
|
#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_9 BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_8, oA9
|
||||||
|
|
||||||
|
|
||||||
|
#define BOOST_REMOTE_CALL_COMMA_0
|
||||||
|
#define BOOST_REMOTE_CALL_COMMA_1 ,
|
||||||
|
#define BOOST_REMOTE_CALL_COMMA_2 ,
|
||||||
|
#define BOOST_REMOTE_CALL_COMMA_3 ,
|
||||||
|
#define BOOST_REMOTE_CALL_COMMA_4 ,
|
||||||
|
#define BOOST_REMOTE_CALL_COMMA_5 ,
|
||||||
|
#define BOOST_REMOTE_CALL_COMMA_6 ,
|
||||||
|
#define BOOST_REMOTE_CALL_COMMA_7 ,
|
||||||
|
#define BOOST_REMOTE_CALL_COMMA_8 ,
|
||||||
|
#define BOOST_REMOTE_CALL_COMMA_9 ,
|
||||||
|
|
||||||
|
|
||||||
|
// this is the macro that ties it all together. From here, we generate all forms of
|
||||||
|
// dt_remote_call and st_remote_call.
|
||||||
|
|
||||||
|
#define BOOST_REMOTE_CALL(context, stack, n) \
|
||||||
|
template<class R BOOST_REMOTE_CALL_CLASS_LIST_ ## n> \
|
||||||
|
inline R context ## _remote_call(stack R (*pfnF)( \
|
||||||
|
BOOST_REMOTE_CALL_ARGUMENT_LIST_ ## n) \
|
||||||
|
BOOST_REMOTE_CALL_COMMA_ ## n \
|
||||||
|
BOOST_REMOTE_CALL_ARGUMENT_LIST_ ## n) \
|
||||||
|
{ \
|
||||||
|
using ::boost::detail::thread::singleton; \
|
||||||
|
using detail::remote_call_manager; \
|
||||||
|
function<R> oFunc(bind(pfnF BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_ ## n)); \
|
||||||
|
remote_call_manager &rManager(singleton<remote_call_manager>::instance()); \
|
||||||
|
return(rManager.execute_at_ ## context(oFunc)); \
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
namespace threads {
|
||||||
|
|
||||||
|
namespace mac {
|
||||||
|
|
||||||
|
|
||||||
|
BOOST_REMOTE_CALL(st, , 0)
|
||||||
|
BOOST_REMOTE_CALL(st, , 1)
|
||||||
|
BOOST_REMOTE_CALL(st, , 2)
|
||||||
|
BOOST_REMOTE_CALL(st, , 3)
|
||||||
|
BOOST_REMOTE_CALL(st, , 4)
|
||||||
|
BOOST_REMOTE_CALL(st, , 5)
|
||||||
|
BOOST_REMOTE_CALL(st, , 6)
|
||||||
|
BOOST_REMOTE_CALL(st, , 7)
|
||||||
|
BOOST_REMOTE_CALL(st, , 8)
|
||||||
|
BOOST_REMOTE_CALL(st, , 9)
|
||||||
|
|
||||||
|
BOOST_REMOTE_CALL(dt, , 0)
|
||||||
|
BOOST_REMOTE_CALL(dt, , 1)
|
||||||
|
BOOST_REMOTE_CALL(dt, , 2)
|
||||||
|
BOOST_REMOTE_CALL(dt, , 3)
|
||||||
|
BOOST_REMOTE_CALL(dt, , 4)
|
||||||
|
BOOST_REMOTE_CALL(dt, , 5)
|
||||||
|
BOOST_REMOTE_CALL(dt, , 6)
|
||||||
|
BOOST_REMOTE_CALL(dt, , 7)
|
||||||
|
BOOST_REMOTE_CALL(dt, , 8)
|
||||||
|
BOOST_REMOTE_CALL(dt, , 9)
|
||||||
|
|
||||||
|
|
||||||
|
BOOST_REMOTE_CALL(st, pascal, 0)
|
||||||
|
BOOST_REMOTE_CALL(st, pascal, 1)
|
||||||
|
BOOST_REMOTE_CALL(st, pascal, 2)
|
||||||
|
BOOST_REMOTE_CALL(st, pascal, 3)
|
||||||
|
BOOST_REMOTE_CALL(st, pascal, 4)
|
||||||
|
BOOST_REMOTE_CALL(st, pascal, 5)
|
||||||
|
BOOST_REMOTE_CALL(st, pascal, 6)
|
||||||
|
BOOST_REMOTE_CALL(st, pascal, 7)
|
||||||
|
BOOST_REMOTE_CALL(st, pascal, 8)
|
||||||
|
BOOST_REMOTE_CALL(st, pascal, 9)
|
||||||
|
|
||||||
|
BOOST_REMOTE_CALL(dt, pascal, 0)
|
||||||
|
BOOST_REMOTE_CALL(dt, pascal, 1)
|
||||||
|
BOOST_REMOTE_CALL(dt, pascal, 2)
|
||||||
|
BOOST_REMOTE_CALL(dt, pascal, 3)
|
||||||
|
BOOST_REMOTE_CALL(dt, pascal, 4)
|
||||||
|
BOOST_REMOTE_CALL(dt, pascal, 5)
|
||||||
|
BOOST_REMOTE_CALL(dt, pascal, 6)
|
||||||
|
BOOST_REMOTE_CALL(dt, pascal, 7)
|
||||||
|
BOOST_REMOTE_CALL(dt, pascal, 8)
|
||||||
|
BOOST_REMOTE_CALL(dt, pascal, 9)
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace mac
|
||||||
|
|
||||||
|
} // namespace threads
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BOOST_REMOTE_CALLS_MJM012402_HPP
|
||||||
216
src/mac/safe.cpp
Normal file
216
src/mac/safe.cpp
Normal file
@@ -0,0 +1,216 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// Mac Murrett
|
||||||
|
//
|
||||||
|
// 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. Mac Murrett makes no representations
|
||||||
|
// about the suitability of this software for any purpose. It is
|
||||||
|
// provided "as is" without express or implied warranty.
|
||||||
|
//
|
||||||
|
// See http://www.boost.org for most recent version including documentation.
|
||||||
|
|
||||||
|
#include <DriverServices.h>
|
||||||
|
#include <Events.h>
|
||||||
|
#include <Multiprocessing.h>
|
||||||
|
#include <Threads.h>
|
||||||
|
|
||||||
|
#include <boost/bind.hpp>
|
||||||
|
#include <boost/function.hpp>
|
||||||
|
|
||||||
|
#include <boost/thread/detail/force_cast.hpp>
|
||||||
|
#include <limits>
|
||||||
|
#include "execution_context.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
using boost::detail::thread::force_cast;
|
||||||
|
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
namespace threads {
|
||||||
|
|
||||||
|
namespace mac {
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
|
||||||
|
static OSStatus safe_wait(function<OSStatus, Duration> &rFunction, Duration lDuration);
|
||||||
|
|
||||||
|
|
||||||
|
// we call WNE to allow tasks that own the resource the blue is waiting on system
|
||||||
|
// task time, in case they are blocked on an ST remote call (or a memory allocation
|
||||||
|
// for that matter).
|
||||||
|
static void idle()
|
||||||
|
{
|
||||||
|
if(at_st())
|
||||||
|
{
|
||||||
|
EventRecord sEvent;
|
||||||
|
bool bEvent = WaitNextEvent(0U, &sEvent, 0UL, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
OSStatus safe_wait_on_semaphore(MPSemaphoreID pSemaphoreID, Duration lDuration)
|
||||||
|
{
|
||||||
|
function<OSStatus, Duration> oWaitOnSemaphore;
|
||||||
|
oWaitOnSemaphore = bind(MPWaitOnSemaphore, pSemaphoreID, _1);
|
||||||
|
return(safe_wait(oWaitOnSemaphore, lDuration));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
OSStatus safe_enter_critical_region(MPCriticalRegionID pCriticalRegionID, Duration lDuration, MPCriticalRegionID pCriticalRegionCriticalRegionID/* = kInvalidID*/)
|
||||||
|
{
|
||||||
|
if(pCriticalRegionCriticalRegionID != kInvalidID)
|
||||||
|
{
|
||||||
|
if(at_mp())
|
||||||
|
{
|
||||||
|
// enter the critical region's critical region
|
||||||
|
OSStatus lStatus = noErr;
|
||||||
|
AbsoluteTime sExpiration;
|
||||||
|
if(lDuration != kDurationImmediate && lDuration != kDurationForever)
|
||||||
|
{
|
||||||
|
sExpiration = AddDurationToAbsolute(lDuration, UpTime());
|
||||||
|
}
|
||||||
|
lStatus = MPEnterCriticalRegion(pCriticalRegionCriticalRegionID, lDuration);
|
||||||
|
assert(lStatus == noErr || lStatus == kMPTimeoutErr);
|
||||||
|
if(lStatus == noErr)
|
||||||
|
{
|
||||||
|
// calculate a new duration
|
||||||
|
if(lDuration != kDurationImmediate && lDuration != kDurationForever)
|
||||||
|
{
|
||||||
|
// check if we have any time left
|
||||||
|
AbsoluteTime sUpTime(UpTime());
|
||||||
|
if(force_cast<uint64_t>(sExpiration) > force_cast<uint64_t>(sUpTime))
|
||||||
|
{
|
||||||
|
// reset our duration to our remaining time
|
||||||
|
lDuration = AbsoluteDeltaToDuration(sExpiration, sUpTime);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// no time left
|
||||||
|
lDuration = kDurationImmediate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if we entered the critical region, exit it again
|
||||||
|
lStatus = MPExitCriticalRegion(pCriticalRegionCriticalRegionID);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// otherwise, give up
|
||||||
|
return(lStatus);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// if we're at system task time, try to enter the critical region's critical
|
||||||
|
// region until we succeed. MP tasks will block on this until we let it go.
|
||||||
|
OSStatus lStatus;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
lStatus = MPEnterCriticalRegion(pCriticalRegionCriticalRegionID, kDurationImmediate);
|
||||||
|
} while(lStatus == kMPTimeoutErr);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// try to enter the critical region
|
||||||
|
function<OSStatus, Duration> oEnterCriticalRegion;
|
||||||
|
oEnterCriticalRegion = bind(MPEnterCriticalRegion, pCriticalRegionID, _1);
|
||||||
|
OSStatus lStatus = safe_wait(oEnterCriticalRegion, lDuration);
|
||||||
|
|
||||||
|
// if we entered the critical region's critical region to get the critical region,
|
||||||
|
// exit the critical region's critical region.
|
||||||
|
if(pCriticalRegionCriticalRegionID != kInvalidID && at_mp() == false)
|
||||||
|
{
|
||||||
|
lStatus = MPExitCriticalRegion(pCriticalRegionCriticalRegionID);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
}
|
||||||
|
return(lStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus safe_wait_on_queue(MPQueueID pQueueID, void **pParam1, void **pParam2, void **pParam3, Duration lDuration)
|
||||||
|
{
|
||||||
|
function<OSStatus, Duration> oWaitOnQueue;
|
||||||
|
oWaitOnQueue = bind(MPWaitOnQueue, pQueueID, pParam1, pParam2, pParam3, _1);
|
||||||
|
return(safe_wait(oWaitOnQueue, lDuration));
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus safe_delay_until(AbsoluteTime *pWakeUpTime)
|
||||||
|
{
|
||||||
|
if(execution_context() == k_eExecutionContextMPTask)
|
||||||
|
{
|
||||||
|
return(MPDelayUntil(pWakeUpTime));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uint64_t ullWakeUpTime = force_cast<uint64_t>(*pWakeUpTime);
|
||||||
|
|
||||||
|
while(force_cast<uint64_t>(UpTime()) < ullWakeUpTime)
|
||||||
|
{
|
||||||
|
idle();
|
||||||
|
}
|
||||||
|
|
||||||
|
return(noErr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
OSStatus safe_wait(function<OSStatus, Duration> &rFunction, Duration lDuration)
|
||||||
|
{
|
||||||
|
if(execution_context() == k_eExecutionContextMPTask)
|
||||||
|
{
|
||||||
|
return(rFunction(lDuration));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uint64_t ullExpiration = 0ULL;
|
||||||
|
|
||||||
|
// get the expiration time in UpTime units
|
||||||
|
if(lDuration == kDurationForever)
|
||||||
|
{
|
||||||
|
ullExpiration = ::std::numeric_limits<uint64_t>::max();
|
||||||
|
}
|
||||||
|
else if(lDuration == kDurationImmediate)
|
||||||
|
{
|
||||||
|
ullExpiration = force_cast<uint64_t>(UpTime());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AbsoluteTime sExpiration = AddDurationToAbsolute(lDuration, UpTime());
|
||||||
|
ullExpiration = force_cast<uint64_t>(sExpiration);
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus lStatus;
|
||||||
|
bool bExpired = false;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
lStatus = rFunction(kDurationImmediate);
|
||||||
|
// mm - "if" #if 0'd out to allow task time to threads blocked on I/O
|
||||||
|
#if 0
|
||||||
|
if(lStatus == kMPTimeoutErr)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
idle();
|
||||||
|
}
|
||||||
|
if(lDuration != kDurationForever)
|
||||||
|
{
|
||||||
|
bExpired = (force_cast<uint64_t>(UpTime()) < ullExpiration);
|
||||||
|
}
|
||||||
|
} while(lStatus == kMPTimeoutErr && bExpired == false);
|
||||||
|
|
||||||
|
return(lStatus);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
} // namespace mac
|
||||||
|
|
||||||
|
} // namespace threads
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
47
src/mac/safe.hpp
Normal file
47
src/mac/safe.hpp
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// Mac Murrett
|
||||||
|
//
|
||||||
|
// 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. Mac Murrett makes no representations
|
||||||
|
// about the suitability of this software for any purpose. It is
|
||||||
|
// provided "as is" without express or implied warranty.
|
||||||
|
//
|
||||||
|
// See http://www.boost.org for most recent version including documentation.
|
||||||
|
|
||||||
|
#ifndef BOOST_SAFE_MJM012402_HPP
|
||||||
|
#define BOOST_SAFE_MJM012402_HPP
|
||||||
|
|
||||||
|
|
||||||
|
#include <Multiprocessing.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
namespace threads {
|
||||||
|
|
||||||
|
namespace mac {
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
|
||||||
|
// these functions are used to wain in an execution context-independent manor. All of these
|
||||||
|
// functions are both MP- and ST-safe.
|
||||||
|
|
||||||
|
OSStatus safe_wait_on_semaphore(MPSemaphoreID pSemaphoreID, Duration lDuration);
|
||||||
|
OSStatus safe_enter_critical_region(MPCriticalRegionID pCriticalRegionID, Duration lDuration, MPCriticalRegionID pCriticalRegionCriticalRegionID = kInvalidID);
|
||||||
|
OSStatus safe_wait_on_queue(MPQueueID pQueueID, void **pParam1, void **pParam2, void **pParam3, Duration lDuration);
|
||||||
|
OSStatus safe_delay_until(AbsoluteTime *pWakeUpTime);
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
} // namespace mac
|
||||||
|
|
||||||
|
} // namespace threads
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
#endif // BOOST_SAFE_MJM012402_HPP
|
||||||
53
src/mac/scoped_critical_region.cpp
Normal file
53
src/mac/scoped_critical_region.cpp
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// Mac Murrett
|
||||||
|
//
|
||||||
|
// 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. Mac Murrett makes no representations
|
||||||
|
// about the suitability of this software for any purpose. It is
|
||||||
|
// provided "as is" without express or implied warranty.
|
||||||
|
//
|
||||||
|
// See http://www.boost.org for most recent version including documentation.
|
||||||
|
|
||||||
|
#include "scoped_critical_region.hpp"
|
||||||
|
|
||||||
|
#include "init.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
namespace threads {
|
||||||
|
|
||||||
|
namespace mac {
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
|
||||||
|
scoped_critical_region::scoped_critical_region():
|
||||||
|
m_pCriticalRegionID(kInvalidID)
|
||||||
|
{
|
||||||
|
static bool bIgnored = thread_init();
|
||||||
|
OSStatus lStatus = MPCreateCriticalRegion(&m_pCriticalRegionID);
|
||||||
|
if(lStatus != noErr || m_pCriticalRegionID == kInvalidID)
|
||||||
|
throw(thread_resource_error());
|
||||||
|
}
|
||||||
|
|
||||||
|
scoped_critical_region::~scoped_critical_region()
|
||||||
|
{
|
||||||
|
OSStatus lStatus = MPDeleteCriticalRegion(m_pCriticalRegionID);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
} // namespace mac
|
||||||
|
|
||||||
|
} // namespace threads
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
69
src/mac/scoped_critical_region.hpp
Normal file
69
src/mac/scoped_critical_region.hpp
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// Mac Murrett
|
||||||
|
//
|
||||||
|
// 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. Mac Murrett makes no representations
|
||||||
|
// about the suitability of this software for any purpose. It is
|
||||||
|
// provided "as is" without express or implied warranty.
|
||||||
|
//
|
||||||
|
// See http://www.boost.org for most recent version including documentation.
|
||||||
|
|
||||||
|
#ifndef BOOST_SCOPED_CRITICAL_REGION_MJM012402_HPP
|
||||||
|
#define BOOST_SCOPED_CRITICAL_REGION_MJM012402_HPP
|
||||||
|
|
||||||
|
|
||||||
|
#include <boost/thread/exceptions.hpp>
|
||||||
|
|
||||||
|
#include <Multiprocessing.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
namespace threads {
|
||||||
|
|
||||||
|
namespace mac {
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
|
||||||
|
// class scoped_critical_region probably needs a new name. Although the current name
|
||||||
|
// is accurate, it can be read to mean that a critical region is entered for the
|
||||||
|
// current scope. In reality, a critical region is _created_ for the current scope.
|
||||||
|
// This class is intended as a replacement for MPCriticalRegionID that will
|
||||||
|
// automatically create and dispose of itself.
|
||||||
|
|
||||||
|
class scoped_critical_region
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
scoped_critical_region();
|
||||||
|
~scoped_critical_region();
|
||||||
|
|
||||||
|
public:
|
||||||
|
operator const MPCriticalRegionID &() const;
|
||||||
|
const MPCriticalRegionID &get() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
MPCriticalRegionID m_pCriticalRegionID;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// these are inlined for speed.
|
||||||
|
inline scoped_critical_region::operator const MPCriticalRegionID &() const
|
||||||
|
{ return(m_pCriticalRegionID); }
|
||||||
|
inline const MPCriticalRegionID &scoped_critical_region::get() const
|
||||||
|
{ return(m_pCriticalRegionID); }
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
} // namespace mac
|
||||||
|
|
||||||
|
} // namespace threads
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BOOST_SCOPED_CRITICAL_REGION_MJM012402_HPP
|
||||||
91
src/mac/st_scheduler.cpp
Normal file
91
src/mac/st_scheduler.cpp
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// Mac Murrett
|
||||||
|
//
|
||||||
|
// 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. Mac Murrett makes no representations
|
||||||
|
// about the suitability of this software for any purpose. It is
|
||||||
|
// provided "as is" without express or implied warranty.
|
||||||
|
//
|
||||||
|
// See http://www.boost.org for most recent version including documentation.
|
||||||
|
|
||||||
|
#include "st_scheduler.hpp"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
namespace threads {
|
||||||
|
|
||||||
|
namespace mac {
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
|
||||||
|
#if TARGET_CARBON
|
||||||
|
|
||||||
|
st_scheduler::st_scheduler():
|
||||||
|
m_uppTask(NULL),
|
||||||
|
m_pTimer(NULL)
|
||||||
|
{
|
||||||
|
m_uppTask = NewEventLoopTimerUPP(task_entry);
|
||||||
|
// TODO - throw on error
|
||||||
|
assert(m_uppTask != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
st_scheduler::~st_scheduler()
|
||||||
|
{
|
||||||
|
DisposeEventLoopTimerUPP(m_uppTask);
|
||||||
|
m_uppTask = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void st_scheduler::start_polling()
|
||||||
|
{
|
||||||
|
assert(m_pTimer == NULL);
|
||||||
|
OSStatus lStatus = InstallEventLoopTimer(GetMainEventLoop(),
|
||||||
|
0 * kEventDurationSecond,
|
||||||
|
kEventDurationMillisecond,
|
||||||
|
m_uppTask,
|
||||||
|
this,
|
||||||
|
&m_pTimer);
|
||||||
|
// TODO - throw on error
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void st_scheduler::stop_polling()
|
||||||
|
{
|
||||||
|
assert(m_pTimer != NULL);
|
||||||
|
OSStatus lStatus = RemoveEventLoopTimer(m_pTimer);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
m_pTimer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*static*/ pascal void st_scheduler::task_entry(EventLoopTimerRef /*pTimer*/, void *pRefCon)
|
||||||
|
{
|
||||||
|
st_scheduler *pThis = reinterpret_cast<st_scheduler *>(pRefCon);
|
||||||
|
assert(pThis != NULL);
|
||||||
|
pThis->task();
|
||||||
|
}
|
||||||
|
|
||||||
|
void st_scheduler::task()
|
||||||
|
{
|
||||||
|
periodic_function();
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
# error st_scheduler unimplemented!
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
} // namespace mac
|
||||||
|
|
||||||
|
} // namespace threads
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
73
src/mac/st_scheduler.hpp
Normal file
73
src/mac/st_scheduler.hpp
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// Mac Murrett
|
||||||
|
//
|
||||||
|
// 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. Mac Murrett makes no representations
|
||||||
|
// about the suitability of this software for any purpose. It is
|
||||||
|
// provided "as is" without express or implied warranty.
|
||||||
|
//
|
||||||
|
// See http://www.boost.org for most recent version including documentation.
|
||||||
|
|
||||||
|
#ifndef BOOST_ST_SCHEDULER_MJM012402_HPP
|
||||||
|
#define BOOST_ST_SCHEDULER_MJM012402_HPP
|
||||||
|
|
||||||
|
|
||||||
|
#include <CarbonEvents.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
namespace threads {
|
||||||
|
|
||||||
|
namespace mac {
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
|
||||||
|
// class st_scheduler calls its pure-virtual periodic_function method periodically at
|
||||||
|
// system task time. This is generally 40Hz under Mac OS 9.
|
||||||
|
|
||||||
|
class st_scheduler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
st_scheduler();
|
||||||
|
virtual ~st_scheduler();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void start_polling();
|
||||||
|
void stop_polling();
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual void periodic_function() = 0;
|
||||||
|
|
||||||
|
#if TARGET_CARBON
|
||||||
|
// use event loop timers under Carbon
|
||||||
|
private:
|
||||||
|
static pascal void task_entry(EventLoopTimerRef pTimer, void *pRefCon);
|
||||||
|
void task();
|
||||||
|
|
||||||
|
private:
|
||||||
|
EventLoopTimerUPP m_uppTask;
|
||||||
|
EventLoopTimerRef m_pTimer;
|
||||||
|
#else
|
||||||
|
// this can be implemented using OT system tasks. This would be mostly a copy-and-
|
||||||
|
// paste of the dt_scheduler code, replacing DeferredTask with SystemTask and DT
|
||||||
|
// with ST.
|
||||||
|
# error st_scheduler unimplemented!
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
} // namespace mac
|
||||||
|
|
||||||
|
} // namespace threads
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BOOST_ST_SCHEDULER_MJM012402_HPP
|
||||||
62
src/mac/thread_cleanup.cpp
Normal file
62
src/mac/thread_cleanup.cpp
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// Mac Murrett
|
||||||
|
//
|
||||||
|
// 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. Mac Murrett makes no representations
|
||||||
|
// about the suitability of this software for any purpose. It is
|
||||||
|
// provided "as is" without express or implied warranty.
|
||||||
|
//
|
||||||
|
// See http://www.boost.org for most recent version including documentation.
|
||||||
|
|
||||||
|
#include "thread_cleanup.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
namespace threads {
|
||||||
|
|
||||||
|
namespace mac {
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
TaskStorageIndex g_ulIndex(0UL);
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
|
|
||||||
|
void do_thread_startup()
|
||||||
|
{
|
||||||
|
if(g_ulIndex == 0UL)
|
||||||
|
{
|
||||||
|
OSStatus lStatus = MPAllocateTaskStorageIndex(&g_ulIndex);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
}
|
||||||
|
set_thread_cleanup_task(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_thread_cleanup()
|
||||||
|
{
|
||||||
|
void (*pfnTask)() = MPGetTaskValue(g_ulIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void set_thread_cleanup_task(void (*pfnTask)())
|
||||||
|
{
|
||||||
|
lStatus = MPSetTaskValue(g_ulIndex, reinterpret_cast<TaskStorageValue>(pfnTask));
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
} // namespace mac
|
||||||
|
|
||||||
|
} // namespace threads
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
42
src/mac/thread_cleanup.hpp
Normal file
42
src/mac/thread_cleanup.hpp
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// Mac Murrett
|
||||||
|
//
|
||||||
|
// 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. Mac Murrett makes no representations
|
||||||
|
// about the suitability of this software for any purpose. It is
|
||||||
|
// provided "as is" without express or implied warranty.
|
||||||
|
//
|
||||||
|
// See http://www.boost.org for most recent version including documentation.
|
||||||
|
|
||||||
|
#ifndef BOOST_THREAD_CLEANUP_MJM012402_HPP
|
||||||
|
#define BOOST_THREAD_CLEANUP_MJM012402_HPP
|
||||||
|
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
namespace threads {
|
||||||
|
|
||||||
|
namespace mac {
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
|
||||||
|
void do_thread_startup();
|
||||||
|
void do_thread_cleanup();
|
||||||
|
|
||||||
|
void set_thread_cleanup_task();
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
} // namespace mac
|
||||||
|
|
||||||
|
} // namespace threads
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BOOST_THREAD_CLEANUP_MJM012402_HPP
|
||||||
535
src/mutex.cpp
Normal file
535
src/mutex.cpp
Normal file
@@ -0,0 +1,535 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// William E. Kempf
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
|
// and its documentation for any purpose is hereby granted without fee,
|
||||||
|
// provided that the above copyright notice appear in all copies and
|
||||||
|
// that both that copyright notice and this permission notice appear
|
||||||
|
// in supporting documentation. 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/xtime.hpp>
|
||||||
|
#include <boost/thread/thread.hpp>
|
||||||
|
#include <boost/thread/exceptions.hpp>
|
||||||
|
#include <boost/limits.hpp>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <cassert>
|
||||||
|
#include <new>
|
||||||
|
#include "timeconv.inl"
|
||||||
|
|
||||||
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
# include <windows.h>
|
||||||
|
# include <time.h>
|
||||||
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
|
# include <errno.h>
|
||||||
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
|
# include <MacErrors.h>
|
||||||
|
|
||||||
|
# include "mac/init.hpp"
|
||||||
|
# include "mac/safe.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
mutex::mutex()
|
||||||
|
{
|
||||||
|
m_mutex = reinterpret_cast<void*>(new(std::nothrow) CRITICAL_SECTION);
|
||||||
|
if (!m_mutex)
|
||||||
|
throw thread_resource_error();
|
||||||
|
InitializeCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(m_mutex));
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex::~mutex()
|
||||||
|
{
|
||||||
|
DeleteCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(m_mutex));
|
||||||
|
delete reinterpret_cast<LPCRITICAL_SECTION>(m_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mutex::do_lock()
|
||||||
|
{
|
||||||
|
EnterCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(m_mutex));
|
||||||
|
}
|
||||||
|
|
||||||
|
void mutex::do_unlock()
|
||||||
|
{
|
||||||
|
LeaveCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(m_mutex));
|
||||||
|
}
|
||||||
|
|
||||||
|
void mutex::do_lock(cv_state&)
|
||||||
|
{
|
||||||
|
do_lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void mutex::do_unlock(cv_state&)
|
||||||
|
{
|
||||||
|
do_unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
try_mutex::try_mutex()
|
||||||
|
{
|
||||||
|
m_mutex = reinterpret_cast<void*>(CreateMutex(0, 0, 0));
|
||||||
|
if (!m_mutex)
|
||||||
|
throw thread_resource_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
try_mutex::~try_mutex()
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = CloseHandle(reinterpret_cast<HANDLE>(m_mutex));
|
||||||
|
assert(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
void try_mutex::do_lock()
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), INFINITE);
|
||||||
|
assert(res == WAIT_OBJECT_0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool try_mutex::do_trylock()
|
||||||
|
{
|
||||||
|
unsigned int res = 0;
|
||||||
|
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), 0);
|
||||||
|
assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
|
||||||
|
return res == WAIT_OBJECT_0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void try_mutex::do_unlock()
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||||
|
assert(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
void try_mutex::do_lock(cv_state&)
|
||||||
|
{
|
||||||
|
do_lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void try_mutex::do_unlock(cv_state&)
|
||||||
|
{
|
||||||
|
do_unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
timed_mutex::timed_mutex()
|
||||||
|
{
|
||||||
|
m_mutex = reinterpret_cast<void*>(CreateMutex(0, 0, 0));
|
||||||
|
if (!m_mutex)
|
||||||
|
throw thread_resource_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
timed_mutex::~timed_mutex()
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = CloseHandle(reinterpret_cast<HANDLE>(m_mutex));
|
||||||
|
assert(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
void timed_mutex::do_lock()
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), INFINITE);
|
||||||
|
assert(res == WAIT_OBJECT_0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool timed_mutex::do_trylock()
|
||||||
|
{
|
||||||
|
unsigned int res = 0;
|
||||||
|
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), 0);
|
||||||
|
assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
|
||||||
|
return res == WAIT_OBJECT_0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool timed_mutex::do_timedlock(const xtime& xt)
|
||||||
|
{
|
||||||
|
int milliseconds;
|
||||||
|
to_duration(xt, milliseconds);
|
||||||
|
|
||||||
|
unsigned int res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), milliseconds);
|
||||||
|
assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
|
||||||
|
return res == WAIT_OBJECT_0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void timed_mutex::do_unlock()
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||||
|
assert(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
void timed_mutex::do_lock(cv_state&)
|
||||||
|
{
|
||||||
|
do_lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void timed_mutex::do_unlock(cv_state&)
|
||||||
|
{
|
||||||
|
do_unlock();
|
||||||
|
}
|
||||||
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
|
mutex::mutex()
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = pthread_mutex_init(&m_mutex, 0);
|
||||||
|
if (res != 0)
|
||||||
|
throw thread_resource_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex::~mutex()
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = pthread_mutex_destroy(&m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mutex::do_lock()
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = pthread_mutex_lock(&m_mutex);
|
||||||
|
if (res == EDEADLK) throw lock_error();
|
||||||
|
assert(res == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mutex::do_unlock()
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = pthread_mutex_unlock(&m_mutex);
|
||||||
|
if (res == EPERM) throw lock_error();
|
||||||
|
assert(res == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mutex::do_lock(cv_state&)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void mutex::do_unlock(cv_state& state)
|
||||||
|
{
|
||||||
|
state.pmutex = &m_mutex;
|
||||||
|
}
|
||||||
|
|
||||||
|
try_mutex::try_mutex()
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = pthread_mutex_init(&m_mutex, 0);
|
||||||
|
if (res != 0)
|
||||||
|
throw thread_resource_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
try_mutex::~try_mutex()
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = pthread_mutex_destroy(&m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void try_mutex::do_lock()
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = pthread_mutex_lock(&m_mutex);
|
||||||
|
if (res == EDEADLK) throw lock_error();
|
||||||
|
assert(res == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool try_mutex::do_trylock()
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = pthread_mutex_trylock(&m_mutex);
|
||||||
|
if (res == EDEADLK) throw lock_error();
|
||||||
|
assert(res == 0 || res == EBUSY);
|
||||||
|
return res == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void try_mutex::do_unlock()
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = pthread_mutex_unlock(&m_mutex);
|
||||||
|
if (res == EPERM) throw lock_error();
|
||||||
|
assert(res == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void try_mutex::do_lock(cv_state&)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void try_mutex::do_unlock(cv_state& state)
|
||||||
|
{
|
||||||
|
state.pmutex = &m_mutex;
|
||||||
|
}
|
||||||
|
|
||||||
|
timed_mutex::timed_mutex()
|
||||||
|
: m_locked(false)
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = pthread_mutex_init(&m_mutex, 0);
|
||||||
|
if (res != 0)
|
||||||
|
throw thread_resource_error();
|
||||||
|
|
||||||
|
res = pthread_cond_init(&m_condition, 0);
|
||||||
|
if (res != 0)
|
||||||
|
{
|
||||||
|
pthread_mutex_destroy(&m_mutex);
|
||||||
|
throw thread_resource_error();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
timed_mutex::~timed_mutex()
|
||||||
|
{
|
||||||
|
assert(!m_locked);
|
||||||
|
int res = 0;
|
||||||
|
res = pthread_mutex_destroy(&m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
|
||||||
|
res = pthread_cond_destroy(&m_condition);
|
||||||
|
assert(res == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void timed_mutex::do_lock()
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = pthread_mutex_lock(&m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
|
||||||
|
while (m_locked)
|
||||||
|
{
|
||||||
|
res = pthread_cond_wait(&m_condition, &m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(!m_locked);
|
||||||
|
m_locked = true;
|
||||||
|
|
||||||
|
res = pthread_mutex_unlock(&m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool timed_mutex::do_trylock()
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = pthread_mutex_lock(&m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
|
||||||
|
bool ret = false;
|
||||||
|
if (!m_locked)
|
||||||
|
{
|
||||||
|
m_locked = true;
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = pthread_mutex_unlock(&m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool timed_mutex::do_timedlock(const xtime& xt)
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = pthread_mutex_lock(&m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
|
||||||
|
timespec ts;
|
||||||
|
to_timespec(xt, ts);
|
||||||
|
|
||||||
|
while (m_locked)
|
||||||
|
{
|
||||||
|
res = pthread_cond_timedwait(&m_condition, &m_mutex, &ts);
|
||||||
|
assert(res == 0 || res == ETIMEDOUT);
|
||||||
|
|
||||||
|
if (res == ETIMEDOUT)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ret = false;
|
||||||
|
if (!m_locked)
|
||||||
|
{
|
||||||
|
m_locked = true;
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = pthread_mutex_unlock(&m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void timed_mutex::do_unlock()
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = pthread_mutex_lock(&m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
|
||||||
|
assert(m_locked);
|
||||||
|
m_locked = false;
|
||||||
|
|
||||||
|
res = pthread_cond_signal(&m_condition);
|
||||||
|
assert(res == 0);
|
||||||
|
|
||||||
|
res = pthread_mutex_unlock(&m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void timed_mutex::do_lock(cv_state&)
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
while (m_locked)
|
||||||
|
{
|
||||||
|
res = pthread_cond_wait(&m_condition, &m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(!m_locked);
|
||||||
|
m_locked = true;
|
||||||
|
|
||||||
|
res = pthread_mutex_unlock(&m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void timed_mutex::do_unlock(cv_state& state)
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = pthread_mutex_lock(&m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
|
||||||
|
assert(m_locked);
|
||||||
|
m_locked = false;
|
||||||
|
|
||||||
|
res = pthread_cond_signal(&m_condition);
|
||||||
|
assert(res == 0);
|
||||||
|
|
||||||
|
state.pmutex = &m_mutex;
|
||||||
|
}
|
||||||
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
|
|
||||||
|
using threads::mac::detail::safe_enter_critical_region;
|
||||||
|
|
||||||
|
mutex::mutex()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex::~mutex()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void mutex::do_lock()
|
||||||
|
{
|
||||||
|
OSStatus lStatus = noErr;
|
||||||
|
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mutex::do_unlock()
|
||||||
|
{
|
||||||
|
OSStatus lStatus = noErr;
|
||||||
|
lStatus = MPExitCriticalRegion(m_mutex);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mutex::do_lock(cv_state& /*state*/)
|
||||||
|
{
|
||||||
|
do_lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void mutex::do_unlock(cv_state& /*state*/)
|
||||||
|
{
|
||||||
|
do_unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
try_mutex::try_mutex()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
try_mutex::~try_mutex()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void try_mutex::do_lock()
|
||||||
|
{
|
||||||
|
OSStatus lStatus = noErr;
|
||||||
|
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool try_mutex::do_trylock()
|
||||||
|
{
|
||||||
|
OSStatus lStatus = noErr;
|
||||||
|
lStatus = MPEnterCriticalRegion(m_mutex, kDurationImmediate);
|
||||||
|
assert(lStatus == noErr || lStatus == kMPTimeoutErr);
|
||||||
|
return lStatus == noErr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void try_mutex::do_unlock()
|
||||||
|
{
|
||||||
|
OSStatus lStatus = noErr;
|
||||||
|
lStatus = MPExitCriticalRegion(m_mutex);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void try_mutex::do_lock(cv_state& /*state*/)
|
||||||
|
{
|
||||||
|
do_lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void try_mutex::do_unlock(cv_state& /*state*/)
|
||||||
|
{
|
||||||
|
do_unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
timed_mutex::timed_mutex()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
timed_mutex::~timed_mutex()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void timed_mutex::do_lock()
|
||||||
|
{
|
||||||
|
OSStatus lStatus = noErr;
|
||||||
|
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool timed_mutex::do_trylock()
|
||||||
|
{
|
||||||
|
OSStatus lStatus = noErr;
|
||||||
|
lStatus = MPEnterCriticalRegion(m_mutex, kDurationImmediate);
|
||||||
|
assert(lStatus == noErr || lStatus == kMPTimeoutErr);
|
||||||
|
return(lStatus == noErr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool timed_mutex::do_timedlock(const xtime& xt)
|
||||||
|
{
|
||||||
|
int microseconds;
|
||||||
|
to_microduration(xt, microseconds);
|
||||||
|
Duration lDuration = kDurationMicrosecond * microseconds;
|
||||||
|
|
||||||
|
OSStatus lStatus = noErr;
|
||||||
|
lStatus = safe_enter_critical_region(m_mutex, lDuration, m_mutex_mutex);
|
||||||
|
assert(lStatus == noErr || lStatus == kMPTimeoutErr);
|
||||||
|
|
||||||
|
return(lStatus == noErr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void timed_mutex::do_unlock()
|
||||||
|
{
|
||||||
|
OSStatus lStatus = noErr;
|
||||||
|
lStatus = MPExitCriticalRegion(m_mutex);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void timed_mutex::do_lock(cv_state& /*state*/)
|
||||||
|
{
|
||||||
|
do_lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void timed_mutex::do_unlock(cv_state& /*state*/)
|
||||||
|
{
|
||||||
|
do_unlock();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
// Change Log:
|
||||||
|
// 8 Feb 01 WEKEMPF Initial version.
|
||||||
139
src/once.cpp
Normal file
139
src/once.cpp
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// William E. Kempf
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
|
// and its documentation for any purpose is hereby granted without fee,
|
||||||
|
// provided that the above copyright notice appear in all copies and
|
||||||
|
// that both that copyright notice and this permission notice appear
|
||||||
|
// in supporting documentation. 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 <cstdio>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
# include <windows.h>
|
||||||
|
# if defined(BOOST_NO_STRINGSTREAM)
|
||||||
|
# include <strstream>
|
||||||
|
class unfreezer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
unfreezer(std::ostrstream& s) : m_stream(s) {}
|
||||||
|
~unfreezer() { m_stream.freeze(false); }
|
||||||
|
private:
|
||||||
|
std::ostrstream& m_stream;
|
||||||
|
};
|
||||||
|
# else
|
||||||
|
# include <sstream>
|
||||||
|
# endif
|
||||||
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
|
# include <Multiprocessing.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef BOOST_NO_STDC_NAMESPACE
|
||||||
|
namespace std { using ::sprintf; }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(BOOST_HAS_PTHREADS)
|
||||||
|
namespace {
|
||||||
|
pthread_key_t key;
|
||||||
|
pthread_once_t once = PTHREAD_ONCE_INIT;
|
||||||
|
|
||||||
|
typedef void (*once_callback)();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
static void key_init()
|
||||||
|
{
|
||||||
|
pthread_key_create(&key, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void do_once()
|
||||||
|
{
|
||||||
|
once_callback* cb = reinterpret_cast<once_callback*>(pthread_getspecific(key));
|
||||||
|
(**cb)();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
|
void *remote_call_proxy(void *pData)
|
||||||
|
{
|
||||||
|
std::pair<void (*)(), boost::once_flag *> &rData(*reinterpret_cast<std::pair<void (*)(), boost::once_flag *> *>(pData));
|
||||||
|
|
||||||
|
if(*rData.second == false)
|
||||||
|
{
|
||||||
|
rData.first();
|
||||||
|
*rData.second = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return(NULL);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
void call_once(void (*func)(), once_flag& flag)
|
||||||
|
{
|
||||||
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
once_flag tmp = flag;
|
||||||
|
|
||||||
|
// Memory barrier would be needed here to prevent race conditions on some platforms with
|
||||||
|
// partial ordering.
|
||||||
|
|
||||||
|
if (!tmp)
|
||||||
|
{
|
||||||
|
#if defined(BOOST_NO_STRINGSTREAM)
|
||||||
|
std::ostrstream strm;
|
||||||
|
strm << "2AC1A572DB6944B0A65C38C4140AF2F4" << std::hex << GetCurrentProcessId() << &flag << std::ends;
|
||||||
|
unfreezer unfreeze(strm);
|
||||||
|
HANDLE mutex = CreateMutex(NULL, FALSE, strm.str());
|
||||||
|
#else
|
||||||
|
std::ostringstream strm;
|
||||||
|
strm << "2AC1A572DB6944B0A65C38C4140AF2F4" << std::hex << GetCurrentProcessId() << &flag;
|
||||||
|
HANDLE mutex = CreateMutex(NULL, FALSE, strm.str().c_str());
|
||||||
|
#endif
|
||||||
|
assert(mutex != NULL);
|
||||||
|
|
||||||
|
int res = 0;
|
||||||
|
res = WaitForSingleObject(mutex, INFINITE);
|
||||||
|
assert(res == WAIT_OBJECT_0);
|
||||||
|
|
||||||
|
tmp = flag;
|
||||||
|
if (!tmp)
|
||||||
|
{
|
||||||
|
func();
|
||||||
|
tmp = true;
|
||||||
|
|
||||||
|
// Memory barrier would be needed here to prevent race conditions on some platforms
|
||||||
|
// with partial ordering.
|
||||||
|
|
||||||
|
flag = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = ReleaseMutex(mutex);
|
||||||
|
assert(res);
|
||||||
|
res = CloseHandle(mutex);
|
||||||
|
assert(res);
|
||||||
|
}
|
||||||
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
|
pthread_once(&once, &key_init);
|
||||||
|
pthread_setspecific(key, &func);
|
||||||
|
pthread_once(&flag, do_once);
|
||||||
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
|
if(flag == false)
|
||||||
|
{
|
||||||
|
// all we do here is make a remote call to blue, as blue is not reentrant.
|
||||||
|
std::pair<void (*)(), once_flag *> sData(func, &flag);
|
||||||
|
MPRemoteCall(remote_call_proxy, &sData, kMPOwningProcessRemoteContext);
|
||||||
|
assert(flag == true);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change Log:
|
||||||
|
// 1 Aug 01 WEKEMPF Initial version.
|
||||||
992
src/recursive_mutex.cpp
Normal file
992
src/recursive_mutex.cpp
Normal file
@@ -0,0 +1,992 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// William E. Kempf
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
|
// and its documentation for any purpose is hereby granted without fee,
|
||||||
|
// provided that the above copyright notice appear in all copies and
|
||||||
|
// that both that copyright notice and this permission notice appear
|
||||||
|
// in supporting documentation. 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/xtime.hpp>
|
||||||
|
#include <boost/thread/thread.hpp>
|
||||||
|
#include <boost/limits.hpp>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <cassert>
|
||||||
|
#include "timeconv.inl"
|
||||||
|
|
||||||
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
# include <windows.h>
|
||||||
|
# include <time.h>
|
||||||
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
|
# include <errno.h>
|
||||||
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
|
# include <MacErrors.h>
|
||||||
|
# include "safe.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
recursive_mutex::recursive_mutex()
|
||||||
|
: m_count(0)
|
||||||
|
{
|
||||||
|
m_mutex = reinterpret_cast<void*>(new(std::nothrow) CRITICAL_SECTION);
|
||||||
|
if (!m_mutex)
|
||||||
|
throw thread_resource_error();
|
||||||
|
InitializeCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(m_mutex));
|
||||||
|
}
|
||||||
|
|
||||||
|
recursive_mutex::~recursive_mutex()
|
||||||
|
{
|
||||||
|
DeleteCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(m_mutex));
|
||||||
|
delete reinterpret_cast<LPCRITICAL_SECTION>(m_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void recursive_mutex::do_lock()
|
||||||
|
{
|
||||||
|
EnterCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(m_mutex));
|
||||||
|
|
||||||
|
if (++m_count > 1)
|
||||||
|
LeaveCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(m_mutex));
|
||||||
|
}
|
||||||
|
|
||||||
|
void recursive_mutex::do_unlock()
|
||||||
|
{
|
||||||
|
if (--m_count == 0)
|
||||||
|
LeaveCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(m_mutex));
|
||||||
|
}
|
||||||
|
|
||||||
|
void recursive_mutex::do_lock(cv_state& state)
|
||||||
|
{
|
||||||
|
EnterCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(m_mutex));
|
||||||
|
m_count = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void recursive_mutex::do_unlock(cv_state& state)
|
||||||
|
{
|
||||||
|
state = m_count;
|
||||||
|
m_count = 0;
|
||||||
|
LeaveCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(m_mutex));
|
||||||
|
}
|
||||||
|
|
||||||
|
recursive_try_mutex::recursive_try_mutex()
|
||||||
|
: m_count(0)
|
||||||
|
{
|
||||||
|
m_mutex = reinterpret_cast<void*>(CreateMutex(0, 0, 0));
|
||||||
|
if (!m_mutex)
|
||||||
|
throw thread_resource_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
recursive_try_mutex::~recursive_try_mutex()
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = CloseHandle(reinterpret_cast<HANDLE>(m_mutex));
|
||||||
|
assert(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
void recursive_try_mutex::do_lock()
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), INFINITE);
|
||||||
|
assert(res == WAIT_OBJECT_0);
|
||||||
|
|
||||||
|
if (++m_count > 1)
|
||||||
|
{
|
||||||
|
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||||
|
assert(res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool recursive_try_mutex::do_trylock()
|
||||||
|
{
|
||||||
|
unsigned int res = 0;
|
||||||
|
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), 0);
|
||||||
|
assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
|
||||||
|
|
||||||
|
if (res == WAIT_OBJECT_0)
|
||||||
|
{
|
||||||
|
if (++m_count > 1)
|
||||||
|
{
|
||||||
|
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||||
|
assert(res);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void recursive_try_mutex::do_unlock()
|
||||||
|
{
|
||||||
|
if (--m_count == 0)
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||||
|
assert(res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void recursive_try_mutex::do_lock(cv_state& state)
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), INFINITE);
|
||||||
|
assert(res == WAIT_OBJECT_0);
|
||||||
|
|
||||||
|
m_count = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void recursive_try_mutex::do_unlock(cv_state& state)
|
||||||
|
{
|
||||||
|
state = m_count;
|
||||||
|
m_count = 0;
|
||||||
|
|
||||||
|
int res = 0;
|
||||||
|
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||||
|
assert(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
recursive_timed_mutex::recursive_timed_mutex()
|
||||||
|
: m_count(0)
|
||||||
|
{
|
||||||
|
m_mutex = reinterpret_cast<void*>(CreateMutex(0, 0, 0));
|
||||||
|
if (!m_mutex)
|
||||||
|
throw thread_resource_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
recursive_timed_mutex::~recursive_timed_mutex()
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = CloseHandle(reinterpret_cast<HANDLE>(m_mutex));
|
||||||
|
assert(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
void recursive_timed_mutex::do_lock()
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), INFINITE);
|
||||||
|
assert(res == WAIT_OBJECT_0);
|
||||||
|
|
||||||
|
if (++m_count > 1)
|
||||||
|
{
|
||||||
|
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||||
|
assert(res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool recursive_timed_mutex::do_trylock()
|
||||||
|
{
|
||||||
|
unsigned int res = 0;
|
||||||
|
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), 0);
|
||||||
|
assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
|
||||||
|
|
||||||
|
if (res == WAIT_OBJECT_0)
|
||||||
|
{
|
||||||
|
if (++m_count > 1)
|
||||||
|
{
|
||||||
|
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||||
|
assert(res);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool recursive_timed_mutex::do_timedlock(const xtime& xt)
|
||||||
|
{
|
||||||
|
int milliseconds;
|
||||||
|
to_duration(xt, milliseconds);
|
||||||
|
|
||||||
|
unsigned int res = 0;
|
||||||
|
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), milliseconds);
|
||||||
|
assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
|
||||||
|
|
||||||
|
if (res == WAIT_OBJECT_0)
|
||||||
|
{
|
||||||
|
if (++m_count > 1)
|
||||||
|
{
|
||||||
|
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||||
|
assert(res);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void recursive_timed_mutex::do_unlock()
|
||||||
|
{
|
||||||
|
if (--m_count == 0)
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||||
|
assert(res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void recursive_timed_mutex::do_lock(cv_state& state)
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), INFINITE);
|
||||||
|
assert(res == WAIT_OBJECT_0);
|
||||||
|
|
||||||
|
m_count = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void recursive_timed_mutex::do_unlock(cv_state& state)
|
||||||
|
{
|
||||||
|
state = m_count;
|
||||||
|
m_count = 0;
|
||||||
|
|
||||||
|
int res = 0;
|
||||||
|
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||||
|
assert(res);
|
||||||
|
}
|
||||||
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
|
recursive_mutex::recursive_mutex()
|
||||||
|
: m_count(0)
|
||||||
|
# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
|
||||||
|
, m_valid_id(false)
|
||||||
|
# endif
|
||||||
|
{
|
||||||
|
pthread_mutexattr_t attr;
|
||||||
|
int res = 0;
|
||||||
|
res = pthread_mutexattr_init(&attr);
|
||||||
|
assert(res == 0);
|
||||||
|
|
||||||
|
# if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
|
||||||
|
res = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
|
||||||
|
assert(res == 0);
|
||||||
|
# endif
|
||||||
|
|
||||||
|
res = pthread_mutex_init(&m_mutex, &attr);
|
||||||
|
if (res != 0)
|
||||||
|
throw thread_resource_error();
|
||||||
|
|
||||||
|
# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
|
||||||
|
res = pthread_cond_init(&m_unlocked, 0);
|
||||||
|
if (res != 0)
|
||||||
|
{
|
||||||
|
pthread_mutex_destroy(&m_mutex);
|
||||||
|
throw thread_resource_error();
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
|
||||||
|
recursive_mutex::~recursive_mutex()
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = pthread_mutex_destroy(&m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
|
||||||
|
# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
|
||||||
|
res = pthread_cond_destroy(&m_unlocked);
|
||||||
|
assert(res == 0);
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void recursive_mutex::do_lock()
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = pthread_mutex_lock(&m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
|
||||||
|
# if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
|
||||||
|
if (++m_count > 1)
|
||||||
|
{
|
||||||
|
res = pthread_mutex_unlock(&m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
}
|
||||||
|
# else
|
||||||
|
pthread_t tid = pthread_self();
|
||||||
|
if (m_valid_id && pthread_equal(m_thread_id, tid))
|
||||||
|
++m_count;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while (m_valid_id)
|
||||||
|
{
|
||||||
|
res = pthread_cond_wait(&m_unlocked, &m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_thread_id = tid;
|
||||||
|
m_valid_id = true;
|
||||||
|
m_count = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = pthread_mutex_unlock(&m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void recursive_mutex::do_unlock()
|
||||||
|
{
|
||||||
|
# if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
|
||||||
|
if (--m_count == 0)
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = pthread_mutex_unlock(&m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
}
|
||||||
|
# else
|
||||||
|
int res = 0;
|
||||||
|
res = pthread_mutex_lock(&m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
|
||||||
|
pthread_t tid = pthread_self();
|
||||||
|
if (m_valid_id && !pthread_equal(m_thread_id, tid))
|
||||||
|
{
|
||||||
|
res = pthread_mutex_unlock(&m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
throw lock_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (--m_count == 0)
|
||||||
|
{
|
||||||
|
assert(m_valid_id);
|
||||||
|
m_valid_id = false;
|
||||||
|
|
||||||
|
res = pthread_cond_signal(&m_unlocked);
|
||||||
|
assert(res == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
res = pthread_mutex_unlock(&m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void recursive_mutex::do_lock(cv_state& state)
|
||||||
|
{
|
||||||
|
# if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
|
||||||
|
m_count = state.count;
|
||||||
|
# else
|
||||||
|
int res = 0;
|
||||||
|
|
||||||
|
while (m_valid_id)
|
||||||
|
{
|
||||||
|
res = pthread_cond_wait(&m_unlocked, &m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_thread_id = pthread_self();
|
||||||
|
m_valid_id = true;
|
||||||
|
m_count = state.count;
|
||||||
|
|
||||||
|
res = pthread_mutex_unlock(&m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void recursive_mutex::do_unlock(cv_state& state)
|
||||||
|
{
|
||||||
|
# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
|
||||||
|
int res = 0;
|
||||||
|
res = pthread_mutex_lock(&m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
|
||||||
|
assert(m_valid_id);
|
||||||
|
m_valid_id = false;
|
||||||
|
|
||||||
|
res = pthread_cond_signal(&m_unlocked);
|
||||||
|
assert(res == 0);
|
||||||
|
# endif
|
||||||
|
|
||||||
|
state.pmutex = &m_mutex;
|
||||||
|
state.count = m_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
recursive_try_mutex::recursive_try_mutex()
|
||||||
|
: m_count(0)
|
||||||
|
# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
|
||||||
|
, m_valid_id(false)
|
||||||
|
# endif
|
||||||
|
{
|
||||||
|
pthread_mutexattr_t attr;
|
||||||
|
int res = 0;
|
||||||
|
res = pthread_mutexattr_init(&attr);
|
||||||
|
assert(res == 0);
|
||||||
|
|
||||||
|
# if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
|
||||||
|
res = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
|
||||||
|
assert(res == 0);
|
||||||
|
# endif
|
||||||
|
|
||||||
|
res = pthread_mutex_init(&m_mutex, &attr);
|
||||||
|
if (res != 0)
|
||||||
|
throw thread_resource_error();
|
||||||
|
|
||||||
|
# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
|
||||||
|
res = pthread_cond_init(&m_unlocked, 0);
|
||||||
|
if (res != 0)
|
||||||
|
{
|
||||||
|
pthread_mutex_destroy(&m_mutex);
|
||||||
|
throw thread_resource_error();
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
|
||||||
|
recursive_try_mutex::~recursive_try_mutex()
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = pthread_mutex_destroy(&m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
|
||||||
|
# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
|
||||||
|
res = pthread_cond_destroy(&m_unlocked);
|
||||||
|
assert(res == 0);
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void recursive_try_mutex::do_lock()
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = pthread_mutex_lock(&m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
|
||||||
|
# if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
|
||||||
|
if (++m_count > 1)
|
||||||
|
{
|
||||||
|
res = pthread_mutex_unlock(&m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
}
|
||||||
|
# else
|
||||||
|
pthread_t tid = pthread_self();
|
||||||
|
if (m_valid_id && pthread_equal(m_thread_id, tid))
|
||||||
|
++m_count;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while (m_valid_id)
|
||||||
|
{
|
||||||
|
res = pthread_cond_wait(&m_unlocked, &m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_thread_id = tid;
|
||||||
|
m_valid_id = true;
|
||||||
|
m_count = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = pthread_mutex_unlock(&m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool recursive_try_mutex::do_trylock()
|
||||||
|
{
|
||||||
|
# if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
|
||||||
|
int res = 0;
|
||||||
|
res = pthread_mutex_trylock(&m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
|
||||||
|
if (res == 0)
|
||||||
|
{
|
||||||
|
if (++m_count > 1)
|
||||||
|
{
|
||||||
|
res = pthread_mutex_unlock(&m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
# else
|
||||||
|
int res = 0;
|
||||||
|
res = pthread_mutex_lock(&m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
|
||||||
|
bool ret = false;
|
||||||
|
pthread_t tid = pthread_self();
|
||||||
|
if (m_valid_id && pthread_equal(m_thread_id, tid))
|
||||||
|
{
|
||||||
|
++m_count;
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
else if (!m_valid_id)
|
||||||
|
{
|
||||||
|
m_thread_id = tid;
|
||||||
|
m_valid_id = true;
|
||||||
|
m_count = 1;
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = pthread_mutex_unlock(&m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
return ret;
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void recursive_try_mutex::do_unlock()
|
||||||
|
{
|
||||||
|
# if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
|
||||||
|
if (--m_count == 0)
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = pthread_mutex_unlock(&m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
}
|
||||||
|
# else
|
||||||
|
int res = 0;
|
||||||
|
res = pthread_mutex_lock(&m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
|
||||||
|
pthread_t tid = pthread_self();
|
||||||
|
if (m_valid_id && !pthread_equal(m_thread_id, tid))
|
||||||
|
{
|
||||||
|
res = pthread_mutex_unlock(&m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
throw lock_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (--m_count == 0)
|
||||||
|
{
|
||||||
|
assert(m_valid_id);
|
||||||
|
m_valid_id = false;
|
||||||
|
|
||||||
|
res = pthread_cond_signal(&m_unlocked);
|
||||||
|
assert(res == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
res = pthread_mutex_unlock(&m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void recursive_try_mutex::do_lock(cv_state& state)
|
||||||
|
{
|
||||||
|
# if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
|
||||||
|
m_count = state.count;
|
||||||
|
# else
|
||||||
|
int res = 0;
|
||||||
|
|
||||||
|
while (m_valid_id)
|
||||||
|
{
|
||||||
|
res = pthread_cond_wait(&m_unlocked, &m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_thread_id = pthread_self();
|
||||||
|
m_valid_id = true;
|
||||||
|
m_count = state.count;
|
||||||
|
|
||||||
|
res = pthread_mutex_unlock(&m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void recursive_try_mutex::do_unlock(cv_state& state)
|
||||||
|
{
|
||||||
|
# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
|
||||||
|
int res = 0;
|
||||||
|
res = pthread_mutex_lock(&m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
|
||||||
|
assert(m_valid_id);
|
||||||
|
m_valid_id = false;
|
||||||
|
|
||||||
|
res = pthread_cond_signal(&m_unlocked);
|
||||||
|
assert(res == 0);
|
||||||
|
# endif
|
||||||
|
|
||||||
|
state.pmutex = &m_mutex;
|
||||||
|
state.count = m_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
recursive_timed_mutex::recursive_timed_mutex()
|
||||||
|
: m_valid_id(false), m_count(0)
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = pthread_mutex_init(&m_mutex, 0);
|
||||||
|
if (res != 0)
|
||||||
|
throw thread_resource_error();
|
||||||
|
|
||||||
|
res = pthread_cond_init(&m_unlocked, 0);
|
||||||
|
if (res != 0)
|
||||||
|
{
|
||||||
|
pthread_mutex_destroy(&m_mutex);
|
||||||
|
throw thread_resource_error();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
recursive_timed_mutex::~recursive_timed_mutex()
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = pthread_mutex_destroy(&m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
|
||||||
|
res = pthread_cond_destroy(&m_unlocked);
|
||||||
|
assert(res == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void recursive_timed_mutex::do_lock()
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = pthread_mutex_lock(&m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
|
||||||
|
pthread_t tid = pthread_self();
|
||||||
|
if (m_valid_id && pthread_equal(m_thread_id, tid))
|
||||||
|
++m_count;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while (m_valid_id)
|
||||||
|
{
|
||||||
|
res = pthread_cond_wait(&m_unlocked, &m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_thread_id = tid;
|
||||||
|
m_valid_id = true;
|
||||||
|
m_count = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = pthread_mutex_unlock(&m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool recursive_timed_mutex::do_trylock()
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = pthread_mutex_lock(&m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
|
||||||
|
bool ret = false;
|
||||||
|
pthread_t tid = pthread_self();
|
||||||
|
if (m_valid_id && pthread_equal(m_thread_id, tid))
|
||||||
|
{
|
||||||
|
++m_count;
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
else if (!m_valid_id)
|
||||||
|
{
|
||||||
|
m_thread_id = tid;
|
||||||
|
m_valid_id = true;
|
||||||
|
m_count = 1;
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = pthread_mutex_unlock(&m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool recursive_timed_mutex::do_timedlock(const xtime& xt)
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = pthread_mutex_lock(&m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
|
||||||
|
bool ret = false;
|
||||||
|
pthread_t tid = pthread_self();
|
||||||
|
if (m_valid_id && pthread_equal(m_thread_id, tid))
|
||||||
|
{
|
||||||
|
++m_count;
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
timespec ts;
|
||||||
|
to_timespec(xt, ts);
|
||||||
|
|
||||||
|
while (m_valid_id)
|
||||||
|
{
|
||||||
|
res = pthread_cond_timedwait(&m_unlocked, &m_mutex, &ts);
|
||||||
|
if (res == ETIMEDOUT)
|
||||||
|
break;
|
||||||
|
assert(res == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_valid_id)
|
||||||
|
{
|
||||||
|
m_thread_id = tid;
|
||||||
|
m_valid_id = true;
|
||||||
|
m_count = 1;
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res = pthread_mutex_unlock(&m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void recursive_timed_mutex::do_unlock()
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = pthread_mutex_lock(&m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
|
||||||
|
pthread_t tid = pthread_self();
|
||||||
|
if (m_valid_id && !pthread_equal(m_thread_id, tid))
|
||||||
|
{
|
||||||
|
res = pthread_mutex_unlock(&m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
throw lock_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (--m_count == 0)
|
||||||
|
{
|
||||||
|
assert(m_valid_id);
|
||||||
|
m_valid_id = false;
|
||||||
|
|
||||||
|
res = pthread_cond_signal(&m_unlocked);
|
||||||
|
assert(res == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
res = pthread_mutex_unlock(&m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void recursive_timed_mutex::do_lock(cv_state& state)
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
|
||||||
|
while (m_valid_id)
|
||||||
|
{
|
||||||
|
res = pthread_cond_wait(&m_unlocked, &m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_thread_id = pthread_self();
|
||||||
|
m_valid_id = true;
|
||||||
|
m_count = state.count;
|
||||||
|
|
||||||
|
res = pthread_mutex_unlock(&m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void recursive_timed_mutex::do_unlock(cv_state& state)
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = pthread_mutex_lock(&m_mutex);
|
||||||
|
assert(res == 0);
|
||||||
|
|
||||||
|
assert(m_valid_id);
|
||||||
|
m_valid_id = false;
|
||||||
|
|
||||||
|
res = pthread_cond_signal(&m_unlocked);
|
||||||
|
assert(res == 0);
|
||||||
|
|
||||||
|
state.pmutex = &m_mutex;
|
||||||
|
state.count = m_count;
|
||||||
|
}
|
||||||
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
|
|
||||||
|
using threads::mac::detail::safe_enter_critical_region;
|
||||||
|
|
||||||
|
|
||||||
|
recursive_mutex::recursive_mutex()
|
||||||
|
: m_count(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
recursive_mutex::~recursive_mutex()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void recursive_mutex::do_lock()
|
||||||
|
{
|
||||||
|
OSStatus lStatus = noErr;
|
||||||
|
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
|
||||||
|
if (++m_count > 1)
|
||||||
|
{
|
||||||
|
lStatus = MPExitCriticalRegion(m_mutex);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void recursive_mutex::do_unlock()
|
||||||
|
{
|
||||||
|
if (--m_count == 0)
|
||||||
|
{
|
||||||
|
OSStatus lStatus = noErr;
|
||||||
|
lStatus = MPExitCriticalRegion(m_mutex);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void recursive_mutex::do_lock(cv_state& state)
|
||||||
|
{
|
||||||
|
OSStatus lStatus = noErr;
|
||||||
|
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
|
||||||
|
m_count = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void recursive_mutex::do_unlock(cv_state& state)
|
||||||
|
{
|
||||||
|
state = m_count;
|
||||||
|
m_count = 0;
|
||||||
|
|
||||||
|
OSStatus lStatus = noErr;
|
||||||
|
lStatus = MPExitCriticalRegion(m_mutex);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
}
|
||||||
|
|
||||||
|
recursive_try_mutex::recursive_try_mutex()
|
||||||
|
: m_count(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
recursive_try_mutex::~recursive_try_mutex()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void recursive_try_mutex::do_lock()
|
||||||
|
{
|
||||||
|
OSStatus lStatus = noErr;
|
||||||
|
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
|
||||||
|
if (++m_count > 1)
|
||||||
|
{
|
||||||
|
lStatus = MPExitCriticalRegion(m_mutex);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool recursive_try_mutex::do_trylock()
|
||||||
|
{
|
||||||
|
OSStatus lStatus = noErr;
|
||||||
|
lStatus = MPEnterCriticalRegion(m_mutex, kDurationImmediate);
|
||||||
|
assert(lStatus == noErr || lStatus == kMPTimeoutErr);
|
||||||
|
|
||||||
|
if (lStatus == noErr)
|
||||||
|
{
|
||||||
|
if (++m_count > 1)
|
||||||
|
{
|
||||||
|
lStatus = MPExitCriticalRegion(m_mutex);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void recursive_try_mutex::do_unlock()
|
||||||
|
{
|
||||||
|
if (--m_count == 0)
|
||||||
|
{
|
||||||
|
OSStatus lStatus = noErr;
|
||||||
|
lStatus = MPExitCriticalRegion(m_mutex);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void recursive_try_mutex::do_lock(cv_state& state)
|
||||||
|
{
|
||||||
|
OSStatus lStatus = noErr;
|
||||||
|
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
|
||||||
|
m_count = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void recursive_try_mutex::do_unlock(cv_state& state)
|
||||||
|
{
|
||||||
|
state = m_count;
|
||||||
|
m_count = 0;
|
||||||
|
|
||||||
|
OSStatus lStatus = noErr;
|
||||||
|
lStatus = MPExitCriticalRegion(m_mutex);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
}
|
||||||
|
|
||||||
|
recursive_timed_mutex::recursive_timed_mutex()
|
||||||
|
: m_count(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
recursive_timed_mutex::~recursive_timed_mutex()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void recursive_timed_mutex::do_lock()
|
||||||
|
{
|
||||||
|
OSStatus lStatus = noErr;
|
||||||
|
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
|
||||||
|
if (++m_count > 1)
|
||||||
|
{
|
||||||
|
lStatus = MPExitCriticalRegion(m_mutex);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool recursive_timed_mutex::do_trylock()
|
||||||
|
{
|
||||||
|
OSStatus lStatus = noErr;
|
||||||
|
lStatus = MPEnterCriticalRegion(m_mutex, kDurationImmediate);
|
||||||
|
assert(lStatus == noErr || lStatus == kMPTimeoutErr);
|
||||||
|
|
||||||
|
if (lStatus == noErr)
|
||||||
|
{
|
||||||
|
if (++m_count > 1)
|
||||||
|
{
|
||||||
|
lStatus = MPExitCriticalRegion(m_mutex);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool recursive_timed_mutex::do_timedlock(const xtime& xt)
|
||||||
|
{
|
||||||
|
int microseconds;
|
||||||
|
to_microduration(xt, microseconds);
|
||||||
|
Duration lDuration = kDurationMicrosecond * microseconds;
|
||||||
|
|
||||||
|
OSStatus lStatus = noErr;
|
||||||
|
lStatus = safe_enter_critical_region(m_mutex, lDuration, m_mutex_mutex);
|
||||||
|
assert(lStatus == noErr || lStatus == kMPTimeoutErr);
|
||||||
|
|
||||||
|
if (lStatus == noErr)
|
||||||
|
{
|
||||||
|
if (++m_count > 1)
|
||||||
|
{
|
||||||
|
lStatus = MPExitCriticalRegion(m_mutex);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void recursive_timed_mutex::do_unlock()
|
||||||
|
{
|
||||||
|
if (--m_count == 0)
|
||||||
|
{
|
||||||
|
OSStatus lStatus = noErr;
|
||||||
|
lStatus = MPExitCriticalRegion(m_mutex);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void recursive_timed_mutex::do_lock(cv_state& state)
|
||||||
|
{
|
||||||
|
OSStatus lStatus = noErr;
|
||||||
|
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
|
||||||
|
m_count = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void recursive_timed_mutex::do_unlock(cv_state& state)
|
||||||
|
{
|
||||||
|
state = m_count;
|
||||||
|
m_count = 0;
|
||||||
|
|
||||||
|
OSStatus lStatus = noErr;
|
||||||
|
lStatus = MPExitCriticalRegion(m_mutex);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
// Change Log:
|
||||||
|
// 8 Feb 01 WEKEMPF Initial version.
|
||||||
315
src/thread.cpp
Normal file
315
src/thread.cpp
Normal file
@@ -0,0 +1,315 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// William E. Kempf
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
|
// and its documentation for any purpose is hereby granted without fee,
|
||||||
|
// provided that the above copyright notice appear in all copies and
|
||||||
|
// that both that copyright notice and this permission notice appear
|
||||||
|
// in supporting documentation. William E. Kempf makes no representations
|
||||||
|
// about the suitability of this software for any purpose.
|
||||||
|
// It is provided "as is" without express or implied warranty.
|
||||||
|
|
||||||
|
#include <boost/thread/thread.hpp>
|
||||||
|
#include <boost/thread/xtime.hpp>
|
||||||
|
#include <boost/thread/condition.hpp>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
# include <windows.h>
|
||||||
|
# include <process.h>
|
||||||
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
|
# include <DriverServices.h>
|
||||||
|
|
||||||
|
# include "init.hpp"
|
||||||
|
# include "safe.hpp"
|
||||||
|
# include <boost/thread/tss.hpp>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "timeconv.inl"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class thread_param
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
thread_param(const boost::function0<void>& threadfunc) : m_threadfunc(threadfunc), m_started(false) { }
|
||||||
|
void wait()
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock scoped_lock(m_mutex);
|
||||||
|
while (!m_started)
|
||||||
|
m_condition.wait(scoped_lock);
|
||||||
|
}
|
||||||
|
void started()
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock scoped_lock(m_mutex);
|
||||||
|
m_started = true;
|
||||||
|
m_condition.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::mutex m_mutex;
|
||||||
|
boost::condition m_condition;
|
||||||
|
const boost::function0<void>& m_threadfunc;
|
||||||
|
bool m_started;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // unnamed namespace
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
unsigned __stdcall thread_proxy(void* param)
|
||||||
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
|
static void* thread_proxy(void* param)
|
||||||
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
|
static OSStatus thread_proxy(void* param)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
thread_param* p = static_cast<thread_param*>(param);
|
||||||
|
boost::function0<void> threadfunc = p->m_threadfunc;
|
||||||
|
p->started();
|
||||||
|
threadfunc();
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#if defined(BOOST_HAS_MPTASKS)
|
||||||
|
::boost::detail::thread_cleanup();
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
thread::thread()
|
||||||
|
: m_joinable(false)
|
||||||
|
{
|
||||||
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
m_thread = reinterpret_cast<void*>(GetCurrentThread());
|
||||||
|
m_id = GetCurrentThreadId();
|
||||||
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
|
m_thread = pthread_self();
|
||||||
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
|
threads::mac::detail::thread_init();
|
||||||
|
threads::mac::detail::create_singletons();
|
||||||
|
m_pTaskID = MPCurrentTaskID();
|
||||||
|
m_pJoinQueueID = kInvalidID;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
thread::thread(const function0<void>& threadfunc)
|
||||||
|
: m_joinable(true)
|
||||||
|
{
|
||||||
|
thread_param param(threadfunc);
|
||||||
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
m_thread = reinterpret_cast<void*>(_beginthreadex(0, 0, &thread_proxy, ¶m, 0, &m_id));
|
||||||
|
if (!m_thread)
|
||||||
|
throw thread_resource_error();
|
||||||
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
|
int res = 0;
|
||||||
|
res = pthread_create(&m_thread, 0, &thread_proxy, ¶m);
|
||||||
|
if (res != 0)
|
||||||
|
throw thread_resource_error();
|
||||||
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
|
threads::mac::detail::thread_init();
|
||||||
|
threads::mac::detail::create_singletons();
|
||||||
|
OSStatus lStatus = noErr;
|
||||||
|
|
||||||
|
m_pJoinQueueID = kInvalidID;
|
||||||
|
m_pTaskID = kInvalidID;
|
||||||
|
|
||||||
|
lStatus = MPCreateQueue(&m_pJoinQueueID);
|
||||||
|
if(lStatus != noErr) throw thread_resource_error();
|
||||||
|
|
||||||
|
lStatus = MPCreateTask(&thread_proxy, ¶m, 0UL, m_pJoinQueueID, NULL, NULL,
|
||||||
|
0UL, &m_pTaskID);
|
||||||
|
if(lStatus != noErr)
|
||||||
|
{
|
||||||
|
lStatus = MPDeleteQueue(m_pJoinQueueID);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
throw thread_resource_error();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
param.wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
thread::~thread()
|
||||||
|
{
|
||||||
|
if (m_joinable)
|
||||||
|
{
|
||||||
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
int res = 0;
|
||||||
|
res = CloseHandle(reinterpret_cast<HANDLE>(m_thread));
|
||||||
|
assert(res);
|
||||||
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
|
pthread_detach(m_thread);
|
||||||
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
|
assert(m_pJoinQueueID != kInvalidID);
|
||||||
|
OSStatus lStatus = MPDeleteQueue(m_pJoinQueueID);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool thread::operator==(const thread& other) const
|
||||||
|
{
|
||||||
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
return other.m_id == m_id;
|
||||||
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
|
return pthread_equal(m_thread, other.m_thread) != 0;
|
||||||
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
|
return other.m_pTaskID == m_pTaskID;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool thread::operator!=(const thread& other) const
|
||||||
|
{
|
||||||
|
return !operator==(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
void thread::join()
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_thread), INFINITE);
|
||||||
|
assert(res == WAIT_OBJECT_0);
|
||||||
|
res = CloseHandle(reinterpret_cast<HANDLE>(m_thread));
|
||||||
|
assert(res);
|
||||||
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
|
res = pthread_join(m_thread, 0);
|
||||||
|
assert(res == 0);
|
||||||
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
|
OSStatus lStatus = threads::mac::detail::safe_wait_on_queue(m_pJoinQueueID, NULL, NULL, NULL, kDurationForever);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
#endif
|
||||||
|
// This isn't a race condition since any race that could occur would
|
||||||
|
// have us in undefined behavior territory any way.
|
||||||
|
m_joinable = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void thread::sleep(const xtime& xt)
|
||||||
|
{
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
int milliseconds;
|
||||||
|
to_duration(xt, milliseconds);
|
||||||
|
Sleep(milliseconds);
|
||||||
|
xtime xt2;
|
||||||
|
xtime_get(&xt2, TIME_UTC);
|
||||||
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
|
# if defined(BOOST_HAS_PTHREAD_DELAY_NP)
|
||||||
|
timespec ts;
|
||||||
|
to_timespec_duration(xt, ts);
|
||||||
|
int res = 0;
|
||||||
|
res = pthread_delay_np(&ts);
|
||||||
|
assert(res == 0);
|
||||||
|
# elif defined(BOOST_HAS_NANOSLEEP)
|
||||||
|
timespec ts;
|
||||||
|
to_timespec_duration(xt, ts);
|
||||||
|
|
||||||
|
// nanosleep takes a timespec that is an offset, not
|
||||||
|
// an absolute time.
|
||||||
|
nanosleep(&ts, 0);
|
||||||
|
# else
|
||||||
|
mutex mx;
|
||||||
|
mutex::scoped_lock lock(mx);
|
||||||
|
condition cond;
|
||||||
|
cond.timed_wait(lock, xt);
|
||||||
|
# endif
|
||||||
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
|
int microseconds;
|
||||||
|
to_microduration(xt, microseconds);
|
||||||
|
Duration lMicroseconds(kDurationMicrosecond * microseconds);
|
||||||
|
AbsoluteTime sWakeTime(DurationToAbsolute(lMicroseconds));
|
||||||
|
threads::mac::detail::safe_delay_until(&sWakeTime);
|
||||||
|
#endif
|
||||||
|
if (xtime_cmp(xt, xt2) >= 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void thread::yield()
|
||||||
|
{
|
||||||
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
Sleep(0);
|
||||||
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
|
# if defined(BOOST_HAS_SCHED_YIELD)
|
||||||
|
int res = 0;
|
||||||
|
res = sched_yield();
|
||||||
|
assert(res == 0);
|
||||||
|
# elif defined(BOOST_HAS_PTHREAD_YIELD)
|
||||||
|
int res = 0;
|
||||||
|
res = pthread_yield();
|
||||||
|
assert(res == 0);
|
||||||
|
# else
|
||||||
|
xtime xt;
|
||||||
|
xtime_get(&xt, TIME_UTC);
|
||||||
|
sleep(xt);
|
||||||
|
# endif
|
||||||
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
|
MPYield();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
thread_group::thread_group()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
thread_group::~thread_group()
|
||||||
|
{
|
||||||
|
// We shouldn't have to scoped_lock here, since referencing this object from another thread
|
||||||
|
// while we're deleting it in the current thread is going to lead to undefined behavior
|
||||||
|
// any way.
|
||||||
|
for (std::list<thread*>::iterator it = m_threads.begin(); it != m_threads.end(); ++it)
|
||||||
|
delete (*it);
|
||||||
|
}
|
||||||
|
|
||||||
|
thread* thread_group::create_thread(const function0<void>& threadfunc)
|
||||||
|
{
|
||||||
|
// No scoped_lock required here since the only "shared data" that's modified here occurs
|
||||||
|
// inside add_thread which does scoped_lock.
|
||||||
|
std::auto_ptr<thread> thrd(new thread(threadfunc));
|
||||||
|
add_thread(thrd.get());
|
||||||
|
return thrd.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
void thread_group::add_thread(thread* thrd)
|
||||||
|
{
|
||||||
|
mutex::scoped_lock scoped_lock(m_mutex);
|
||||||
|
|
||||||
|
// For now we'll simply ignore requests to add a thread object multiple times.
|
||||||
|
// Should we consider this an error and either throw or return an error value?
|
||||||
|
std::list<thread*>::iterator it = std::find(m_threads.begin(), m_threads.end(), thrd);
|
||||||
|
assert(it == m_threads.end());
|
||||||
|
if (it == m_threads.end())
|
||||||
|
m_threads.push_back(thrd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void thread_group::remove_thread(thread* thrd)
|
||||||
|
{
|
||||||
|
mutex::scoped_lock scoped_lock(m_mutex);
|
||||||
|
|
||||||
|
// For now we'll simply ignore requests to remove a thread object that's not in the group.
|
||||||
|
// Should we consider this an error and either throw or return an error value?
|
||||||
|
std::list<thread*>::iterator it = std::find(m_threads.begin(), m_threads.end(), thrd);
|
||||||
|
assert(it != m_threads.end());
|
||||||
|
if (it != m_threads.end())
|
||||||
|
m_threads.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
void thread_group::join_all()
|
||||||
|
{
|
||||||
|
mutex::scoped_lock scoped_lock(m_mutex);
|
||||||
|
for (std::list<thread*>::iterator it = m_threads.begin(); it != m_threads.end(); ++it)
|
||||||
|
(*it)->join();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
// Change Log:
|
||||||
|
// 8 Feb 01 WEKEMPF Initial version.
|
||||||
|
// 1 Jun 01 WEKEMPF Added boost::thread initial implementation.
|
||||||
|
// 3 Jul 01 WEKEMPF Redesigned boost::thread to be noncopyable.
|
||||||
146
src/threadmon.cpp
Normal file
146
src/threadmon.cpp
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
// threadmon.cpp : Defines the entry point for the DLL application.
|
||||||
|
//
|
||||||
|
|
||||||
|
#define BOOST_THREADMON_EXPORTS
|
||||||
|
#include "threadmon.hpp"
|
||||||
|
|
||||||
|
#ifdef BOOST_HAS_WINTHREADS
|
||||||
|
|
||||||
|
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#ifdef BOOST_MSVC
|
||||||
|
# pragma warning(disable : 4786)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <set>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
typedef void (__cdecl * handler)(void);
|
||||||
|
typedef std::list<handler> exit_handlers;
|
||||||
|
typedef std::set<exit_handlers*> registered_handlers;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
CRITICAL_SECTION cs;
|
||||||
|
DWORD key;
|
||||||
|
registered_handlers registry;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(__BORLANDC__)
|
||||||
|
#define DllMain DllEntryPoint
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
BOOL WINAPI DllMain(HANDLE module, DWORD reason, LPVOID)
|
||||||
|
{
|
||||||
|
switch (reason)
|
||||||
|
{
|
||||||
|
case DLL_PROCESS_ATTACH:
|
||||||
|
InitializeCriticalSection(&cs);
|
||||||
|
key = TlsAlloc();
|
||||||
|
break;
|
||||||
|
case DLL_THREAD_ATTACH:
|
||||||
|
break;
|
||||||
|
case DLL_THREAD_DETACH:
|
||||||
|
{
|
||||||
|
// Call the thread's exit handlers.
|
||||||
|
exit_handlers* handlers = static_cast<exit_handlers*>(TlsGetValue(key));
|
||||||
|
if (handlers)
|
||||||
|
{
|
||||||
|
for (exit_handlers::iterator it = handlers->begin(); it != handlers->end(); ++it)
|
||||||
|
(*it)();
|
||||||
|
|
||||||
|
// Remove the exit handler list from the registered lists and then destroy it.
|
||||||
|
EnterCriticalSection(&cs);
|
||||||
|
registry.erase(handlers);
|
||||||
|
LeaveCriticalSection(&cs);
|
||||||
|
delete handlers;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DLL_PROCESS_DETACH:
|
||||||
|
{
|
||||||
|
// Assume the main thread is ending (call its handlers) and all other threads
|
||||||
|
// have already ended. If this DLL is loaded and unloaded dynamically at run time
|
||||||
|
// this is a bad assumption, but this is the best we can do.
|
||||||
|
exit_handlers* handlers = static_cast<exit_handlers*>(TlsGetValue(key));
|
||||||
|
if (handlers)
|
||||||
|
{
|
||||||
|
for (exit_handlers::iterator it = handlers->begin(); it != handlers->end(); ++it)
|
||||||
|
(*it)();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy any remaining exit handlers. Above we assumed there'd only be the main
|
||||||
|
// thread left, but to insure we don't get memory leaks we won't make that assumption
|
||||||
|
// here.
|
||||||
|
EnterCriticalSection(&cs);
|
||||||
|
for (registered_handlers::iterator it = registry.begin(); it != registry.end(); ++it)
|
||||||
|
delete (*it);
|
||||||
|
LeaveCriticalSection(&cs);
|
||||||
|
DeleteCriticalSection(&cs);
|
||||||
|
TlsFree(key);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int on_thread_exit(void (__cdecl * func)(void))
|
||||||
|
{
|
||||||
|
// Get the exit handlers for the current thread, creating and registering
|
||||||
|
// one if it doesn't exist.
|
||||||
|
exit_handlers* handlers = static_cast<exit_handlers*>(TlsGetValue(key));
|
||||||
|
if (!handlers)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
handlers = new exit_handlers;
|
||||||
|
// Handle "broken" implementations of operator new that don't throw.
|
||||||
|
if (!handlers)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to set a TLS value for the new handlers.
|
||||||
|
if (!TlsSetValue(key, handlers))
|
||||||
|
{
|
||||||
|
delete handlers;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to register this new handler so that memory can be properly
|
||||||
|
// cleaned up.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
EnterCriticalSection(&cs);
|
||||||
|
registry.insert(handlers);
|
||||||
|
LeaveCriticalSection(&cs);
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
LeaveCriticalSection(&cs);
|
||||||
|
delete handlers;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to add the handler to the list of exit handlers. If it's been previously
|
||||||
|
// added just report success and exit.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
handlers->push_front(func);
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // BOOST_HAS_WINTHREADS
|
||||||
23
src/threadmon.hpp
Normal file
23
src/threadmon.hpp
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#include <boost/config.hpp>
|
||||||
|
#ifndef BOOST_HAS_THREADS
|
||||||
|
# error Thread support is unavailable!
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef BOOST_HAS_WINTHREADS
|
||||||
|
|
||||||
|
// The following ifdef block is the standard way of creating macros which make exporting
|
||||||
|
// from a DLL simpler. All files within this DLL are compiled with the BOOST_THREADMON_EXPORTS
|
||||||
|
// symbol defined on the command line. this symbol should not be defined on any project
|
||||||
|
// that uses this DLL. This way any other project whose source files include this file see
|
||||||
|
// BOOST_THREADMON_API functions as being imported from a DLL, wheras this DLL sees symbols
|
||||||
|
// defined with this macro as being exported.
|
||||||
|
|
||||||
|
#ifdef BOOST_THREADMON_EXPORTS
|
||||||
|
#define BOOST_THREADMON_API __declspec(dllexport)
|
||||||
|
#else
|
||||||
|
#define BOOST_THREADMON_API __declspec(dllimport)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern "C" BOOST_THREADMON_API int on_thread_exit(void (__cdecl * func)(void));
|
||||||
|
|
||||||
|
#endif // BOOST_HAS_WINTHREADS
|
||||||
122
src/timeconv.inl
Normal file
122
src/timeconv.inl
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// William E. Kempf
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
|
// and its documentation for any purpose is hereby granted without fee,
|
||||||
|
// provided that the above copyright notice appear in all copies and
|
||||||
|
// that both that copyright notice and this permission notice appear
|
||||||
|
// in supporting documentation. 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.
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
const int MILLISECONDS_PER_SECOND = 1000;
|
||||||
|
const int NANOSECONDS_PER_SECOND = 1000000000;
|
||||||
|
const int NANOSECONDS_PER_MILLISECOND = 1000000;
|
||||||
|
|
||||||
|
const int MICROSECONDS_PER_SECOND = 1000000;
|
||||||
|
const int NANOSECONDS_PER_MICROSECOND = 1000;
|
||||||
|
|
||||||
|
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;
|
||||||
|
xt.nsec -= NANOSECONDS_PER_SECOND;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(BOOST_HAS_PTHREADS)
|
||||||
|
inline void to_timespec(const boost::xtime& xt, timespec& ts)
|
||||||
|
{
|
||||||
|
ts.tv_sec = static_cast<int>(xt.sec);
|
||||||
|
ts.tv_nsec = static_cast<int>(xt.nsec);
|
||||||
|
if(ts.tv_nsec > static_cast<const int>(NANOSECONDS_PER_SECOND))
|
||||||
|
{
|
||||||
|
ts.tv_sec += ts.tv_nsec / NANOSECONDS_PER_SECOND;
|
||||||
|
ts.tv_nsec %= NANOSECONDS_PER_SECOND;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void to_time(int milliseconds, timespec& ts)
|
||||||
|
{
|
||||||
|
boost::xtime xt;
|
||||||
|
to_time(milliseconds, xt);
|
||||||
|
to_timespec(xt, ts);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void to_timespec_duration(const boost::xtime& xt, timespec& ts)
|
||||||
|
{
|
||||||
|
boost::xtime cur;
|
||||||
|
int res = 0;
|
||||||
|
res = boost::xtime_get(&cur, boost::TIME_UTC);
|
||||||
|
assert(res == boost::TIME_UTC);
|
||||||
|
|
||||||
|
if (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
|
||||||
|
|
||||||
|
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 (xt.sec < cur.sec || (xt.sec == cur.sec && xt.nsec < cur.nsec))
|
||||||
|
milliseconds = 0;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
milliseconds = ((xt.sec - cur.sec) * MILLISECONDS_PER_SECOND) +
|
||||||
|
(((xt.nsec - cur.nsec) + (NANOSECONDS_PER_MILLISECOND/2)) /
|
||||||
|
NANOSECONDS_PER_MILLISECOND);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void to_microduration(const boost::xtime& xt, int& microseconds)
|
||||||
|
{
|
||||||
|
boost::xtime cur;
|
||||||
|
int res = 0;
|
||||||
|
res = boost::xtime_get(&cur, boost::TIME_UTC);
|
||||||
|
assert(res == boost::TIME_UTC);
|
||||||
|
|
||||||
|
if (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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change Log:
|
||||||
|
// 1 Jun 01 Initial creation.
|
||||||
247
src/tss.cpp
Normal file
247
src/tss.cpp
Normal file
@@ -0,0 +1,247 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// William E. Kempf
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
|
// and its documentation for any purpose is hereby granted without fee,
|
||||||
|
// provided that the above copyright notice appear in all copies and
|
||||||
|
// that both that copyright notice and this permission notice appear
|
||||||
|
// in supporting documentation. 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/once.hpp>
|
||||||
|
#include <boost/thread/exceptions.hpp>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
# include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
#include "threadmon.hpp"
|
||||||
|
#include <map>
|
||||||
|
namespace {
|
||||||
|
typedef std::pair<void(*)(void*), void*> cleanup_info;
|
||||||
|
typedef std::map<int, cleanup_info> cleanup_handlers;
|
||||||
|
|
||||||
|
DWORD key;
|
||||||
|
boost::once_flag once = BOOST_ONCE_INIT;
|
||||||
|
|
||||||
|
void init_cleanup_key()
|
||||||
|
{
|
||||||
|
key = TlsAlloc();
|
||||||
|
assert(key != 0xFFFFFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
void __cdecl cleanup()
|
||||||
|
{
|
||||||
|
cleanup_handlers* handlers = static_cast<cleanup_handlers*>(TlsGetValue(key));
|
||||||
|
for (cleanup_handlers::iterator it = handlers->begin(); it != handlers->end(); ++it)
|
||||||
|
{
|
||||||
|
cleanup_info info = it->second;
|
||||||
|
if (info.second)
|
||||||
|
info.first(info.second);
|
||||||
|
}
|
||||||
|
delete handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup_handlers* get_handlers()
|
||||||
|
{
|
||||||
|
boost::call_once(&init_cleanup_key, once);
|
||||||
|
|
||||||
|
cleanup_handlers* handlers = static_cast<cleanup_handlers*>(TlsGetValue(key));
|
||||||
|
if (!handlers)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
handlers = new cleanup_handlers;
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int res = 0;
|
||||||
|
res = TlsSetValue(key, handlers);
|
||||||
|
assert(res);
|
||||||
|
res = on_thread_exit(&cleanup);
|
||||||
|
assert(res == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
|
#include <map>
|
||||||
|
namespace {
|
||||||
|
typedef std::pair<void(*)(void*), void*> cleanup_info;
|
||||||
|
typedef std::map<int, cleanup_info> cleanup_handlers;
|
||||||
|
|
||||||
|
TaskStorageIndex key;
|
||||||
|
boost::once_flag once = BOOST_ONCE_INIT;
|
||||||
|
|
||||||
|
void init_cleanup_key()
|
||||||
|
{
|
||||||
|
OSStatus lStatus = MPAllocateTaskStorageIndex(&key);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup_handlers* get_handlers()
|
||||||
|
{
|
||||||
|
boost::call_once(&init_cleanup_key, once);
|
||||||
|
|
||||||
|
cleanup_handlers* handlers = reinterpret_cast<cleanup_handlers*>(MPGetTaskStorageValue(key));
|
||||||
|
if (!handlers)
|
||||||
|
{
|
||||||
|
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 detail {
|
||||||
|
|
||||||
|
|
||||||
|
void thread_cleanup()
|
||||||
|
{
|
||||||
|
cleanup_handlers* handlers = reinterpret_cast<cleanup_handlers*>(MPGetTaskStorageValue(key));
|
||||||
|
if(handlers != NULL)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace boost { namespace detail {
|
||||||
|
|
||||||
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
tss::tss(void (*cleanup)(void*))
|
||||||
|
{
|
||||||
|
m_key = TlsAlloc();
|
||||||
|
if (m_key == 0xFFFFFFFF)
|
||||||
|
throw thread_resource_error();
|
||||||
|
|
||||||
|
m_cleanup = cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
tss::~tss()
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = TlsFree(m_key);
|
||||||
|
assert(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* tss::get() const
|
||||||
|
{
|
||||||
|
return TlsGetValue(m_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool tss::set(void* value)
|
||||||
|
{
|
||||||
|
if (value && m_cleanup)
|
||||||
|
{
|
||||||
|
cleanup_handlers* handlers = get_handlers();
|
||||||
|
assert(handlers);
|
||||||
|
if (!handlers)
|
||||||
|
return false;
|
||||||
|
cleanup_info info(m_cleanup, value);
|
||||||
|
(*handlers)[m_key] = info;
|
||||||
|
}
|
||||||
|
return !!TlsSetValue(m_key, value);
|
||||||
|
}
|
||||||
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
|
tss::tss(void (*cleanup)(void*))
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = pthread_key_create(&m_key, cleanup);
|
||||||
|
if (res != 0)
|
||||||
|
throw thread_resource_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
tss::~tss()
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = pthread_key_delete(m_key);
|
||||||
|
assert(res == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* tss::get() const
|
||||||
|
{
|
||||||
|
return pthread_getspecific(m_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool tss::set(void* value)
|
||||||
|
{
|
||||||
|
return pthread_setspecific(m_key, value) == 0;
|
||||||
|
}
|
||||||
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
|
tss::tss(void (*cleanup)(void*))
|
||||||
|
{
|
||||||
|
OSStatus lStatus = MPAllocateTaskStorageIndex(&m_key);
|
||||||
|
if(lStatus != noErr)
|
||||||
|
throw thread_resource_error();
|
||||||
|
|
||||||
|
m_cleanup = cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
tss::~tss()
|
||||||
|
{
|
||||||
|
OSStatus lStatus = MPDeallocateTaskStorageIndex(m_key);
|
||||||
|
assert(lStatus == noErr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* tss::get() const
|
||||||
|
{
|
||||||
|
TaskStorageValue ulValue = MPGetTaskStorageValue(m_key);
|
||||||
|
return(reinterpret_cast<void *>(ulValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool tss::set(void* value)
|
||||||
|
{
|
||||||
|
if (value && m_cleanup)
|
||||||
|
{
|
||||||
|
cleanup_handlers* handlers = get_handlers();
|
||||||
|
assert(handlers);
|
||||||
|
if (!handlers)
|
||||||
|
return false;
|
||||||
|
cleanup_info info(m_cleanup, value);
|
||||||
|
(*handlers)[m_key] = info;
|
||||||
|
}
|
||||||
|
OSStatus lStatus = MPSetTaskStorageValue(m_key, reinterpret_cast<TaskStorageValue>(value));
|
||||||
|
return(lStatus == noErr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
// Change Log:
|
||||||
|
// 6 Jun 01 WEKEMPF Initial version.
|
||||||
120
src/xtime.cpp
Normal file
120
src/xtime.cpp
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
// Copyright (C) 2001
|
||||||
|
// William E. Kempf
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
|
// and its documentation for any purpose is hereby granted without fee,
|
||||||
|
// provided that the above copyright notice appear in all copies and
|
||||||
|
// that both that copyright notice and this permission notice appear
|
||||||
|
// in supporting documentation. 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>
|
||||||
|
|
||||||
|
#if defined(BOOST_HAS_FTIME)
|
||||||
|
# include <windows.h>
|
||||||
|
#elif defined(BOOST_HAS_GETTIMEOFDAY)
|
||||||
|
# include <sys/time.h>
|
||||||
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
|
# include <DriverServices.h>
|
||||||
|
# include <boost/thread/detail/force_cast.hpp>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
#ifdef BOOST_HAS_MPTASKS
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
using thread::force_cast;
|
||||||
|
|
||||||
|
struct startup_time_info
|
||||||
|
{
|
||||||
|
startup_time_info()
|
||||||
|
{
|
||||||
|
// 1970 Jan 1 at 00:00:00
|
||||||
|
static const DateTimeRec k_sUNIXBase = {1970, 1, 1, 0, 0, 0, 0};
|
||||||
|
static unsigned long s_ulUNIXBaseSeconds = 0UL;
|
||||||
|
|
||||||
|
if(s_ulUNIXBaseSeconds == 0UL)
|
||||||
|
{
|
||||||
|
// calculate the number of seconds between the Mac OS base and the UNIX base
|
||||||
|
// the first time we enter this constructor.
|
||||||
|
DateToSeconds(&k_sUNIXBase, &s_ulUNIXBaseSeconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long ulSeconds;
|
||||||
|
|
||||||
|
// get the time in UpTime units twice, with the time in seconds in the middle.
|
||||||
|
uint64_t ullFirstUpTime = force_cast<uint64_t>(UpTime());
|
||||||
|
GetDateTime(&ulSeconds);
|
||||||
|
uint64_t ullSecondUpTime = force_cast<uint64_t>(UpTime());
|
||||||
|
|
||||||
|
// calculate the midpoint of the two UpTimes, and save that.
|
||||||
|
uint64_t ullAverageUpTime = (ullFirstUpTime + ullSecondUpTime) / 2ULL;
|
||||||
|
m_sStartupAbsoluteTime = force_cast<AbsoluteTime>(ullAverageUpTime);
|
||||||
|
|
||||||
|
// save the number of seconds, recentered at the UNIX base.
|
||||||
|
m_ulStartupSeconds = ulSeconds - s_ulUNIXBaseSeconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
AbsoluteTime m_sStartupAbsoluteTime;
|
||||||
|
UInt32 m_ulStartupSeconds;
|
||||||
|
};
|
||||||
|
|
||||||
|
static startup_time_info g_sStartupTimeInfo;
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
int xtime_get(struct xtime* xtp, int clock_type)
|
||||||
|
{
|
||||||
|
if (clock_type == TIME_UTC)
|
||||||
|
{
|
||||||
|
#if defined(BOOST_HAS_FTIME)
|
||||||
|
FILETIME ft;
|
||||||
|
GetSystemTimeAsFileTime(&ft);
|
||||||
|
const boost::uint64_t TIMESPEC_TO_FILETIME_OFFSET = ((boost::uint64_t)27111902UL << 32) + (boost::uint64_t)3577643008UL;
|
||||||
|
xtp->sec = (int)((*(__int64*)&ft - TIMESPEC_TO_FILETIME_OFFSET) / 10000000);
|
||||||
|
xtp->nsec = (int)((*(__int64*)&ft - TIMESPEC_TO_FILETIME_OFFSET -
|
||||||
|
((__int64)xtp->sec * (__int64)10000000)) * 100);
|
||||||
|
return clock_type;
|
||||||
|
#elif defined(BOOST_HAS_GETTIMEOFDAY)
|
||||||
|
struct timeval tv;
|
||||||
|
gettimeofday(&tv, 0);
|
||||||
|
xtp->sec = tv.tv_sec;
|
||||||
|
xtp->nsec = tv.tv_usec * 1000;
|
||||||
|
return clock_type;
|
||||||
|
#elif defined(BOOST_HAS_CLOCK_GETTIME)
|
||||||
|
timespec ts;
|
||||||
|
clock_gettime(CLOCK_REALTIME, &ts);
|
||||||
|
xtp->sec = ts.tv_sec;
|
||||||
|
xtp->nsec = ts.tv_nsec;
|
||||||
|
return clock_type;
|
||||||
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
|
using detail::thread::force_cast;
|
||||||
|
// the Mac OS does not have an MP-safe way of getting the date/time, so we use a
|
||||||
|
// delta from the startup time. We _could_ defer this and use something that is
|
||||||
|
// interrupt-safe, but this would be _SLOW_, and we need speed here.
|
||||||
|
const uint64_t k_ullNanosecondsPerSecond(1000ULL * 1000ULL * 1000ULL);
|
||||||
|
AbsoluteTime sUpTime(UpTime());
|
||||||
|
uint64_t ullNanoseconds(force_cast<uint64_t>(AbsoluteDeltaToNanoseconds(sUpTime, detail::g_sStartupTimeInfo.m_sStartupAbsoluteTime)));
|
||||||
|
uint64_t ullSeconds = (ullNanoseconds / k_ullNanosecondsPerSecond);
|
||||||
|
ullNanoseconds -= (ullSeconds * k_ullNanosecondsPerSecond);
|
||||||
|
xtp->sec = detail::g_sStartupTimeInfo.m_ulStartupSeconds + ullSeconds;
|
||||||
|
xtp->nsec = ullNanoseconds;
|
||||||
|
return clock_type;
|
||||||
|
#else
|
||||||
|
# error "xtime_get implementation undefined"
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
// Change Log:
|
||||||
|
// 8 Feb 01 WEKEMPF Initial version.
|
||||||
2
test/.cvsignore
Normal file
2
test/.cvsignore
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
bin
|
||||||
|
*.pdb
|
||||||
1
test/Carbon.r
Normal file
1
test/Carbon.r
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/*
|
||||||
43
test/Jamfile
43
test/Jamfile
@@ -0,0 +1,43 @@
|
|||||||
|
# (C) Copyright William E. Kempf 2001. Permission to copy, use, modify, sell and
|
||||||
|
# distribute this software is granted provided this copyright notice appears
|
||||||
|
# in all copies. This software is provided "as is" without express or implied
|
||||||
|
# warranty, and with no claim as to its suitability for any purpose.
|
||||||
|
#
|
||||||
|
# Boost.Threads test Jamfile
|
||||||
|
#
|
||||||
|
# Declares the following targets:
|
||||||
|
# 1. test_thread, a unit test executable.
|
||||||
|
# Additional configuration variables used:
|
||||||
|
# 1. PTW32 may be used on Win32 platforms to specify that the pthreads-win32
|
||||||
|
# library should be used instead of "native" threads. This feature is
|
||||||
|
# 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/test ;
|
||||||
|
|
||||||
|
# Include threads.jam for Boost.Threads global build information.
|
||||||
|
# This greatly simplifies the Jam code needed to configure the build
|
||||||
|
# for the various Win32 build types.
|
||||||
|
SEARCH on <module@>threads.jam = $(BOOST_ROOT)/libs/thread/build ;
|
||||||
|
include <module@>threads.jam ;
|
||||||
|
|
||||||
|
sources = test.cpp test_thread.cpp test_mutex.cpp test_condition.cpp test_tss.cpp test_once.cpp ;
|
||||||
|
|
||||||
|
#######################
|
||||||
|
# Declare the Boost.Threads unit test program test_thread.
|
||||||
|
|
||||||
|
unit-test test_thread
|
||||||
|
: $(sources)
|
||||||
|
<lib>../build/boost_thread
|
||||||
|
<lib>../../test/build/unit_test_framework
|
||||||
|
$(threadmon)
|
||||||
|
: <sysinclude>$(BOOST_ROOT)
|
||||||
|
$(pthreads-win32)
|
||||||
|
<threading>multi
|
||||||
|
: debug release <runtime-link>static/dynamic
|
||||||
|
;
|
||||||
|
|||||||
20
test/test.cpp
Normal file
20
test/test.cpp
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
|
extern boost::unit_test_framework::test_suite* thread_tests();
|
||||||
|
extern boost::unit_test_framework::test_suite* mutex_tests();
|
||||||
|
extern boost::unit_test_framework::test_suite* condition_tests();
|
||||||
|
extern boost::unit_test_framework::test_suite* tss_tests();
|
||||||
|
extern boost::unit_test_framework::test_suite* once_tests();
|
||||||
|
|
||||||
|
boost::unit_test_framework::test_suite* init_unit_test_suite(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
boost::unit_test_framework::test_suite* test = BOOST_TEST_SUITE("Boost.Threads test suite");
|
||||||
|
|
||||||
|
test->add(thread_tests());
|
||||||
|
test->add(mutex_tests());
|
||||||
|
test->add(condition_tests());
|
||||||
|
test->add(tss_tests());
|
||||||
|
test->add(once_tests());
|
||||||
|
|
||||||
|
return test;
|
||||||
|
}
|
||||||
BIN
test/test.mcp
Normal file
BIN
test/test.mcp
Normal file
Binary file not shown.
191
test/test_condition.cpp
Normal file
191
test/test_condition.cpp
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
#include <boost/thread/condition.hpp>
|
||||||
|
#include <boost/thread/thread.hpp>
|
||||||
|
#include <boost/thread/xtime.hpp>
|
||||||
|
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
struct condition_test_data
|
||||||
|
{
|
||||||
|
condition_test_data() : notified(0), awoken(0) { }
|
||||||
|
|
||||||
|
boost::mutex mutex;
|
||||||
|
boost::condition condition;
|
||||||
|
int notified;
|
||||||
|
int awoken;
|
||||||
|
};
|
||||||
|
|
||||||
|
void condition_test_thread(void* param)
|
||||||
|
{
|
||||||
|
condition_test_data* data = static_cast<condition_test_data*>(param);
|
||||||
|
boost::mutex::scoped_lock lock(data->mutex);
|
||||||
|
BOOST_CHECK(lock);
|
||||||
|
while (!(data->notified > 0))
|
||||||
|
data->condition.wait(lock);
|
||||||
|
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++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_condition_notify_one()
|
||||||
|
{
|
||||||
|
condition_test_data data;
|
||||||
|
|
||||||
|
boost::thread thread(thread_adapter(&condition_test_thread, &data));
|
||||||
|
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(data.mutex);
|
||||||
|
BOOST_CHECK(lock);
|
||||||
|
data.notified++;
|
||||||
|
data.condition.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
thread.join();
|
||||||
|
BOOST_CHECK_EQUAL(data.awoken, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_condition_notify_all()
|
||||||
|
{
|
||||||
|
const int NUMTHREADS = 5;
|
||||||
|
boost::thread_group threads;
|
||||||
|
condition_test_data data;
|
||||||
|
|
||||||
|
for (int i = 0; i < NUMTHREADS; ++i)
|
||||||
|
threads.create_thread(thread_adapter(&condition_test_thread, &data));
|
||||||
|
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(data.mutex);
|
||||||
|
BOOST_CHECK(lock);
|
||||||
|
data.notified++;
|
||||||
|
data.condition.notify_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
threads.join_all();
|
||||||
|
BOOST_CHECK_EQUAL(data.awoken, NUMTHREADS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_condition_waits()
|
||||||
|
{
|
||||||
|
condition_test_data data;
|
||||||
|
|
||||||
|
boost::thread thread(thread_adapter(&condition_test_waits, &data));
|
||||||
|
|
||||||
|
boost::xtime xt;
|
||||||
|
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(data.mutex);
|
||||||
|
BOOST_CHECK(lock);
|
||||||
|
|
||||||
|
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();
|
||||||
|
while (data.awoken != 1)
|
||||||
|
data.condition.wait(lock);
|
||||||
|
BOOST_CHECK_EQUAL(data.awoken, 1);
|
||||||
|
|
||||||
|
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();
|
||||||
|
while (data.awoken != 2)
|
||||||
|
data.condition.wait(lock);
|
||||||
|
BOOST_CHECK_EQUAL(data.awoken, 2);
|
||||||
|
|
||||||
|
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();
|
||||||
|
while (data.awoken != 3)
|
||||||
|
data.condition.wait(lock);
|
||||||
|
BOOST_CHECK_EQUAL(data.awoken, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
BOOST_CHECK_EQUAL(data.awoken, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::unit_test_framework::test_suite* condition_tests()
|
||||||
|
{
|
||||||
|
boost::unit_test_framework::test_suite* test = BOOST_TEST_SUITE("Boost.Threads: condition test suite");
|
||||||
|
|
||||||
|
test->add(BOOST_TEST_CASE(&test_condition_notify_one));
|
||||||
|
test->add(BOOST_TEST_CASE(&test_condition_notify_all));
|
||||||
|
test->add(BOOST_TEST_CASE(&test_condition_waits));
|
||||||
|
|
||||||
|
return test;
|
||||||
|
}
|
||||||
184
test/test_mutex.cpp
Normal file
184
test/test_mutex.cpp
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
#include <boost/thread/mutex.hpp>
|
||||||
|
#include <boost/thread/recursive_mutex.hpp>
|
||||||
|
#include <boost/thread/xtime.hpp>
|
||||||
|
#include <boost/thread/condition.hpp>
|
||||||
|
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
#include <boost/test/unit_test_suite_ex.hpp>
|
||||||
|
|
||||||
|
template <typename M>
|
||||||
|
struct test_lock
|
||||||
|
{
|
||||||
|
typedef M mutex_type;
|
||||||
|
typedef typename M::scoped_lock lock_type;
|
||||||
|
|
||||||
|
void operator()()
|
||||||
|
{
|
||||||
|
mutex_type mutex;
|
||||||
|
boost::condition condition;
|
||||||
|
|
||||||
|
// Test the lock's constructors.
|
||||||
|
{
|
||||||
|
lock_type lock(mutex, false);
|
||||||
|
BOOST_CHECK(!lock);
|
||||||
|
}
|
||||||
|
lock_type lock(mutex);
|
||||||
|
BOOST_CHECK(lock);
|
||||||
|
|
||||||
|
// Construct and initialize an xtime for a fast time out.
|
||||||
|
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.
|
||||||
|
// No one is going to notify this condition variable. We expect to
|
||||||
|
// time out.
|
||||||
|
BOOST_CHECK(!condition.timed_wait(lock, xt));
|
||||||
|
BOOST_CHECK(lock);
|
||||||
|
|
||||||
|
// Test the lock and unlock methods.
|
||||||
|
lock.unlock();
|
||||||
|
BOOST_CHECK(!lock);
|
||||||
|
lock.lock();
|
||||||
|
BOOST_CHECK(lock);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename M>
|
||||||
|
struct test_trylock
|
||||||
|
{
|
||||||
|
typedef M mutex_type;
|
||||||
|
typedef typename M::scoped_try_lock try_lock_type;
|
||||||
|
|
||||||
|
void operator()()
|
||||||
|
{
|
||||||
|
mutex_type mutex;
|
||||||
|
boost::condition condition;
|
||||||
|
|
||||||
|
// Test the lock's constructors.
|
||||||
|
{
|
||||||
|
try_lock_type lock(mutex);
|
||||||
|
BOOST_CHECK(lock);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
try_lock_type lock(mutex, false);
|
||||||
|
BOOST_CHECK(!lock);
|
||||||
|
}
|
||||||
|
try_lock_type lock(mutex, true);
|
||||||
|
BOOST_CHECK(lock);
|
||||||
|
|
||||||
|
// Construct and initialize an xtime for a fast time out.
|
||||||
|
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.
|
||||||
|
// No one is going to notify this condition variable. We expect to
|
||||||
|
// time out.
|
||||||
|
BOOST_CHECK(!condition.timed_wait(lock, xt));
|
||||||
|
BOOST_CHECK(lock);
|
||||||
|
|
||||||
|
// Test the lock, unlock and trylock methods.
|
||||||
|
lock.unlock();
|
||||||
|
BOOST_CHECK(!lock);
|
||||||
|
lock.lock();
|
||||||
|
BOOST_CHECK(lock);
|
||||||
|
lock.unlock();
|
||||||
|
BOOST_CHECK(!lock);
|
||||||
|
BOOST_CHECK(lock.try_lock());
|
||||||
|
BOOST_CHECK(lock);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename M>
|
||||||
|
struct test_timedlock
|
||||||
|
{
|
||||||
|
typedef M mutex_type;
|
||||||
|
typedef typename M::scoped_timed_lock timed_lock_type;
|
||||||
|
|
||||||
|
void operator()()
|
||||||
|
{
|
||||||
|
mutex_type mutex;
|
||||||
|
boost::condition condition;
|
||||||
|
|
||||||
|
// Test the lock's constructors.
|
||||||
|
{
|
||||||
|
// Construct and initialize an xtime for a fast time out.
|
||||||
|
boost::xtime xt;
|
||||||
|
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), boost::TIME_UTC);
|
||||||
|
xt.nsec += 100000000;
|
||||||
|
|
||||||
|
timed_lock_type lock(mutex, xt);
|
||||||
|
BOOST_CHECK(lock);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
timed_lock_type lock(mutex, false);
|
||||||
|
BOOST_CHECK(!lock);
|
||||||
|
}
|
||||||
|
timed_lock_type lock(mutex, true);
|
||||||
|
BOOST_CHECK(lock);
|
||||||
|
|
||||||
|
// Construct and initialize an xtime for a fast time out.
|
||||||
|
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.
|
||||||
|
// No one is going to notify this condition variable. We expect to
|
||||||
|
// time out.
|
||||||
|
BOOST_CHECK(!condition.timed_wait(lock, xt));
|
||||||
|
BOOST_CHECK(lock);
|
||||||
|
|
||||||
|
// Test the lock, unlock and timedlock methods.
|
||||||
|
lock.unlock();
|
||||||
|
BOOST_CHECK(!lock);
|
||||||
|
lock.lock();
|
||||||
|
BOOST_CHECK(lock);
|
||||||
|
lock.unlock();
|
||||||
|
BOOST_CHECK(!lock);
|
||||||
|
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), boost::TIME_UTC);
|
||||||
|
xt.nsec += 100000000;
|
||||||
|
BOOST_CHECK(lock.timed_lock(xt));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename M>
|
||||||
|
struct test_recursive_lock
|
||||||
|
{
|
||||||
|
typedef M mutex;
|
||||||
|
|
||||||
|
void operator()()
|
||||||
|
{
|
||||||
|
mutex mx;
|
||||||
|
mutex::scoped_lock lock1(mx);
|
||||||
|
mutex::scoped_lock lock2(mx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
boost::unit_test_framework::test_suite* mutex_tests()
|
||||||
|
{
|
||||||
|
boost::unit_test_framework::test_suite* test = BOOST_TEST_SUITE("Boost.Threads: mutex test suite");
|
||||||
|
|
||||||
|
test->add(BOOST_TEST_CASE(test_lock<boost::mutex>()));
|
||||||
|
|
||||||
|
test->add(BOOST_TEST_CASE(test_lock<boost::try_mutex>()));
|
||||||
|
test->add(BOOST_TEST_CASE(test_trylock<boost::try_mutex>()));
|
||||||
|
|
||||||
|
test->add(BOOST_TEST_CASE(test_lock<boost::timed_mutex>()));
|
||||||
|
test->add(BOOST_TEST_CASE(test_trylock<boost::timed_mutex>()));
|
||||||
|
test->add(BOOST_TEST_CASE(test_timedlock<boost::timed_mutex>()));
|
||||||
|
|
||||||
|
test->add(BOOST_TEST_CASE(test_lock<boost::recursive_mutex>()));
|
||||||
|
test->add(BOOST_TEST_CASE(test_recursive_lock<boost::recursive_mutex>()));
|
||||||
|
|
||||||
|
test->add(BOOST_TEST_CASE(test_lock<boost::recursive_try_mutex>()));
|
||||||
|
test->add(BOOST_TEST_CASE(test_trylock<boost::recursive_try_mutex>()));
|
||||||
|
test->add(BOOST_TEST_CASE(test_recursive_lock<boost::recursive_try_mutex>()));
|
||||||
|
|
||||||
|
test->add(BOOST_TEST_CASE(test_lock<boost::recursive_timed_mutex>()));
|
||||||
|
test->add(BOOST_TEST_CASE(test_trylock<boost::recursive_timed_mutex>()));
|
||||||
|
test->add(BOOST_TEST_CASE(test_timedlock<boost::recursive_timed_mutex>()));
|
||||||
|
test->add(BOOST_TEST_CASE(test_recursive_lock<boost::recursive_timed_mutex>()));
|
||||||
|
|
||||||
|
return test;
|
||||||
|
}
|
||||||
39
test/test_once.cpp
Normal file
39
test/test_once.cpp
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#include <boost/thread/once.hpp>
|
||||||
|
#include <boost/thread/thread.hpp>
|
||||||
|
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
int once_value = 0;
|
||||||
|
boost::once_flag once = BOOST_ONCE_INIT;
|
||||||
|
|
||||||
|
void init_once_value()
|
||||||
|
{
|
||||||
|
once_value++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_once_thread()
|
||||||
|
{
|
||||||
|
boost::call_once(&init_once_value, once);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_once()
|
||||||
|
{
|
||||||
|
const int NUMTHREADS=5;
|
||||||
|
boost::thread_group threads;
|
||||||
|
for (int i=0; i<NUMTHREADS; ++i)
|
||||||
|
threads.create_thread(&test_once_thread);
|
||||||
|
threads.join_all();
|
||||||
|
BOOST_CHECK_EQUAL(once_value, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::unit_test_framework::test_suite* once_tests()
|
||||||
|
{
|
||||||
|
boost::unit_test_framework::test_suite* test = BOOST_TEST_SUITE("Boost.Threads: once test suite");
|
||||||
|
|
||||||
|
test->add(BOOST_TEST_CASE(&test_once));
|
||||||
|
|
||||||
|
return test;
|
||||||
|
}
|
||||||
89
test/test_thread.cpp
Normal file
89
test/test_thread.cpp
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
#include <boost/thread/thread.hpp>
|
||||||
|
#include <boost/thread/xtime.hpp>
|
||||||
|
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
inline bool xtime_in_range(boost::xtime& xt, int less_seconds, int greater_seconds)
|
||||||
|
{
|
||||||
|
boost::xtime cur;
|
||||||
|
BOOST_CHECK_EQUAL(boost::xtime_get(&cur, boost::TIME_UTC), boost::TIME_UTC);
|
||||||
|
|
||||||
|
boost::xtime less = cur;
|
||||||
|
less.sec += less_seconds;
|
||||||
|
|
||||||
|
boost::xtime greater = cur;
|
||||||
|
greater.sec += greater_seconds;
|
||||||
|
|
||||||
|
return (boost::xtime_cmp(xt, less) >= 0) && (boost::xtime_cmp(xt, greater) <= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_value;
|
||||||
|
|
||||||
|
void simple_thread()
|
||||||
|
{
|
||||||
|
test_value = 999;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct thread_adapter
|
||||||
|
{
|
||||||
|
thread_adapter(void (*func)(boost::thread& parent), boost::thread& parent)
|
||||||
|
: func(func), parent(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator()()
|
||||||
|
{
|
||||||
|
(*func)(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void (*func)(boost::thread& parent);
|
||||||
|
boost::thread& parent;
|
||||||
|
};
|
||||||
|
|
||||||
|
void comparison_thread(boost::thread& parent)
|
||||||
|
{
|
||||||
|
boost::thread thrd;
|
||||||
|
BOOST_TEST(thrd != parent);
|
||||||
|
BOOST_TEST(thrd == boost::thread());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_sleep()
|
||||||
|
{
|
||||||
|
boost::xtime xt;
|
||||||
|
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), boost::TIME_UTC);
|
||||||
|
xt.sec += 5;
|
||||||
|
|
||||||
|
boost::thread::sleep(xt);
|
||||||
|
|
||||||
|
// Insure it's in a range instead of checking actual equality due to time lapse
|
||||||
|
BOOST_CHECK(xtime_in_range(xt, -1, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_creation()
|
||||||
|
{
|
||||||
|
test_value = 0;
|
||||||
|
boost::thread thrd(&simple_thread);
|
||||||
|
thrd.join();
|
||||||
|
BOOST_CHECK_EQUAL(test_value, 999);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_comparison()
|
||||||
|
{
|
||||||
|
boost::thread self;
|
||||||
|
boost::thread thrd(thread_adapter(&comparison_thread, self));
|
||||||
|
thrd.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::unit_test_framework::test_suite* thread_tests()
|
||||||
|
{
|
||||||
|
boost::unit_test_framework::test_suite* test = BOOST_TEST_SUITE("Boost.Threads: thread test suite");
|
||||||
|
|
||||||
|
test->add(BOOST_TEST_CASE(&test_sleep));
|
||||||
|
test->add(BOOST_TEST_CASE(&test_creation));
|
||||||
|
test->add(BOOST_TEST_CASE(&test_comparison));
|
||||||
|
|
||||||
|
return test;
|
||||||
|
}
|
||||||
59
test/test_tss.cpp
Normal file
59
test/test_tss.cpp
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
#include <boost/thread/tss.hpp>
|
||||||
|
#include <boost/thread/mutex.hpp>
|
||||||
|
#include <boost/thread/thread.hpp>
|
||||||
|
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
boost::mutex tss_mutex;
|
||||||
|
int tss_instances = 0;
|
||||||
|
|
||||||
|
struct tss_value_t
|
||||||
|
{
|
||||||
|
tss_value_t()
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(tss_mutex);
|
||||||
|
++tss_instances;
|
||||||
|
value = 0;
|
||||||
|
}
|
||||||
|
~tss_value_t()
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(tss_mutex);
|
||||||
|
--tss_instances;
|
||||||
|
}
|
||||||
|
int value;
|
||||||
|
};
|
||||||
|
|
||||||
|
boost::thread_specific_ptr<tss_value_t> tss_value;
|
||||||
|
|
||||||
|
void test_tss_thread()
|
||||||
|
{
|
||||||
|
tss_value.reset(new tss_value_t());
|
||||||
|
for (int i=0; i<1000; ++i)
|
||||||
|
{
|
||||||
|
int& n = tss_value->value;
|
||||||
|
BOOST_CHECK_EQUAL(n, i);
|
||||||
|
++n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_tss()
|
||||||
|
{
|
||||||
|
const int NUMTHREADS=5;
|
||||||
|
boost::thread_group threads;
|
||||||
|
for (int i=0; i<NUMTHREADS; ++i)
|
||||||
|
threads.create_thread(&test_tss_thread);
|
||||||
|
threads.join_all();
|
||||||
|
BOOST_CHECK_EQUAL(tss_instances, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::unit_test_framework::test_suite* tss_tests()
|
||||||
|
{
|
||||||
|
boost::unit_test_framework::test_suite* test = BOOST_TEST_SUITE("Boost.Threads: tss test suite");
|
||||||
|
|
||||||
|
test->add(BOOST_TEST_CASE(&test_tss));
|
||||||
|
|
||||||
|
return test;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user