mirror of
https://github.com/boostorg/thread.git
synced 2026-02-05 22:22:11 +00:00
Compare commits
110 Commits
develop
...
svn-branch
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9f9292e2e3 | ||
|
|
0a88a53a33 | ||
|
|
0bce1befd9 | ||
|
|
9f354c98ab | ||
|
|
274b04bcf7 | ||
|
|
539d19468d | ||
|
|
fff6d9eddd | ||
|
|
5472ebdfde | ||
|
|
50c034f650 | ||
|
|
2a5e1a36b5 | ||
|
|
2e10da00ba | ||
|
|
af4b2d5d2a | ||
|
|
a89ec945c0 | ||
|
|
08eb9eed48 | ||
|
|
7ed1a79ab8 | ||
|
|
18974b3cb4 | ||
|
|
c973faf627 | ||
|
|
6ffcde749a | ||
|
|
42840199aa | ||
|
|
1addb6ad9b | ||
|
|
1dbdb77ed7 | ||
|
|
430ebf66f9 | ||
|
|
97562928a8 | ||
|
|
45aabefb4d | ||
|
|
b0e970863b | ||
|
|
3468fb61bc | ||
|
|
5982a97bdf | ||
|
|
ffef009696 | ||
|
|
c8f181e461 | ||
|
|
7b84d69915 | ||
|
|
bbb8efe58f | ||
|
|
63209e3c69 | ||
|
|
2272c322f9 | ||
|
|
36acb80412 | ||
|
|
b72142cef7 | ||
|
|
6dd6f51faa | ||
|
|
82630dc9bb | ||
|
|
3402aea7c1 | ||
|
|
5c4bd8e9c9 | ||
|
|
a11748d187 | ||
|
|
dc906613dc | ||
|
|
b69bdd3918 | ||
|
|
d90ef5eeef | ||
|
|
641d658a10 | ||
|
|
fef99d3db2 | ||
|
|
0fc8d8897d | ||
|
|
ad9f6244b0 | ||
|
|
59d082202c | ||
|
|
b7549a5bae | ||
|
|
f0dce755bb | ||
|
|
c1261d6df3 | ||
|
|
1fb0dac16d | ||
|
|
424d02fafa | ||
|
|
52717aaa75 | ||
|
|
335f85ad5b | ||
|
|
7da456edca | ||
|
|
f50176946d | ||
|
|
aeafcbb822 | ||
|
|
171b890972 | ||
|
|
89a9531d34 | ||
|
|
3259f681a4 | ||
|
|
17f72cf580 | ||
|
|
e03f0ed008 | ||
|
|
0804944002 | ||
|
|
8e5d5002cd | ||
|
|
008aaeaeee | ||
|
|
c1283bb731 | ||
|
|
46b1a4d1e3 | ||
|
|
ff6e0df2bc | ||
|
|
9cb9224b3c | ||
|
|
5ea5494172 | ||
|
|
e4c27981d0 | ||
|
|
fe61772d47 | ||
|
|
a437d6d7f6 | ||
|
|
c9f52098b9 | ||
|
|
a15a35a4b6 | ||
|
|
14c8137ba6 | ||
|
|
5caf9ed169 | ||
|
|
5da4a7b105 | ||
|
|
91c4af37ad | ||
|
|
5848dc2f56 | ||
|
|
efa12b1db9 | ||
|
|
58b6eba0ea | ||
|
|
f73253fcf5 | ||
|
|
3627dfc3b7 | ||
|
|
f8ebb9a127 | ||
|
|
2a0f57a8de | ||
|
|
da7278acef | ||
|
|
b17eb23f2e | ||
|
|
8e01ac5d04 | ||
|
|
5d6a1633e0 | ||
|
|
2e6f9a785e | ||
|
|
4e1acef27e | ||
|
|
73e482832d | ||
|
|
949b332337 | ||
|
|
244cfd3f01 | ||
|
|
3239fe0c22 | ||
|
|
ca10110aa7 | ||
|
|
fd4c76c7a5 | ||
|
|
60d7c84aa2 | ||
|
|
c043efa346 | ||
|
|
dab1961b5a | ||
|
|
6f94d26c50 | ||
|
|
83baf142f2 | ||
|
|
88bb39e3ce | ||
|
|
48ad27558a | ||
|
|
a0ba7f174c | ||
|
|
6e60d33181 | ||
|
|
bc69926604 | ||
|
|
d90825f7f9 |
@@ -1,2 +1,3 @@
|
|||||||
bin*
|
bin*
|
||||||
*.pdb
|
*.pdb
|
||||||
|
bjam.log
|
||||||
158
build/Jamfile
158
build/Jamfile
@@ -1,18 +1,16 @@
|
|||||||
# (C) Copyright William E. Kempf 2001. Permission to copy, use, modify,
|
# Copyright (C) 2001-2003
|
||||||
# sell and distribute this software is granted provided this copyright
|
# William E. Kempf
|
||||||
# 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
|
# Permission to use, copy, modify, distribute and sell this software
|
||||||
# any purpose.
|
# 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.
|
||||||
#
|
#
|
||||||
# Boost.Threads build Jamfile
|
# Boost.Threads build Jamfile
|
||||||
#
|
#
|
||||||
# Declares the following targets:
|
|
||||||
# 1. libboost_thread, a static link library.
|
|
||||||
# 1a. On Win32 (when PTW32 is not defined), a dynamic link library
|
|
||||||
# boost_threadmon, which must be used in conjunction with
|
|
||||||
# libboost_thread. Note that this DLL *must* be used through static
|
|
||||||
# linking to the import library. Dynamic loading will cause undefined
|
|
||||||
# behavior.
|
|
||||||
# Additional configuration variables used:
|
# Additional configuration variables used:
|
||||||
# 1. PTW32 may be used on Win32 platforms to specify that the pthreads-win32
|
# 1. PTW32 may be used on Win32 platforms to specify that the pthreads-win32
|
||||||
# library should be used instead of "native" threads. This feature is
|
# library should be used instead of "native" threads. This feature is
|
||||||
@@ -29,46 +27,106 @@ subproject libs/thread/build ;
|
|||||||
# Include threads.jam for Boost.Threads global build information.
|
# Include threads.jam for Boost.Threads global build information.
|
||||||
# This greatly simplifies the Jam code needed to configure the build
|
# This greatly simplifies the Jam code needed to configure the build
|
||||||
# for the various Win32 build types.
|
# for the various Win32 build types.
|
||||||
SEARCH on <module@>threads.jam = $(SUBDIR) ;
|
import ./threads ;
|
||||||
include <module@>threads.jam ;
|
|
||||||
|
|
||||||
template thread_libs
|
{
|
||||||
## sources ##
|
CPP_SOURCES =
|
||||||
: <template>thread_base
|
barrier
|
||||||
## requirements ##
|
condition
|
||||||
:
|
exceptions
|
||||||
## default build ##
|
mutex
|
||||||
: debug release <runtime-link>static/dynamic
|
named
|
||||||
;
|
once
|
||||||
|
recursive_mutex
|
||||||
|
read_write_mutex
|
||||||
|
shared_memory
|
||||||
|
thread
|
||||||
|
threadmon
|
||||||
|
thread_pool
|
||||||
|
tss
|
||||||
|
xtime
|
||||||
|
;
|
||||||
|
|
||||||
|
template boost_thread_lib_base
|
||||||
#######################
|
: ## sources ##
|
||||||
# Declare the Boost.Threads static link library libboost_thread.
|
<template>thread_base
|
||||||
|
../src/$(CPP_SOURCES).cpp
|
||||||
# Base names of the source files for libboost_thread.
|
: ## requirements ##
|
||||||
CPP_SOURCES = condition mutex recursive_mutex thread tss xtime once
|
<define>BOOST_THREAD_BUILD_LIB=1
|
||||||
exceptions threadmon ;
|
<runtime-link>static
|
||||||
|
# the common names rule ensures that the library will
|
||||||
#if $(NT) && ! $(PTW32)
|
# be named according to the rules used by the install
|
||||||
#{
|
# and auto-link features:
|
||||||
dll boost_thread
|
common-variant-tag
|
||||||
: <template>thread_libs ../src/$(CPP_SOURCES).cpp
|
: ## default build ##
|
||||||
: <define>BOOST_THREAD_BUILD_DLL=1
|
|
||||||
;
|
;
|
||||||
#}
|
|
||||||
#else
|
|
||||||
#{
|
|
||||||
# lib boost_thread
|
|
||||||
# : <template>thread_libs ../src/$(CPP_SOURCES).cpp
|
|
||||||
# ;
|
|
||||||
#}
|
|
||||||
|
|
||||||
#######################
|
template thread_dll_base
|
||||||
# Stage the generated targets.
|
: ## sources ##
|
||||||
|
<template>thread_base
|
||||||
|
../src/$(CPP_SOURCES).cpp
|
||||||
|
: ## requirements ##
|
||||||
|
<define>BOOST_THREAD_BUILD_DLL=1
|
||||||
|
<runtime-link>dynamic
|
||||||
|
# the common names rule ensures that the library will
|
||||||
|
# be named according to the rules used by the install
|
||||||
|
# and auto-link features:
|
||||||
|
common-variant-tag
|
||||||
|
: ## default build ##
|
||||||
|
;
|
||||||
|
|
||||||
#stage bin-stage
|
lib $(boost_thread_lib_name)
|
||||||
# : <lib>boost_thread $(threadmon)
|
: ## sources ##
|
||||||
# : <tag><runtime-link-static>"s"
|
<template>boost_thread_lib_base
|
||||||
# <tag><debug>"d"
|
: ## requirements ##
|
||||||
# : debug release <runtime-link>static/dynamic
|
<define>BOOST_THREAD_LIB_NAME=$(boost_thread_lib_name)
|
||||||
#;
|
: ## default build ##
|
||||||
|
;
|
||||||
|
|
||||||
|
dll $(boost_thread_lib_name)
|
||||||
|
: ## sources ##
|
||||||
|
<template>thread_dll_base
|
||||||
|
: ## requirements ##
|
||||||
|
<define>BOOST_THREAD_LIB_NAME=$(boost_thread_lib_name)
|
||||||
|
: ## default build ##
|
||||||
|
;
|
||||||
|
|
||||||
|
stage bin-stage
|
||||||
|
: <dll>$(boost_thread_lib_name)
|
||||||
|
<lib>$(boost_thread_lib_name)
|
||||||
|
;
|
||||||
|
|
||||||
|
install thread lib
|
||||||
|
: <dll>$(boost_thread_lib_name)
|
||||||
|
<lib>$(boost_thread_lib_name)
|
||||||
|
;
|
||||||
|
|
||||||
|
if $(boost_thread_lib_settings_ptw32)
|
||||||
|
{
|
||||||
|
lib $(boost_thread_lib_name_ptw32)
|
||||||
|
: ## sources ##
|
||||||
|
<template>boost_thread_lib_base
|
||||||
|
: ## requirements ##
|
||||||
|
<define>BOOST_THREAD_LIB_NAME=$(boost_thread_lib_name_ptw32)
|
||||||
|
$(pthreads-win32)
|
||||||
|
;
|
||||||
|
|
||||||
|
dll $(boost_thread_lib_name_ptw32)
|
||||||
|
: ## sources ##
|
||||||
|
<template>thread_dll_base
|
||||||
|
: ## requirements ##
|
||||||
|
<define>BOOST_THREAD_LIB_NAME=$(boost_thread_lib_name_ptw32)
|
||||||
|
$(pthreads-win32)
|
||||||
|
;
|
||||||
|
|
||||||
|
stage bin-stage
|
||||||
|
: <dll>$(boost_thread_lib_name_ptw32)
|
||||||
|
<lib>$(boost_thread_lib_name_ptw32)
|
||||||
|
;
|
||||||
|
|
||||||
|
install thread lib
|
||||||
|
: <dll>$(boost_thread_lib_name_ptw32)
|
||||||
|
<lib>$(boost_thread_lib_name_ptw32)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
|
|
||||||
|
# Declare the uses system library
|
||||||
|
lib pthread : : <name>pthread ;
|
||||||
|
|
||||||
project boost/thread
|
project boost/thread
|
||||||
: source-location ../src
|
: source-location ../src
|
||||||
: use-requirements <find-library>pthread
|
: usage-requirements <library>pthread
|
||||||
;
|
;
|
||||||
|
|
||||||
CPP_SOURCES = condition mutex recursive_mutex thread tss xtime once exceptions ;
|
CPP_SOURCES = condition mutex recursive_mutex thread tss xtime once exceptions ;
|
||||||
|
|||||||
@@ -1,28 +1,45 @@
|
|||||||
|
# Copyright (C) 2001-2003
|
||||||
|
# William E. Kempf
|
||||||
|
#
|
||||||
|
# Permission to use, copy, modify, distribute and sell this software
|
||||||
|
# and its documentation for any purpose is hereby granted without fee,
|
||||||
|
# provided that the above copyright notice appear in all copies and
|
||||||
|
# that both that copyright notice and this permission notice appear
|
||||||
|
# in supporting documentation. William E. Kempf makes no representations
|
||||||
|
# about the suitability of this software for any purpose.
|
||||||
|
# It is provided "as is" without express or implied warranty.
|
||||||
|
|
||||||
# Do some OS-specific setup
|
# Do some OS-specific setup
|
||||||
|
|
||||||
threadmon = ;
|
|
||||||
pthreads-win32 = ;
|
|
||||||
|
|
||||||
if $(NT)
|
|
||||||
{
|
{
|
||||||
if $(PTW32)
|
#thread library name
|
||||||
|
boost_thread_lib_name = boost_thread ;
|
||||||
|
|
||||||
|
#thread library name with "pthreads-win32" library
|
||||||
|
boost_thread_lib_name_ptw32 = boost_thread_ptw32 ;
|
||||||
|
|
||||||
|
if $(NT)
|
||||||
{
|
{
|
||||||
local install-path = $(PTW32[1]) ;
|
if $(PTW32_DIR)
|
||||||
local lib = $(PTW32[2]) ;
|
{
|
||||||
pthreads-win32 =
|
if $(PTW32_LIB)
|
||||||
<define>BOOST_HAS_PTHREADS
|
{
|
||||||
<define>PtW32NoCatchWarn
|
boost_thread_lib_settings_ptw32 =
|
||||||
<include>$(install-path)/pre-built/include
|
<define>BOOST_HAS_PTHREADS
|
||||||
<library-file>$(install-path)/pre-built/lib/$(lib)
|
<define>PtW32NoCatchWarn
|
||||||
;
|
<include>$(PTW32_DIR)/pre-built/include
|
||||||
|
<library-file>$(PTW32_DIR)/pre-built/lib/$(PTW32_LIB)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
template thread_base
|
template thread_base
|
||||||
## sources ##
|
: ## sources ##
|
||||||
:
|
: ## requirements ##
|
||||||
## requirements ##
|
<sysinclude>$(BOOST_ROOT)
|
||||||
: <sysinclude>$(BOOST_ROOT) <threading>multi $(pthreads-win32)
|
<threading>multi
|
||||||
## default build ##
|
<borland><*><cxxflags>-w-8004
|
||||||
:
|
<borland><*><cxxflags>-w-8057
|
||||||
;
|
: ## default build ##
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|||||||
3
doc/.cvsignore
Normal file
3
doc/.cvsignore
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
bin
|
||||||
|
html
|
||||||
|
catalog.xml
|
||||||
5
doc/Jamfile.v2
Normal file
5
doc/Jamfile.v2
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
project boost/doc ;
|
||||||
|
import boostbook : boostbook ;
|
||||||
|
|
||||||
|
boostbook doc : thread.xml ;
|
||||||
|
|
||||||
64
doc/acknowledgements.xml
Normal file
64
doc/acknowledgements.xml
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
||||||
|
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
|
||||||
|
<!ENTITY % threads.entities SYSTEM "entities.xml">
|
||||||
|
%threads.entities;
|
||||||
|
]>
|
||||||
|
<section id="thread.acknowledgements"
|
||||||
|
last-revision="$Date$">
|
||||||
|
<title>Acknowledgements</title>
|
||||||
|
<para>William E. Kempf was the architect, designer, and implementor of
|
||||||
|
&Boost.Threads;.</para>
|
||||||
|
<para>Mac OS Carbon implementation written by Mac Murrett.</para>
|
||||||
|
<para>Dave Moore provided initial submissions and further comments on the
|
||||||
|
<code>barrier</code>
|
||||||
|
,
|
||||||
|
<code>thread_pool</code>
|
||||||
|
,
|
||||||
|
<code>read_write_mutex</code>
|
||||||
|
,
|
||||||
|
<code>read_write_try_mutex</code>
|
||||||
|
and
|
||||||
|
<code>read_write_timed_mutex</code>
|
||||||
|
classes.</para>
|
||||||
|
<para>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).</para>
|
||||||
|
<para>Mike Glassford finished changes to &Boost.Threads; that were begun
|
||||||
|
by William Kempf and moved them into the main CVS branch.
|
||||||
|
He also addressed a number of issues that were brought up on the Boost
|
||||||
|
developer's mailing list and provided some additions and changes to the
|
||||||
|
read_write_mutex and related classes.</para>
|
||||||
|
<para>The documentation was written by William E. Kempf. Beman Dawes
|
||||||
|
provided additional documentation material and editing.
|
||||||
|
Mike Glassford finished William Kempf's conversion of the documentation to
|
||||||
|
BoostBook format and added a number of new sections.</para>
|
||||||
|
<para>Discussions on the boost.org mailing list were essential in the
|
||||||
|
development of &Boost.Threads;
|
||||||
|
. 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, 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.</para>
|
||||||
|
<para>Apologies for anyone inadvertently missed.</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
|
||||||
<link rel="stylesheet" type="text/css" href="../../../boost.css">
|
|
||||||
<title>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>
|
|
||||||
78
doc/barrier-ref.xml
Normal file
78
doc/barrier-ref.xml
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
||||||
|
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
|
||||||
|
<!ENTITY % threads.entities SYSTEM "entities.xml">
|
||||||
|
%threads.entities;
|
||||||
|
]>
|
||||||
|
<header name="boost/thread/barrier.hpp"
|
||||||
|
last-revision="$Date$">
|
||||||
|
<namespace name="boost">
|
||||||
|
<class name="barrier">
|
||||||
|
<inherit access="private">
|
||||||
|
<type><classname>boost::noncopyable</classname></type>
|
||||||
|
<purpose>Exposition only</purpose>
|
||||||
|
</inherit>
|
||||||
|
|
||||||
|
<purpose>
|
||||||
|
<para>An object of class <classname>barrier</classname> is a synchronization
|
||||||
|
primitive used to cause a set of threads to wait until they each perform a
|
||||||
|
certain function or each reach a particular point in their execution.</para>
|
||||||
|
</purpose>
|
||||||
|
|
||||||
|
<description>
|
||||||
|
<para>When a barrier is created, it is initialized with a thread count N.
|
||||||
|
The first N-1 calls to <code>wait()</code> will all cause their threads to be blocked.
|
||||||
|
The Nth call to <code>wait()</code> will allow all of the waiting threads, including
|
||||||
|
the Nth thread, to be placed in a ready state. The Nth call will also "reset"
|
||||||
|
the barrier such that, if an additional N+1th call is made to <code>wait()</code>,
|
||||||
|
it will be as though this were the first call to <code>wait()</code>; in other
|
||||||
|
words, the N+1th to 2N-1th calls to <code>wait()</code> will cause their
|
||||||
|
threads to be blocked, and the 2Nth call to <code>wait()</code> will allow all of
|
||||||
|
the waiting threads, including the 2Nth thread, to be placed in a ready state
|
||||||
|
and reset the barrier. This functionality allows the same set of N threads to re-use
|
||||||
|
a barrier object to synchronize their execution at multiple points during their
|
||||||
|
execution.</para>
|
||||||
|
<para>See <xref linkend="threads.glossary"/> for definitions of thread
|
||||||
|
states <link linkend="threads.glossary.thread-state">blocked</link>
|
||||||
|
and <link linkend="threads.glossary.thread-state">ready</link>.
|
||||||
|
Note that "waiting" is a synonym for blocked.</para>
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<constructor>
|
||||||
|
<parameter name="count">
|
||||||
|
<paramtype>size_t</paramtype>
|
||||||
|
</parameter>
|
||||||
|
|
||||||
|
<effects><simpara>Constructs a <classname>barrier</classname> object that
|
||||||
|
will cause <code>count</code> threads to block on a call to <code>wait()</code>.
|
||||||
|
</simpara></effects>
|
||||||
|
</constructor>
|
||||||
|
|
||||||
|
<destructor>
|
||||||
|
<effects><simpara>Destroys <code>*this</code>. If threads are still executing
|
||||||
|
their <code>wait()</code> operations, the behavior for these threads is undefined.
|
||||||
|
</simpara></effects>
|
||||||
|
</destructor>
|
||||||
|
|
||||||
|
<method-group name="waiting">
|
||||||
|
<method name="wait">
|
||||||
|
<type>bool</type>
|
||||||
|
|
||||||
|
<effects><simpara>Wait until N threads call <code>wait()</code>, where
|
||||||
|
N equals the <code>count</code> provided to the constructor for the
|
||||||
|
barrier object.</simpara>
|
||||||
|
<simpara><emphasis role="bold">Note</emphasis> that if the barrier is
|
||||||
|
destroyed before <code>wait()</code> can return, the behavior is
|
||||||
|
undefined.</simpara></effects>
|
||||||
|
|
||||||
|
<returns>Exactly one of the N threads will receive a return value
|
||||||
|
of <code>true</code>, the others will receive a value of <code>false</code>.
|
||||||
|
Precisely which thread receives the return value of <code>true</code> will
|
||||||
|
be implementation-defined. Applications can use this value to designate one
|
||||||
|
thread as a leader that will take a certain action, and the other threads
|
||||||
|
emerging from the barrier can wait for that action to take place.</returns>
|
||||||
|
</method>
|
||||||
|
</method-group>
|
||||||
|
</class>
|
||||||
|
</namespace>
|
||||||
|
</header>
|
||||||
@@ -1,165 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
|
||||||
<link rel="stylesheet" type="text/css" href="../../../boost.css">
|
|
||||||
<title>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>
|
|
||||||
230
doc/bibliography.xml
Normal file
230
doc/bibliography.xml
Normal file
@@ -0,0 +1,230 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
||||||
|
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
|
||||||
|
<!ENTITY % threads.entities SYSTEM "entities.xml">
|
||||||
|
%threads.entities;
|
||||||
|
]>
|
||||||
|
<bibliography id="threads.bibliography"
|
||||||
|
last-revision="$Date$">
|
||||||
|
<title>Bibliography</title>
|
||||||
|
<biblioentry id="threads.bib.AndrewsSchneider83">
|
||||||
|
<abbrev id="threads.bib.AndrewsSchneider83.abbrev">AndrewsSchnieder83</abbrev>
|
||||||
|
<biblioset relation="journal">
|
||||||
|
<title>ACM Computing Surveys</title>
|
||||||
|
<volumenum>Vol. 15</volumenum>
|
||||||
|
<issuenum>No. 1</issuenum>
|
||||||
|
<date>March, 1983</date>
|
||||||
|
</biblioset>
|
||||||
|
<biblioset relation="article">
|
||||||
|
<authorgroup>
|
||||||
|
<author>
|
||||||
|
<firstname>Gregory</firstname>
|
||||||
|
<othername>R.</othername>
|
||||||
|
<surname>Andrews</surname>
|
||||||
|
</author>
|
||||||
|
<author>
|
||||||
|
<firstname>Fred</firstname>
|
||||||
|
<othername>B.</othername>
|
||||||
|
<surname>Schneider</surname>
|
||||||
|
</author>
|
||||||
|
</authorgroup>
|
||||||
|
<title>
|
||||||
|
<ulink
|
||||||
|
url="http://www.acm.org/pubs/citations/journals/surveys/1983-15-1/p3-andrews/"
|
||||||
|
>Concepts and Notations for Concurrent Programming</ulink>
|
||||||
|
</title>
|
||||||
|
</biblioset>
|
||||||
|
<para>Good general background reading. Includes descriptions of Path
|
||||||
|
Expressions, Message Passing, and Remote Procedure Call in addition to the
|
||||||
|
basics</para>
|
||||||
|
</biblioentry>
|
||||||
|
<biblioentry id="threads.bib.Boost">
|
||||||
|
<abbrev id="threads.bib.Boost.abbrev">Boost</abbrev>
|
||||||
|
<bibliomisc>The <emphasis>Boost</emphasis> world wide web site.
|
||||||
|
<ulink url="http:/www.boost.org">http://www.boost.org</ulink></bibliomisc>
|
||||||
|
<para>&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.</para>
|
||||||
|
</biblioentry>
|
||||||
|
<biblioentry id="threads.bib.Hansen73">
|
||||||
|
<abbrev id="threads.bib.Hansen73.abbrev">Hansen73</abbrev>
|
||||||
|
<biblioset relation="journal">
|
||||||
|
<title>ACM Computing Surveys</title>
|
||||||
|
<volumenum>Vol. 5</volumenum>
|
||||||
|
<issuenum>No. 4</issuenum>
|
||||||
|
<date>December, 1983</date>
|
||||||
|
</biblioset>
|
||||||
|
<biblioset relation="article">
|
||||||
|
<author>0-201-63392-2
|
||||||
|
<firstname>Per Brinch</firstname>
|
||||||
|
<lastname>Hansen</lastname>
|
||||||
|
</author>
|
||||||
|
<title>
|
||||||
|
<ulink
|
||||||
|
url="http://www.acm.org/pubs/articles/journals/surveys/1973-5-4/p223-hansen/"
|
||||||
|
>Concurrent Programming Concepts</ulink>
|
||||||
|
</title>
|
||||||
|
</biblioset>
|
||||||
|
<para>"This paper describes the evolution of language features for
|
||||||
|
multiprogramming from event queues and semaphores to critical regions and
|
||||||
|
monitors." Includes analysis of why events 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.</para>
|
||||||
|
</biblioentry>
|
||||||
|
<biblioentry id="threads.bib.Butenhof97">
|
||||||
|
<abbrev id="threads.bib.Butenhof97.abbrev">Butenhof97</abbrev>
|
||||||
|
<title>
|
||||||
|
<ulink url="http://cseng.aw.com/book/0,3828,0201633922,00.html"
|
||||||
|
>Programming with POSIX Threads </ulink>
|
||||||
|
</title>
|
||||||
|
<author>
|
||||||
|
<firstname>David</firstname>
|
||||||
|
<othername>R.</othername>
|
||||||
|
<surname>Butenhof</surname>
|
||||||
|
</author>
|
||||||
|
<publisher>Addison-Wesley</publisher>
|
||||||
|
<copyright><year>1997</year></copyright>
|
||||||
|
<isbn>ISNB: 0-201-63392-2</isbn>
|
||||||
|
<para>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</para>
|
||||||
|
</biblioentry>
|
||||||
|
<biblioentry id="threads.bib.Hoare74">
|
||||||
|
<abbrev id="threads.bib.Hoare74.abbrev">Hoare74</abbrev>
|
||||||
|
<biblioset relation="journal">
|
||||||
|
<title>Communications of the ACM</title>
|
||||||
|
<volumenum>Vol. 17</volumenum>
|
||||||
|
<issuenum>No. 10</issuenum>
|
||||||
|
<date>October, 1974</date>
|
||||||
|
</biblioset>
|
||||||
|
<biblioset relation="article">
|
||||||
|
<title>
|
||||||
|
<ulink url=" http://www.acm.org/classics/feb96/"
|
||||||
|
>Monitors: An Operating System Structuring Concept</ulink>
|
||||||
|
</title>
|
||||||
|
<author>
|
||||||
|
<firstname>C.A.R.</firstname>
|
||||||
|
<surname>Hoare</surname>
|
||||||
|
</author>
|
||||||
|
<pagenums>549-557</pagenums>
|
||||||
|
</biblioset>
|
||||||
|
<para>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.</para>
|
||||||
|
</biblioentry>
|
||||||
|
<biblioentry id="threads.bib.ISO98">
|
||||||
|
<abbrev id="threads.bib.ISO98.abbrev">ISO98</abbrev>
|
||||||
|
<title>
|
||||||
|
<ulink url="http://www.ansi.org">Programming Language C++</ulink>
|
||||||
|
</title>
|
||||||
|
<orgname>ISO/IEC</orgname>
|
||||||
|
<releaseinfo>14882:1998(E)</releaseinfo>
|
||||||
|
<para>This is the official C++ Standards document. Available from the ANSI
|
||||||
|
(American National Standards Institute) Electronic Standards Store.</para>
|
||||||
|
</biblioentry>
|
||||||
|
<biblioentry id="threads.bib.McDowellHelmbold89">
|
||||||
|
<abbrev id="threads.bib.McDowellHelmbold89.abbrev">McDowellHelmbold89</abbrev>
|
||||||
|
<biblioset relation="journal">
|
||||||
|
<title>Communications of the ACM</title>
|
||||||
|
<volumenum>Vol. 21</volumenum>
|
||||||
|
<issuenum>No. 2</issuenum>
|
||||||
|
<date>December, 1989</date>
|
||||||
|
</biblioset>
|
||||||
|
<biblioset>
|
||||||
|
<author>
|
||||||
|
<firstname>Charles</firstname>
|
||||||
|
<othername>E.</othername>
|
||||||
|
<surname>McDowell</surname>
|
||||||
|
</author>
|
||||||
|
<author>
|
||||||
|
<firstname>David</firstname>
|
||||||
|
<othername>P.</othername>
|
||||||
|
<surname>Helmbold</surname>
|
||||||
|
</author>
|
||||||
|
<title>
|
||||||
|
<ulink
|
||||||
|
url="http://www.acm.org/pubs/citations/journals/surveys/1989-21-4/p593-mcdowell/"
|
||||||
|
>Debugging Concurrent Programs</ulink>
|
||||||
|
</title>
|
||||||
|
</biblioset>
|
||||||
|
<para>Identifies many of the unique failure modes and debugging difficulties
|
||||||
|
associated with concurrent programs.</para>
|
||||||
|
</biblioentry>
|
||||||
|
<biblioentry id="threads.bib.SchmidtPyarali">
|
||||||
|
<abbrev id="threads.bib.SchmidtPyarali.abbrev">SchmidtPyarali</abbrev>
|
||||||
|
<title>
|
||||||
|
<ulink url="http://www.cs.wustl.edu/~schmidt/win32-cv-1.html8"
|
||||||
|
>Strategies for Implementing POSIX Condition Variables on Win32</ulink>
|
||||||
|
</title>
|
||||||
|
<authorgroup>
|
||||||
|
<author>
|
||||||
|
<firstname>Douglas</firstname>
|
||||||
|
<othername>C.</othername>
|
||||||
|
<surname>Schmidt</surname>
|
||||||
|
</author>
|
||||||
|
<author>
|
||||||
|
<firstname>Irfan</firstname>
|
||||||
|
<surname>Pyarali</surname>
|
||||||
|
</author>
|
||||||
|
</authorgroup>
|
||||||
|
<orgname>Department of Computer Science, Washington University, St. Louis,
|
||||||
|
Missouri</orgname>
|
||||||
|
<para>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.</para>
|
||||||
|
</biblioentry>
|
||||||
|
<biblioentry id="threads.bib.SchmidtStalRohnertBuschmann">
|
||||||
|
<abbrev
|
||||||
|
id="threads.bib.SchmidtStalRohnertBuschmann.abbrev">SchmidtStalRohnertBuschmann</abbrev>
|
||||||
|
<title>
|
||||||
|
<ulink
|
||||||
|
url="http://www.wiley.com/Corporate/Website/Objects/Products/0,9049,104671,00.html"
|
||||||
|
>Pattern-Oriented Architecture Volume 2</ulink>
|
||||||
|
</title>
|
||||||
|
<subtitle>Patterns for Concurrent and Networked Objects</subtitle>
|
||||||
|
<titleabbrev>POSA2</titleabbrev>
|
||||||
|
<authorgroup>
|
||||||
|
<author>
|
||||||
|
<firstname>Douglas</firstname>
|
||||||
|
<othername>C.</othername>
|
||||||
|
<surname>Schmidt</surname>
|
||||||
|
</author>
|
||||||
|
<author>
|
||||||
|
<firstname>Michael</firstname>
|
||||||
|
<lastname>Stal</lastname>
|
||||||
|
</author>
|
||||||
|
<author>
|
||||||
|
<firstname>Hans</firstname>
|
||||||
|
<surname>Rohnert</surname>
|
||||||
|
</author>
|
||||||
|
<author>
|
||||||
|
<firstname>Frank</firstname>
|
||||||
|
<surname>Buschmann</surname>
|
||||||
|
</author>
|
||||||
|
</authorgroup>
|
||||||
|
<publisher>Wiley</publisher>
|
||||||
|
<copyright><year>2000</year></copyright>
|
||||||
|
<para>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 &Boost.Threads;
|
||||||
|
documentation.</para>
|
||||||
|
</biblioentry>
|
||||||
|
<biblioentry id="threads.bib.Stroustrup">
|
||||||
|
<abbrev id="threads.bib.Stroustrup.abbrev">Stroustrup</abbrev>
|
||||||
|
<title>
|
||||||
|
<ulink url="http://cseng.aw.com/book/0,3828,0201700735,00.html"
|
||||||
|
>The C++ Programming Language</ulink>
|
||||||
|
</title>
|
||||||
|
<edition>Special Edition</edition>
|
||||||
|
<publisher>Addison-Wesley</publisher>
|
||||||
|
<copyright><year>2000</year></copyright>
|
||||||
|
<isbn>ISBN: 0-201-70073-5</isbn>
|
||||||
|
<para>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.</para>
|
||||||
|
</biblioentry>
|
||||||
|
</bibliography>
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
|
||||||
<link rel="stylesheet" type="text/css" href="../../../boost.css">
|
|
||||||
<title>{{Library}} - Overview</title>
|
|
||||||
</head>
|
|
||||||
<body link="#0000ff" vlink="#800080">
|
|
||||||
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
|
|
||||||
"header">
|
|
||||||
<tr>
|
|
||||||
<td valign="top" width="300">
|
|
||||||
<h3><a href="../../../index.htm"><img height="86" width="277" alt="C++ Boost" src="../../../c++boost.gif" border="0"></a></h3>
|
|
||||||
</td>
|
|
||||||
<td valign="top">
|
|
||||||
<h1 align="center">Boost.Threads</h1>
|
|
||||||
<h2 align="center">Building and Testing</h2>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<hr>
|
|
||||||
<dl class="index">
|
|
||||||
<dt><a href="#introduction">Introduction</a></dt>
|
|
||||||
<dt><a href="#topic1">First topic</a></dt>
|
|
||||||
<dt><a href="#topic2">Second topic</a></dt>
|
|
||||||
<dt><a href="#footnotes">Footnotes</a></dt>
|
|
||||||
</dl>
|
|
||||||
<h2><a name="introduction"></a>Introduction</h2>
|
|
||||||
<p>How you build the Boost.Threads libraries, and how you build your own applications
|
|
||||||
that use those libraries, are some of the most frequently asked questions. Build
|
|
||||||
processes are difficult to deal with in a portable manner. That's one reason
|
|
||||||
why Boost.Threads makes use of <a href="../../../tools/build/index.html">Boost.Build</a>.
|
|
||||||
In general you should refer to the documentation for <a href="../../../tools/build/index.html">Boost.Build</a>.
|
|
||||||
This document will only supply you with some simple usage examples for how to
|
|
||||||
use <em>bjam</em> to build and test Boost.Threads. In addition, this document
|
|
||||||
will try and explain the build requirements so that users may create their own
|
|
||||||
build processes (for instance, create an IDE specific project), both for building
|
|
||||||
and testing Boost.Threads, as well as for building their own projects using
|
|
||||||
Boost.Threads. </p>
|
|
||||||
<h2><a name="topic1"></a>Building the Boost.Threads Libraries</h2>
|
|
||||||
<p>To build the Boost.Thread libraries using Boost.Build, simply change to the
|
|
||||||
directory <em>boost_root</em>/libs/thread/build and execute the command:</p>
|
|
||||||
<pre>bjam -sTOOLS=<em>toolset</em></pre>
|
|
||||||
<p>This will create four variants of the Boost.Threads library with the permuations
|
|
||||||
of debug/release and runtime-link-dynamic/runtime-link-static. <em><strong>Note:</strong></em>
|
|
||||||
Invoking the above command in <em>boost_root</em> will build all of the Boost
|
|
||||||
distribution, including Boost.Threads.</p>
|
|
||||||
<p>The Jamfile supplied with Boost.Threads produces a static library named <em>libboostthread</em>.
|
|
||||||
In addition, on Win32 platforms a <em>boostthreadmon.dll</em> and a coresponding
|
|
||||||
import library are created. The source files that are used to create the <em>libboostthread</em>
|
|
||||||
library are all of the *.cpp files found in <em>boost_root</em>/libs/thread/src,
|
|
||||||
except for <em>threadmon.cpp</em>. These need to be built with the compiler's
|
|
||||||
and linker's multi-threading support enabled. On Win32 platforms the <em>boostthreadmon.dll</em>
|
|
||||||
is created from <em>boost_root</em>/libs/thread/src/threadmon.cpp. This, too,
|
|
||||||
needs to be built with the compiler's and linker's multi-threading support enabled.
|
|
||||||
If you want to create your own build solution you'll have to follow these same
|
|
||||||
guidelines. One of the most frequently reported problems when trying to do this
|
|
||||||
occurs from not enabling the compiler's and linker's support for multi-threading.</p>
|
|
||||||
<h2><a name="topic2"></a>Testing the Boost.Threads Libraries</h2>
|
|
||||||
<p>To test the Boost.Threads libraries using Boost.Build, simply change to the
|
|
||||||
directory <em>boost_root</em>/libs/thread/test and execute the command:</p>
|
|
||||||
<pre><code>bjam -sTOOLS=<em>toolset</em> test</code></pre>
|
|
||||||
<p> </p>
|
|
||||||
<h2><a name="footnotes"></a>Footnotes</h2>
|
|
||||||
<dl>
|
|
||||||
<dt><a name="footnote1" class="footnote">(1)</a> {{text}}</dt>
|
|
||||||
<dt><a name="footnote2" class="footnote">(2)</a> {{text}}</dt>
|
|
||||||
</dl>
|
|
||||||
<hr>
|
|
||||||
<p>Revised
|
|
||||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
|
||||||
05 November, 2001
|
|
||||||
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
|
|
||||||
</p>
|
|
||||||
<p><i>© Copyright <a href="mailto:{{address}}">{{author}}</a>
|
|
||||||
2002. All Rights Reserved.</i></p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
58
doc/build.xml
Normal file
58
doc/build.xml
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
||||||
|
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
|
||||||
|
<!ENTITY % threads.entities SYSTEM "entities.xml">
|
||||||
|
%threads.entities;
|
||||||
|
]>
|
||||||
|
<section id="thread.build" last-revision="$Date$">
|
||||||
|
<title>Build</title>
|
||||||
|
<para>
|
||||||
|
How you build the &Boost.Threads; libraries, and how you build your own applications
|
||||||
|
that use those libraries, are some of the most frequently asked questions. Build
|
||||||
|
processes are difficult to deal with in a portable manner. That's one reason
|
||||||
|
why &Boost.Threads; makes use of &Boost.Build;.
|
||||||
|
In general you should refer to the documentation for &Boost.Build;.
|
||||||
|
This document will only supply you with some simple usage examples for how to
|
||||||
|
use <emphasis>bjam</emphasis> to build and test &Boost.Threads;. In addition, this document
|
||||||
|
will try to explain the build requirements so that users may create their own
|
||||||
|
build processes (for instance, create an IDE specific project), both for building
|
||||||
|
and testing &Boost.Threads;, as well as for building their own projects using
|
||||||
|
&Boost.Threads;.
|
||||||
|
</para>
|
||||||
|
<section id="thread.build.building">
|
||||||
|
<title>Building the &Boost.Threads; Libraries</title>
|
||||||
|
<para>
|
||||||
|
To build the &Boost.Threads; libraries using &Boost.Build;, simply change to the
|
||||||
|
directory <emphasis>boost_root</emphasis>/libs/thread/build and execute the command:
|
||||||
|
<programlisting>bjam -sTOOLS=<emphasis>toolset</emphasis></programlisting>
|
||||||
|
This will create the debug and the release builds of the &Boost.Threads; library.
|
||||||
|
<note>Invoking the above command in <emphasis>boost_root</emphasis> will build all of
|
||||||
|
the Boost distribution, including &Boost.Threads;.</note>
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
The Jamfile supplied with &Boost.Threads; produces a dynamic link library named
|
||||||
|
<emphasis>boost_thread{build-specific-tags}.{extension}</emphasis>, where the build-specific
|
||||||
|
tags indicate the toolset used to build the library, whether it's a debug or release
|
||||||
|
build, what version of Boost was used, etc.; and the extension is the appropriate extension
|
||||||
|
for a dynamic link library for the platform for which &Boost.Threads; is being built.
|
||||||
|
For instance, a debug library built for Win32 with VC++ 7.1 using Boost 1.31 would
|
||||||
|
be named <emphasis>boost_thread-vc71-mt-gd-1_31.dll</emphasis>.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
The source files that are used to create the &Boost.Threads; library
|
||||||
|
are all of the *.cpp files found in <emphasis>boost_root</emphasis>/libs/thread/src.
|
||||||
|
These need to be built with the compiler's and linker's multi-threading support enabled.
|
||||||
|
If you want to create your own build solution you'll have to follow these same
|
||||||
|
guidelines. One of the most frequently reported problems when trying to do this
|
||||||
|
occurs from not enabling the compiler's and linker's support for multi-threading.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
<section id="thread.build.testing">
|
||||||
|
<title>Testing the &Boost.Threads; Libraries</title>
|
||||||
|
<para>
|
||||||
|
To test the &Boost.Threads; libraries using &Boost.Build;, simply change to the
|
||||||
|
directory <emphasis>boost_root</emphasis>/libs/thread/test and execute the command:
|
||||||
|
<programlisting>bjam -sTOOLS=<emphasis>toolset</emphasis> test</programlisting>
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
2229
doc/concepts.xml
Normal file
2229
doc/concepts.xml
Normal file
File diff suppressed because it is too large
Load Diff
188
doc/condition-ref.xml
Normal file
188
doc/condition-ref.xml
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
||||||
|
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
|
||||||
|
<!ENTITY % threads.entities SYSTEM "entities.xml">
|
||||||
|
%threads.entities;
|
||||||
|
]>
|
||||||
|
<header name="boost/thread/condition.hpp"
|
||||||
|
last-revision="$Date$">
|
||||||
|
<namespace name="boost">
|
||||||
|
<class name="condition">
|
||||||
|
<inherit access="private">
|
||||||
|
<type><classname>boost::noncopyable</classname></type>
|
||||||
|
<purpose>Exposition only</purpose>
|
||||||
|
</inherit>
|
||||||
|
|
||||||
|
<purpose>
|
||||||
|
<para>An object of class <classname>condition</classname> is a
|
||||||
|
synchronization primitive used to cause a thread to wait until a
|
||||||
|
particular shared-data condition (or time) is met.</para>
|
||||||
|
</purpose>
|
||||||
|
|
||||||
|
<description>
|
||||||
|
<para>A <classname>condition</classname> object is always used in
|
||||||
|
conjunction with a <link linkend="threads.concepts.mutexes">mutex</link>
|
||||||
|
object (an object whose type is a model of a <link
|
||||||
|
linkend="threads.concepts.Mutex">Mutex</link> or one of its
|
||||||
|
refinements). The mutex object must be locked prior to waiting on the
|
||||||
|
condition, which is verified by passing a lock object (an object whose
|
||||||
|
type is a model of <link linkend="threads.concepts.Lock">Lock</link> or
|
||||||
|
one of its refinements) to the <classname>condition</classname> object's
|
||||||
|
wait functions. Upon blocking on the <classname>condition</classname>
|
||||||
|
object, the thread unlocks the mutex object. When the thread returns
|
||||||
|
from a call to one of the <classname>condition</classname> object's wait
|
||||||
|
functions the mutex object is again locked. The tricky unlock/lock
|
||||||
|
sequence is performed automatically by the
|
||||||
|
<classname>condition</classname> object's wait functions.</para>
|
||||||
|
<para>The <classname>condition</classname> type is often used to
|
||||||
|
implement the Monitor Object and other important patterns (see
|
||||||
|
&cite.SchmidtStalRohnertBuschmann; and &cite.Hoare74;). Monitors are one
|
||||||
|
of the most important patterns for creating reliable multithreaded
|
||||||
|
programs.</para>
|
||||||
|
<para>See <xref linkend="threads.glossary"/> for definitions of <link
|
||||||
|
linkend="threads.glossary.thread-state">thread states</link>
|
||||||
|
blocked and ready. Note that "waiting" is a synonym for blocked.</para>
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<constructor>
|
||||||
|
<effects><simpara>Constructs a <classname>condition</classname>
|
||||||
|
object.</simpara></effects>
|
||||||
|
</constructor>
|
||||||
|
|
||||||
|
<destructor>
|
||||||
|
<effects><simpara>Destroys <code>*this</code>.</simpara></effects>
|
||||||
|
</destructor>
|
||||||
|
|
||||||
|
<method-group name="notification">
|
||||||
|
<method name="notify_one">
|
||||||
|
<type>void</type>
|
||||||
|
<effects><simpara>If there is a thread waiting on <code>*this</code>,
|
||||||
|
change that thread's state to ready. Otherwise there is no
|
||||||
|
effect.</simpara></effects>
|
||||||
|
<notes><simpara>If more than one thread is waiting on <code>*this</code>,
|
||||||
|
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 <classname>condition</classname>
|
||||||
|
object's wait functions.)</simpara></notes>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="notify_all">
|
||||||
|
<type>void</type>
|
||||||
|
<effects><simpara>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.</simpara></effects>
|
||||||
|
</method>
|
||||||
|
</method-group>
|
||||||
|
|
||||||
|
<method-group name="waiting">
|
||||||
|
<method name="wait">
|
||||||
|
<template>
|
||||||
|
<template-type-parameter name="ScopedLock"/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<type>void</type>
|
||||||
|
|
||||||
|
<parameter name="lock">
|
||||||
|
<paramtype>ScopedLock&</paramtype>
|
||||||
|
</parameter>
|
||||||
|
|
||||||
|
<requires><simpara><code>ScopedLock</code> meets the <link
|
||||||
|
linkend="threads.concepts.ScopedLock">ScopedLock</link>
|
||||||
|
requirements.</simpara></requires>
|
||||||
|
<effects><simpara>Releases the lock on the <link
|
||||||
|
linkend="threads.concepts.mutexes">mutex object</link>
|
||||||
|
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.</simpara></effects>
|
||||||
|
<throws><simpara><classname>lock_error</classname> if
|
||||||
|
<code>!lock.locked()</code></simpara></throws>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="wait">
|
||||||
|
<template>
|
||||||
|
<template-type-parameter name="ScopedLock"/>
|
||||||
|
<template-type-parameter name="Pred"/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<type>void</type>
|
||||||
|
|
||||||
|
<parameter name="lock">
|
||||||
|
<paramtype>ScopedLock&</paramtype>
|
||||||
|
</parameter>
|
||||||
|
|
||||||
|
<parameter name="pred">
|
||||||
|
<paramtype>Pred</paramtype>
|
||||||
|
</parameter>
|
||||||
|
|
||||||
|
<requires><simpara><code>ScopedLock</code> meets the <link
|
||||||
|
linkend="threads.concepts.ScopedLock">ScopedLock</link>
|
||||||
|
requirements and the return from <code>pred()</code> is
|
||||||
|
convertible to <code>bool</code>.</simpara></requires>
|
||||||
|
<effects><simpara>As if: <code>while (!pred())
|
||||||
|
wait(lock)</code></simpara></effects>
|
||||||
|
<throws><simpara><classname>lock_error</classname> if
|
||||||
|
<code>!lock.locked()</code></simpara></throws>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="timed_wait">
|
||||||
|
<template>
|
||||||
|
<template-type-parameter name="ScopedLock"/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<type>bool</type>
|
||||||
|
|
||||||
|
<parameter name="lock">
|
||||||
|
<paramtype>ScopedLock&</paramtype>
|
||||||
|
</parameter>
|
||||||
|
|
||||||
|
<parameter name="xt">
|
||||||
|
<paramtype>const <classname>boost::xtime</classname>&</paramtype>
|
||||||
|
</parameter>
|
||||||
|
|
||||||
|
<requires><simpara><code>ScopedLock</code> meets the <link
|
||||||
|
linkend="threads.concepts.ScopedLock">ScopedLock</link>
|
||||||
|
requirements.</simpara></requires>
|
||||||
|
<effects><simpara>Releases the lock on the <link
|
||||||
|
linkend="threads.concepts.mutexes">mutex object</link>
|
||||||
|
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>, or until time <code>xt</code>
|
||||||
|
is reached, and then reacquires the lock.</simpara></effects>
|
||||||
|
<returns><simpara><code>false</code> if time <code>xt</code> is reached,
|
||||||
|
otherwise <code>true</code>.</simpara></returns>
|
||||||
|
<throws><simpara><classname>lock_error</classname> if
|
||||||
|
<code>!lock.locked()</code></simpara></throws>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="timed_wait">
|
||||||
|
<template>
|
||||||
|
<template-type-parameter name="ScopedLock"/>
|
||||||
|
<template-type-parameter name="Pred"/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<type>bool</type>
|
||||||
|
|
||||||
|
<parameter name="lock">
|
||||||
|
<paramtype>ScopedLock&</paramtype>
|
||||||
|
</parameter>
|
||||||
|
|
||||||
|
<parameter name="pred">
|
||||||
|
<paramtype>Pred</paramtype>
|
||||||
|
</parameter>
|
||||||
|
|
||||||
|
<requires><simpara><code>ScopedLock</code> meets the <link
|
||||||
|
linkend="threads.concepts.ScopedLock">ScopedLock</link>
|
||||||
|
requirements and the return from <code>pred()</code> is
|
||||||
|
convertible to <code>bool</code>.</simpara></requires>
|
||||||
|
<effects><simpara>As if: <code>while (!pred()) { if (!timed_wait(lock,
|
||||||
|
xt)) return false; } return true;</code></simpara></effects>
|
||||||
|
<returns><simpara><code>false</code> if <code>xt</code> is reached,
|
||||||
|
otherwise <code>true</code>.</simpara></returns>
|
||||||
|
<throws><simpara><classname>lock_error</classname> if
|
||||||
|
<code>!lock.locked()</code></simpara></throws>
|
||||||
|
</method>
|
||||||
|
</method-group>
|
||||||
|
</class>
|
||||||
|
</namespace>
|
||||||
|
</header>
|
||||||
@@ -1,225 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
|
||||||
<link rel="stylesheet" type="text/css" href="../../../boost.css">
|
|
||||||
<title>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>
|
|
||||||
<p><a href="../example/condition.cpp">libs/thread/example/condition.cpp</a></p>
|
|
||||||
<p>Typical output (dependent on scheduling policies) is:</p>
|
|
||||||
<pre>
|
|
||||||
sent: 0
|
|
||||||
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>
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
|
||||||
<link rel="stylesheet" type="text/css" href="../../../boost.css">
|
|
||||||
<title>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>
|
|
||||||
92
doc/configuration.xml
Normal file
92
doc/configuration.xml
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
||||||
|
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
|
||||||
|
<!ENTITY % threads.entities SYSTEM "entities.xml">
|
||||||
|
%threads.entities;
|
||||||
|
]>
|
||||||
|
<section id="thread.configuration" last-revision="$Date$">
|
||||||
|
<title>Configuration</title>
|
||||||
|
<para>&Boost.Threads; uses several configuration macros in <boost/config.hpp>,
|
||||||
|
as well as configuration macros meant to be supplied by the application. These
|
||||||
|
macros are documented here.
|
||||||
|
</para>
|
||||||
|
<section id="thread.configuration.public">
|
||||||
|
<title>Library Defined Public Macros</title>
|
||||||
|
<para>
|
||||||
|
These macros are defined by &Boost.Threads; but are expected to be used
|
||||||
|
by application code.
|
||||||
|
</para>
|
||||||
|
<informaltable>
|
||||||
|
<tgroup cols="2">
|
||||||
|
<thead>
|
||||||
|
<row>
|
||||||
|
<entry>Macro</entry>
|
||||||
|
<entry>Meaning</entry>
|
||||||
|
</row>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<row>
|
||||||
|
<entry>BOOST_HAS_THREADS</entry>
|
||||||
|
<entry>
|
||||||
|
Indicates that threading support is available. This means both that there
|
||||||
|
is a platform specific implementation for &Boost.Threads; and that
|
||||||
|
threading support has been enabled in a platform specific manner. For instance,
|
||||||
|
on the Win32 platform there's an implementation for &Boost.Threads;
|
||||||
|
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.
|
||||||
|
</entry>
|
||||||
|
</row>
|
||||||
|
</tbody>
|
||||||
|
</tgroup>
|
||||||
|
</informaltable>
|
||||||
|
</section>
|
||||||
|
<section id="thread.configuration.implementation">
|
||||||
|
<title>Library Defined Implementation Macros</title>
|
||||||
|
<para>
|
||||||
|
These macros are defined by &Boost.Threads; and are implementation details
|
||||||
|
of interest only to implementors.
|
||||||
|
</para>
|
||||||
|
<informaltable>
|
||||||
|
<tgroup cols="2">
|
||||||
|
<thead>
|
||||||
|
<row>
|
||||||
|
<entry>Macro</entry>
|
||||||
|
<entry>Meaning</entry>
|
||||||
|
</row>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<row>
|
||||||
|
<entry>BOOST_HAS_WINTHREADS</entry>
|
||||||
|
<entry>
|
||||||
|
Indicates that the platform has the Microsoft Win32 threading libraries,
|
||||||
|
and that they should be used to implement &Boost.Threads;.
|
||||||
|
</entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>BOOST_HAS_PTHREADS</entry>
|
||||||
|
<entry>
|
||||||
|
Indicates that the platform has the POSIX pthreads libraries, and that
|
||||||
|
they should be used to implement &Boost.Threads;.
|
||||||
|
</entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>BOOST_HAS_FTIME</entry>
|
||||||
|
<entry>
|
||||||
|
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().
|
||||||
|
</entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>BOOST_HAS_GETTTIMEOFDAY</entry>
|
||||||
|
<entry>
|
||||||
|
Indicates that the implementation should use gettimeofday() to calculate
|
||||||
|
the current time. This is an implementation detail used by boost::detail::getcurtime().
|
||||||
|
</entry>
|
||||||
|
</row>
|
||||||
|
</tbody>
|
||||||
|
</tgroup>
|
||||||
|
</informaltable>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
@@ -1,262 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
|
||||||
<link rel="stylesheet" type="text/css" href="../../../boost.css">
|
|
||||||
<title>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 was originally written by Beman Dawes, and then much improved by the incorporation of comments from
|
|
||||||
William Kempf, who now maintains the contents.</p>
|
|
||||||
<p>The visibility rules are based on <a href=
|
|
||||||
"bibliography.html#Butenhof-97">[Butenhof 97]</a>.</p>
|
|
||||||
<hr>
|
|
||||||
<p>Revised
|
|
||||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->06 October, 2002<!--webbot bot="Timestamp" endspan i-checksum="38429" -->
|
|
||||||
</p>
|
|
||||||
<p><i>© Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a> 2001-2002.
|
|
||||||
All Rights Reserved.<br>
|
|
||||||
</i>© Copyright Beman Dawes, 2001</p>
|
|
||||||
<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/design.xml
Normal file
155
doc/design.xml
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
||||||
|
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
|
||||||
|
<!ENTITY % threads.entities SYSTEM "entities.xml">
|
||||||
|
%threads.entities;
|
||||||
|
]>
|
||||||
|
<section id="threads.design" last-revision="$Date$">
|
||||||
|
<title>Design</title>
|
||||||
|
<para>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 concepts unique to C++, such as
|
||||||
|
exceptions.</para>
|
||||||
|
<para>The &Boost.Threads; library is an attempt to define a portable interface
|
||||||
|
for writing parallel processes in C++.</para>
|
||||||
|
<section id="threads.design.goals">
|
||||||
|
<title>Goals</title>
|
||||||
|
<para>The &Boost.Threads; 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.
|
||||||
|
<variablelist>
|
||||||
|
<varlistentry>
|
||||||
|
<term>Portability</term>
|
||||||
|
<listitem>
|
||||||
|
<para>&Boost.Threads; 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.</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term>Safety</term>
|
||||||
|
<listitem>
|
||||||
|
<para>&Boost.Threads; was designed to be as safe as possible. Writing
|
||||||
|
<link linkend="threads.glossary.thread-safe">thread-safe</link>
|
||||||
|
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:
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem>
|
||||||
|
<para>C++ language features are used to make correct usage easy
|
||||||
|
(if possible) and error-prone usage impossible or at least more
|
||||||
|
difficult. For example, see the <link
|
||||||
|
linkend="threads.concepts.Mutex">Mutex</link> and <link
|
||||||
|
linkend="threads.concepts.Lock">Lock</link> designs, and note
|
||||||
|
how they interact.</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>Certain traditional concurrent programming features are
|
||||||
|
considered so error-prone that they are not provided at all. For
|
||||||
|
example, see <xref linkend="threads.rationale.events" />.</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>Dangerous features, or features which may be misused, are
|
||||||
|
identified as such in the documentation to make users aware of
|
||||||
|
potential pitfalls.</para>
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist></para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term>Flexibility</term>
|
||||||
|
<listitem>
|
||||||
|
<para>&Boost.Threads; was designed to be flexible. This goal is often
|
||||||
|
at odds with <emphasis>safety</emphasis>. When functionality might be
|
||||||
|
compromised by the desire to keep the interface safe, &Boost.Threads;
|
||||||
|
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.</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term>Efficiency</term>
|
||||||
|
<listitem>
|
||||||
|
<para>&Boost.Threads; 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. &Boost.Threads; 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 <emphasis>safety</emphasis>. Every
|
||||||
|
effort was made to ensure efficient implementations, but when in
|
||||||
|
conflict <emphasis>safety</emphasis> has always taken
|
||||||
|
precedence.</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
</variablelist></para>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<title>Iterative Phases</title>
|
||||||
|
<para>Another goal of &Boost.Threads; 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 it is very difficult to use them safely or to provide formal
|
||||||
|
proofs for constructs built on top of them. There has been a lot of research
|
||||||
|
into other concepts, such as in "Communicating Sequential Processes."
|
||||||
|
&Boost.Threads; was designed in iterative steps, with each step providing
|
||||||
|
the building blocks necessary for the next step and giving the researcher
|
||||||
|
the tools necessary to explore new concepts in a portable manner.</para>
|
||||||
|
<para>Given the goal of following a dynamic, iterative approach
|
||||||
|
&Boost.Threads; shall go through several growth cycles. Each phase in its
|
||||||
|
development shall be roughly documented here.</para>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<title>Phase 1, Synchronization Primitives</title>
|
||||||
|
<para>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 therefore 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 <link
|
||||||
|
linkend="threads.glossary.thread-safe">thread-safe</link>
|
||||||
|
implementations. This need far out weighs the need for portable methods to
|
||||||
|
create and manage threads.</para>
|
||||||
|
<para>Because of this need, the first phase of &Boost.Threads; focuses
|
||||||
|
solely on providing portable primitive concepts for thread
|
||||||
|
synchronization. Types provided in this phase include the
|
||||||
|
<classname>boost::mutex</classname>,
|
||||||
|
<classname>boost::try_mutex</classname>,
|
||||||
|
<classname>boost::timed_mutex</classname>,
|
||||||
|
<classname>boost::recursive_mutex</classname>,
|
||||||
|
<classname>boost::recursive_try_mutex</classname>,
|
||||||
|
<classname>boost::recursive_timed_mutex</classname>, and
|
||||||
|
<classname>boost::lock_error</classname>. These are considered the "core"
|
||||||
|
synchronization primitives, though there are others that will be added in
|
||||||
|
later phases.</para>
|
||||||
|
</section>
|
||||||
|
<section id="threads.design.phase2">
|
||||||
|
<title>Phase 2, Thread Management and Thread Specific Storage</title>
|
||||||
|
<para>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 &Boost.Threads; adds the <classname>boost::thread</classname> and
|
||||||
|
<classname>boost::thread_specific_ptr</classname> types. With these
|
||||||
|
additions the &Boost.Threads; library can be considered minimal but
|
||||||
|
complete.</para>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<title>The Next Phase</title>
|
||||||
|
<para>The next phase will address more advanced synchronization concepts,
|
||||||
|
such as read/write mutexes and barriers.</para>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
26
doc/entities.xml
Normal file
26
doc/entities.xml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<!ENTITY Boost.Threads "<emphasis role='bold'>Boost.Threads</emphasis>">
|
||||||
|
<!ENTITY Boost.Build "<emphasis role='bold'>Boost.Build</emphasis>">
|
||||||
|
<!ENTITY cite.AndrewsSchneider83 "<citation><xref
|
||||||
|
linkend='threads.bib.AndrewsSchneider83'
|
||||||
|
endterm='threads.bib.AndrewsSchneider83.abbrev'/></citation>">
|
||||||
|
<!ENTITY cite.Boost "<citation><xref linkend='threads.bib.Boost'
|
||||||
|
endterm='threads.bib.Boost.abbrev'/></citation>">
|
||||||
|
<!ENTITY cite.Hansen73 "<citation><xref linkend='threads.bib.Hansen73'
|
||||||
|
endterm='threads.bib.Hansen73.abbrev'/></citation>">
|
||||||
|
<!ENTITY cite.Butenhof97 "<citation><xref linkend='threads.bib.Butenhof97'
|
||||||
|
endterm='threads.bib.Butenhof97.abbrev'/></citation>">
|
||||||
|
<!ENTITY cite.Hoare74 "<citation><xref linkend='threads.bib.Hoare74'
|
||||||
|
endterm='threads.bib.Hoare74.abbrev'/></citation>">
|
||||||
|
<!ENTITY cite.ISO98 "<citation><xref linkend='threads.bib.ISO98'
|
||||||
|
endterm='threads.bib.ISO98.abbrev'/></citation>">
|
||||||
|
<!ENTITY cite.McDowellHelmbold89 "<citation><xref
|
||||||
|
linkend='threads.bib.McDowellHelmbold89'
|
||||||
|
endterm='threads.bib.McDowellHelmbold89.abbrev'/></citation>">
|
||||||
|
<!ENTITY cite.SchmidtPyarali "<citation><xref
|
||||||
|
linkend='threads.bib.SchmidtPyarali'
|
||||||
|
endterm='threads.bib.SchmidtPyarali.abbrev'/></citation>">
|
||||||
|
<!ENTITY cite.SchmidtStalRohnertBuschmann "<citation><xref
|
||||||
|
linkend='threads.bib.SchmidtStalRohnertBuschmann'
|
||||||
|
endterm='threads.bib.SchmidtStalRohnertBuschmann.abbrev'/></citation>">
|
||||||
|
<!ENTITY cite.Stroustrup "<citation><xref linkend='threads.bib.Stroustrup'
|
||||||
|
endterm='threads.bib.Stroustrup.abbrev'/></citation>">
|
||||||
58
doc/exceptions-ref.xml
Normal file
58
doc/exceptions-ref.xml
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
||||||
|
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
|
||||||
|
<!ENTITY % threads.entities SYSTEM "entities.xml">
|
||||||
|
%threads.entities;
|
||||||
|
]>
|
||||||
|
<header name="boost/thread/exceptions.hpp"
|
||||||
|
last-revision="$Date$">
|
||||||
|
<namespace name="boost">
|
||||||
|
<class name="lock_error">
|
||||||
|
<purpose>
|
||||||
|
<simpara>The lock_error class defines an exception type thrown
|
||||||
|
to indicate a locking related error has been detected.</simpara>
|
||||||
|
</purpose>
|
||||||
|
|
||||||
|
<description>
|
||||||
|
<simpara>Examples of errors indicated by a lock_error exception
|
||||||
|
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.</simpara>
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<inherit access="public">
|
||||||
|
<type><classname>std::logical_error</classname></type>
|
||||||
|
</inherit>
|
||||||
|
|
||||||
|
<constructor>
|
||||||
|
<effects><simpara>Constructs a <code>lock_error</code> object.
|
||||||
|
</simpara></effects>
|
||||||
|
</constructor>
|
||||||
|
</class>
|
||||||
|
|
||||||
|
<class name="thread_resource_error">
|
||||||
|
<purpose>
|
||||||
|
<simpara>The <classname>thread_resource_error</classname> class
|
||||||
|
defines an exception type that is thrown by constructors in the
|
||||||
|
&Boost.Threads; library when thread-related resources can not be
|
||||||
|
acquired.</simpara>
|
||||||
|
</purpose>
|
||||||
|
|
||||||
|
<description>
|
||||||
|
<simpara><classname>thread_resource_error</classname> is used
|
||||||
|
only when thread-related resources cannot be acquired; memory
|
||||||
|
allocation failures are indicated by
|
||||||
|
<classname>std::bad_alloc</classname>.</simpara>
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<inherit access="public">
|
||||||
|
<type><classname>std::runtime_error</classname></type>
|
||||||
|
</inherit>
|
||||||
|
|
||||||
|
<constructor>
|
||||||
|
<effects><simpara>Constructs a <code>thread_resource_error</code>
|
||||||
|
object.</simpara></effects>
|
||||||
|
</constructor>
|
||||||
|
</class>
|
||||||
|
</namespace>
|
||||||
|
</header>
|
||||||
@@ -1,110 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
|
||||||
<link rel="stylesheet" type="text/css" href="../../../boost.css">
|
|
||||||
<title>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
183
doc/faq.html
@@ -1,183 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
|
||||||
<link rel="stylesheet" type="text/css" href="../../../boost.css">
|
|
||||||
<title>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>
|
|
||||||
210
doc/faq.xml
Normal file
210
doc/faq.xml
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
||||||
|
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
|
||||||
|
<!ENTITY % threads.entities SYSTEM "entities.xml">
|
||||||
|
%threads.entities;
|
||||||
|
]>
|
||||||
|
<section id="threads.faq" last-revision="$Date$">
|
||||||
|
<title>Frequently Asked Questions</title>
|
||||||
|
<qandaset>
|
||||||
|
<qandaentry>
|
||||||
|
<question>
|
||||||
|
<para>Are lock objects <link
|
||||||
|
linkend="threads.glossary.thread-safe">thread safe</link>?</para>
|
||||||
|
</question>
|
||||||
|
<answer>
|
||||||
|
<para><emphasis role="bold">No!</emphasis> 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 anyway.
|
||||||
|
Share <link linkend="threads.concepts.mutexes">Mutexes</link>, not
|
||||||
|
Locks. For more information see the <link
|
||||||
|
linkend="threads.rationale.locks">rationale</link> behind the
|
||||||
|
design for lock objects.</para>
|
||||||
|
</answer>
|
||||||
|
</qandaentry>
|
||||||
|
<qandaentry>
|
||||||
|
<question>
|
||||||
|
<para>Why was &Boost.Threads; modeled after (specific library
|
||||||
|
name)?</para>
|
||||||
|
</question>
|
||||||
|
<answer>
|
||||||
|
<para>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.</para>
|
||||||
|
</answer>
|
||||||
|
</qandaentry>
|
||||||
|
<qandaentry>
|
||||||
|
<question>
|
||||||
|
<para>Why wasn't &Boost.Threads; modeled after (specific library
|
||||||
|
name)?</para>
|
||||||
|
</question>
|
||||||
|
<answer>
|
||||||
|
<para>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 &cite.SchmidtStalRohnertBuschmann;.</para>
|
||||||
|
</answer>
|
||||||
|
</qandaentry>
|
||||||
|
<qandaentry>
|
||||||
|
<question>
|
||||||
|
<para>Why do <link linkend="threads.concepts.mutexes">Mutexes</link>
|
||||||
|
have noncopyable semantics?</para>
|
||||||
|
</question>
|
||||||
|
<answer>
|
||||||
|
<para>To ensure that <link
|
||||||
|
linkend="threads.glossary.deadlock">deadlocks</link> 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).</para>
|
||||||
|
</answer>
|
||||||
|
</qandaentry>
|
||||||
|
<qandaentry>
|
||||||
|
<question>
|
||||||
|
<para>How can you prevent <link
|
||||||
|
linkend="threads.glossary.deadlock">deadlock</link> from occurring when
|
||||||
|
a thread must lock multiple mutexes?</para>
|
||||||
|
</question>
|
||||||
|
<answer>
|
||||||
|
<para>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.</para>
|
||||||
|
</answer>
|
||||||
|
</qandaentry>
|
||||||
|
<qandaentry>
|
||||||
|
<question>
|
||||||
|
<para>Don't noncopyable <link
|
||||||
|
linkend="threads.concepts.mutexes">Mutex</link> semantics mean that a
|
||||||
|
class with a mutex member will be noncopyable as well?</para>
|
||||||
|
</question>
|
||||||
|
<answer>
|
||||||
|
<para>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 <emphasis role="bold">good thing</emphasis>,
|
||||||
|
however, since the compiler generated operations would not be <link
|
||||||
|
linkend="threads.glossary.thread-safe">thread-safe</link>. The following
|
||||||
|
is a simple example of a class with copyable semantics and internal
|
||||||
|
synchronization through a mutex member.</para>
|
||||||
|
<programlisting>
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
</programlisting>
|
||||||
|
</answer>
|
||||||
|
</qandaentry>
|
||||||
|
<qandaentry>
|
||||||
|
<question>
|
||||||
|
<para>How can you lock a <link
|
||||||
|
linkend="threads.concepts.mutexes">Mutex</link> member in a const member
|
||||||
|
function, in order to implement the Monitor Pattern?</para>
|
||||||
|
</question>
|
||||||
|
<answer>
|
||||||
|
<para>The Monitor Pattern &cite.SchmidtStalRohnertBuschmann; mutex
|
||||||
|
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.</para>
|
||||||
|
</answer>
|
||||||
|
</qandaentry>
|
||||||
|
<qandaentry>
|
||||||
|
<question>
|
||||||
|
<para>Why supply <classname>boost::condition</classname> variables rather than
|
||||||
|
event variables?</para>
|
||||||
|
</question>
|
||||||
|
<answer>
|
||||||
|
<para>Condition variables result in user code much less prone to <link
|
||||||
|
linkend="threads.glossary.race-condition">race conditions</link> than
|
||||||
|
event variables. See <xref linkend="threads.rationale.events" />
|
||||||
|
for analysis. Also see &cite.Hoare74; and &cite.SchmidtStalRohnertBuschmann;.
|
||||||
|
</para>
|
||||||
|
</answer>
|
||||||
|
</qandaentry>
|
||||||
|
<qandaentry>
|
||||||
|
<question>
|
||||||
|
<para>Why isn't thread cancellation or termination provided?</para>
|
||||||
|
</question>
|
||||||
|
<answer>
|
||||||
|
<para>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.</para>
|
||||||
|
</answer>
|
||||||
|
</qandaentry>
|
||||||
|
<qandaentry>
|
||||||
|
<question>
|
||||||
|
<para>Is it safe for threads to share automatic storage duration (stack)
|
||||||
|
objects via pointers or references?</para>
|
||||||
|
</question>
|
||||||
|
<answer>
|
||||||
|
<para>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).</para>
|
||||||
|
</answer>
|
||||||
|
</qandaentry>
|
||||||
|
<qandaentry>
|
||||||
|
<question>
|
||||||
|
<para>Why has class semaphore disappeared?</para>
|
||||||
|
</question>
|
||||||
|
<answer>
|
||||||
|
<para>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.</para>
|
||||||
|
</answer>
|
||||||
|
</qandaentry>
|
||||||
|
</qandaset>
|
||||||
|
</section>
|
||||||
300
doc/glossary.xml
Normal file
300
doc/glossary.xml
Normal file
@@ -0,0 +1,300 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
||||||
|
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
|
||||||
|
<!ENTITY % threads.entities SYSTEM "entities.xml">
|
||||||
|
%threads.entities;
|
||||||
|
]>
|
||||||
|
<glossary id="threads.glossary" last-revision="$Date$">
|
||||||
|
<title>Glossary</title>
|
||||||
|
<para>Definitions are given in terms of the C++ Standard
|
||||||
|
&cite.ISO98;. References to the standard are in the form [1.2.3/4], which
|
||||||
|
represents the section number, with the paragraph number following the
|
||||||
|
"/".</para>
|
||||||
|
<para>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.</para>
|
||||||
|
<glossentry id="threads.glossary.thread">
|
||||||
|
<glossterm>Thread</glossterm>
|
||||||
|
<glossdef>
|
||||||
|
<para>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.</para>
|
||||||
|
<para>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:</para>
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem><para>Static storage duration (static, extern) objects
|
||||||
|
[3.7.1].</para></listitem>
|
||||||
|
<listitem><para>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.</para></listitem>
|
||||||
|
<listitem><para>Automatic storage duration (stack) objects [3.7.2]
|
||||||
|
accessed via pointer or reference from another thread.</para></listitem>
|
||||||
|
<listitem><para>Resources provided by the operating system. For example,
|
||||||
|
files.</para></listitem>
|
||||||
|
<listitem><para>The program itself. In other words, each thread is
|
||||||
|
executing some function of the same program, not a totally different
|
||||||
|
program.</para></listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
<para>Each thread has its own:</para>
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem><para>Registers and current execution sequence (program
|
||||||
|
counter) [1.9/5].</para></listitem>
|
||||||
|
<listitem><para>Automatic storage duration (stack) objects
|
||||||
|
[3.7.2].</para></listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
</glossdef>
|
||||||
|
</glossentry>
|
||||||
|
<glossentry id="threads.glossary.thread-safe">
|
||||||
|
<glossterm>Thread-safe</glossterm>
|
||||||
|
<glossdef>
|
||||||
|
<para>A program is thread-safe if it has no <link
|
||||||
|
linkend="threads.glossary.race-condition">race conditions</link>, does
|
||||||
|
not <link linkend="threads.glossary.deadlock">deadlock</link>, and has
|
||||||
|
no <link linkend="threads.glossary.priority-failure">priority
|
||||||
|
failures</link>.</para>
|
||||||
|
<para>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.</para>
|
||||||
|
</glossdef>
|
||||||
|
</glossentry>
|
||||||
|
<glossentry id="threads.glossary.thread-state">
|
||||||
|
<glossterm>Thread State</glossterm>
|
||||||
|
<glossdef>
|
||||||
|
<para>During the lifetime of a thread, it shall be in one of the following
|
||||||
|
states:</para>
|
||||||
|
<table>
|
||||||
|
<title>Thread States</title>
|
||||||
|
<tgroup cols="2" align="left">
|
||||||
|
<thead>
|
||||||
|
<row>
|
||||||
|
<entry>State</entry>
|
||||||
|
<entry>Description</entry>
|
||||||
|
</row>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<row>
|
||||||
|
<entry>Ready</entry>
|
||||||
|
<entry>Ready to run, but waiting for a processor.</entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>Running</entry>
|
||||||
|
<entry>Currently executing on a processor. Zero or more threads
|
||||||
|
may be running at any time, with a maximum equal to the number of
|
||||||
|
processors.</entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>Blocked</entry>
|
||||||
|
<entry>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 with
|
||||||
|
"blocked"</entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>Terminated</entry>
|
||||||
|
<entry>Finished execution but not yet detached or joined.</entry>
|
||||||
|
</row>
|
||||||
|
</tbody>
|
||||||
|
</tgroup>
|
||||||
|
</table>
|
||||||
|
<para>Thread state transitions shall occur only as specified:</para>
|
||||||
|
<table>
|
||||||
|
<title>Thread States Transitions</title>
|
||||||
|
<tgroup cols="3" align="left">
|
||||||
|
<thead>
|
||||||
|
<row>
|
||||||
|
<entry>From</entry>
|
||||||
|
<entry>To</entry>
|
||||||
|
<entry>Cause</entry>
|
||||||
|
</row>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<row>
|
||||||
|
<entry>[none]</entry>
|
||||||
|
<entry>Ready</entry>
|
||||||
|
<entry><para>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].</para></entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>Ready</entry>
|
||||||
|
<entry>Running</entry>
|
||||||
|
<entry><para>Processor becomes available.</para></entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>Running</entry>
|
||||||
|
<entry>Ready</entry>
|
||||||
|
<entry>Thread preempted.</entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>Running</entry>
|
||||||
|
<entry>Blocked</entry>
|
||||||
|
<entry>Thread calls a library function which waits for a resource or
|
||||||
|
for the completion of I/O.</entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>Running</entry>
|
||||||
|
<entry>Terminated</entry>
|
||||||
|
<entry>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.</entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>Blocked</entry>
|
||||||
|
<entry>Ready</entry>
|
||||||
|
<entry>The resource being waited for becomes available, or the
|
||||||
|
blocking library function completes.</entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>Terminated</entry>
|
||||||
|
<entry>[none]</entry>
|
||||||
|
<entry>Thread is detached or joined by some other thread calling the
|
||||||
|
appropriate library function, or by program termination
|
||||||
|
[3.6.3].</entry>
|
||||||
|
</row>
|
||||||
|
</tbody>
|
||||||
|
</tgroup>
|
||||||
|
</table>
|
||||||
|
<para>[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.]</para>
|
||||||
|
</glossdef>
|
||||||
|
</glossentry>
|
||||||
|
<glossentry id="threads.glossary.race-condition">
|
||||||
|
<glossterm>Race Condition</glossterm>
|
||||||
|
<glossdef>
|
||||||
|
<para>A race condition is what occurs when multiple threads read from 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].</para>
|
||||||
|
<para>Race conditions can be prevented by serializing memory access using
|
||||||
|
the tools provided by &Boost.Threads;.</para>
|
||||||
|
</glossdef>
|
||||||
|
</glossentry>
|
||||||
|
<glossentry id="threads.glossary.deadlock">
|
||||||
|
<glossterm>Deadlock</glossterm>
|
||||||
|
<glossdef>
|
||||||
|
<para>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.</para>
|
||||||
|
</glossdef>
|
||||||
|
</glossentry>
|
||||||
|
<glossentry id="threads.glossary.starvation">
|
||||||
|
<glossterm>Starvation</glossterm>
|
||||||
|
<glossdef>
|
||||||
|
<para>The condition in which a thread is not making sufficient progress in
|
||||||
|
its work during a given time interval.</para>
|
||||||
|
</glossdef>
|
||||||
|
</glossentry>
|
||||||
|
<glossentry id="threads.glossary.priority-failure">
|
||||||
|
<glossterm>Priority Failure</glossterm>
|
||||||
|
<glossdef>
|
||||||
|
<para>A priority failure (such as priority inversion or infinite overtaking)
|
||||||
|
occurs when threads are executed in such a sequence that required work is not
|
||||||
|
performed in time to be useful.</para>
|
||||||
|
</glossdef>
|
||||||
|
</glossentry>
|
||||||
|
<glossentry id="threads.glossary.undefined-behavior">
|
||||||
|
<glossterm>Undefined Behavior</glossterm>
|
||||||
|
<glossdef>
|
||||||
|
<para>The result of certain operations in &Boost.Threads; is undefined;
|
||||||
|
this means that those operations can invoke almost any behavior when
|
||||||
|
they are executed.</para>
|
||||||
|
|
||||||
|
<para>An operation whose behavior is undefined can work "correctly"
|
||||||
|
in some implementations (i.e., do what the programmer thought it
|
||||||
|
would do), while in other implementations it may exhibit almost
|
||||||
|
any "incorrect" behavior--such as returning an invalid value,
|
||||||
|
throwing an exception, generating an access violation, or terminating
|
||||||
|
the process.</para>
|
||||||
|
|
||||||
|
<para>Executing a statement whose behavior is undefined is a
|
||||||
|
programming error.</para>
|
||||||
|
</glossdef>
|
||||||
|
</glossentry>
|
||||||
|
<glossentry id="threads.glossary.memory-visibility">
|
||||||
|
<glossterm>Memory Visibility</glossterm>
|
||||||
|
<glossdef>
|
||||||
|
<para>An address [1.7] shall always point to the same memory byte,
|
||||||
|
regardless of the thread or processor dereferencing the address.</para>
|
||||||
|
<para>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.</para>
|
||||||
|
<para>For an object accessible from multiple threads, the value of the
|
||||||
|
object accessed from one thread may be indeterminate or different from 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].</para>
|
||||||
|
<table>
|
||||||
|
<title>Memory Visibility</title>
|
||||||
|
<tgroup cols="2">
|
||||||
|
<thead>
|
||||||
|
<row>
|
||||||
|
<entry>Thread A</entry>
|
||||||
|
<entry>Thread B</entry>
|
||||||
|
</row>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<row>
|
||||||
|
<entry>The sequence point at a call to a library thread-creation
|
||||||
|
function.</entry>
|
||||||
|
<entry>The first sequence point of the initial function in the new
|
||||||
|
thread created by the Thread A call.</entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>The sequence point at a call to a library function which
|
||||||
|
locks a mutex, directly or by waiting for a condition
|
||||||
|
variable.</entry>
|
||||||
|
<entry>The sequence point after a call to a library function which
|
||||||
|
unlocks the same mutex.</entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>The last sequence point before thread termination.</entry>
|
||||||
|
<entry>The sequence point after a call to a library function which
|
||||||
|
joins the terminated thread.</entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>The sequence point at a call to a library function which
|
||||||
|
signals or broadcasts a condition variable.</entry>
|
||||||
|
<entry>The sequence point after the call to the library function
|
||||||
|
which was waiting on that same condition variable or signal.</entry>
|
||||||
|
</row>
|
||||||
|
</tbody>
|
||||||
|
</tgroup>
|
||||||
|
</table>
|
||||||
|
<para>The architecture of the execution environment and the observable
|
||||||
|
behavior of the abstract machine [1.9] shall be the same on all
|
||||||
|
processors.</para>
|
||||||
|
<para>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.</para>
|
||||||
|
<para>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.</para>
|
||||||
|
</glossdef>
|
||||||
|
</glossentry>
|
||||||
|
<section>
|
||||||
|
<title>Acknowledgements</title>
|
||||||
|
<para>This document was originally written by Beman Dawes, and then much
|
||||||
|
improved by the incorporation of comments from William Kempf, who now
|
||||||
|
maintains the contents.</para>
|
||||||
|
<para>The visibility rules are based on &cite.Butenhof97;.</para>
|
||||||
|
</section>
|
||||||
|
</glossary>
|
||||||
34
doc/implementation_notes.xml
Normal file
34
doc/implementation_notes.xml
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
||||||
|
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
|
||||||
|
<!ENTITY % threads.entities SYSTEM "entities.xml">
|
||||||
|
%threads.entities;
|
||||||
|
]>
|
||||||
|
<section id="threads.implementation_notes" last-revision="$Date$">
|
||||||
|
<title>Implementation Notes</title>
|
||||||
|
<section id="threads.implementation_notes.win32">
|
||||||
|
<title>Win32</title>
|
||||||
|
<para>
|
||||||
|
In the current Win32 implementation, creating a boost::thread object
|
||||||
|
during dll initialization will result in deadlock because the thread
|
||||||
|
class constructor causes the current thread to wait on the thread that
|
||||||
|
is being created until it signals that it has finished its initialization,
|
||||||
|
and, as stated in the
|
||||||
|
<ulink url="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/dllmain.asp">MSDN Library, "DllMain" article, "Remarks" section</ulink>,
|
||||||
|
"Because DLL notifications are serialized, entry-point functions should not
|
||||||
|
attempt to communicate with other threads or processes. Deadlocks may occur as a result."
|
||||||
|
(Also see <ulink url="http://www.microsoft.com/msj/archive/S220.aspx">"Under the Hood", January 1996</ulink>
|
||||||
|
for a more detailed discussion of this issue).
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
The following non-exhaustive list details some of the situations that
|
||||||
|
should be avoided until this issue can be addressed:
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem>Creating a boost::thread object in DllMain() or in any function called by it.</listitem>
|
||||||
|
<listitem>Creating a boost::thread object in the constructor of a global static object or in any function called by one.</listitem>
|
||||||
|
<listitem>Creating a boost::thread object in MFC's CWinApp::InitInstance() function or in any function called by it.</listitem>
|
||||||
|
<listitem>Creating a boost::thread object in the function pointed to by MFC's _pRawDllMain function pointer or in any function called by it.</listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
156
doc/index.html
156
doc/index.html
@@ -1,156 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
|
||||||
<link rel="stylesheet" type="text/css" href="../../../boost.css">
|
|
||||||
<title>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="build.html">Building and Testing</a></dt>
|
|
||||||
<dt><a href="introduction.html">Introduction to Design</a></dt>
|
|
||||||
<dt><a href="rationale.html">Rationale</a></dt>
|
|
||||||
<dt><a href="definitions.html">Definitions</a></dt>
|
|
||||||
<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>
|
|
||||||
@@ -1,159 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
|
||||||
<link rel="stylesheet" type="text/css" href="../../../boost.css">
|
|
||||||
<title>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>
|
|
||||||
@@ -1,194 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
|
||||||
<link rel="stylesheet" type="text/css" href="../../../boost.css">
|
|
||||||
<title>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>
|
|
||||||
308
doc/mutex-ref.xml
Normal file
308
doc/mutex-ref.xml
Normal file
@@ -0,0 +1,308 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
||||||
|
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
|
||||||
|
<!ENTITY % threads.entities SYSTEM "entities.xml">
|
||||||
|
%threads.entities;
|
||||||
|
]>
|
||||||
|
<header name="boost/thread/mutex.hpp"
|
||||||
|
last-revision="$Date$">
|
||||||
|
<namespace name="boost">
|
||||||
|
<class name="mutex">
|
||||||
|
<purpose>
|
||||||
|
<para>The <classname>mutex</classname> class is a model of the
|
||||||
|
<link linkend="threads.concepts.Mutex">Mutex</link> concept.</para>
|
||||||
|
</purpose>
|
||||||
|
|
||||||
|
<description>
|
||||||
|
<para>The <classname>mutex</classname> class is a model of the
|
||||||
|
<link linkend="threads.concepts.Mutex">Mutex</link> concept.
|
||||||
|
It should be used to synchronize access to shared resources using
|
||||||
|
<link linkend="threads.concepts.unspecified-locking-strategy">Unspecified</link>
|
||||||
|
locking mechanics.</para>
|
||||||
|
|
||||||
|
<para>For classes that model related mutex concepts, see
|
||||||
|
<classname>try_mutex</classname> and <classname>timed_mutex</classname>.</para>
|
||||||
|
|
||||||
|
<para>For <link linkend="threads.concepts.recursive-locking-strategy">Recursive</link>
|
||||||
|
locking mechanics, see <classname>recursive_mutex</classname>,
|
||||||
|
<classname>recursive_try_mutex</classname>, and <classname>recursive_timed_mutex</classname>.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>The <classname>mutex</classname> class supplies the following typedef,
|
||||||
|
which <link linkend="threads.concepts.lock-models">models</link>
|
||||||
|
the specified locking strategy:
|
||||||
|
|
||||||
|
<informaltable>
|
||||||
|
<title>Supported Lock Types</title>
|
||||||
|
<tgroup cols="2" align="left">
|
||||||
|
<thead>
|
||||||
|
<row>
|
||||||
|
<entry>Lock Name</entry>
|
||||||
|
<entry>Lock Concept</entry>
|
||||||
|
</row>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<row>
|
||||||
|
<entry>scoped_lock</entry>
|
||||||
|
<entry><link linkend="threads.concepts.ScopedLock">ScopedLock</link></entry>
|
||||||
|
</row>
|
||||||
|
</tbody>
|
||||||
|
</tgroup>
|
||||||
|
</informaltable>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>The <classname>mutex</classname> class uses an
|
||||||
|
<link linkend="threads.concepts.unspecified-locking-strategy">Unspecified</link>
|
||||||
|
locking strategy, so attempts to recursively lock a <classname>mutex</classname>
|
||||||
|
object or attempts to unlock one by threads that don't own a lock on it result in
|
||||||
|
<emphasis role="bold">undefined behavior</emphasis>.
|
||||||
|
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.</para>
|
||||||
|
|
||||||
|
<para>Like all
|
||||||
|
<link linkend="threads.concepts.mutex-models">mutex models</link>
|
||||||
|
in &Boost.Threads;, <classname>mutex</classname> leaves the
|
||||||
|
<link linkend="threads.concepts.sheduling-policies">scheduling policy</link>
|
||||||
|
as <link linkend="threads.concepts.unspecified-scheduling-policy">Unspecified</link>.
|
||||||
|
Programmers should make no assumptions about the order in which
|
||||||
|
waiting threads acquire a lock.</para>
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<inherit access="private">
|
||||||
|
<type><classname>boost::noncopyable</classname></type>
|
||||||
|
<purpose>Exposition only</purpose>
|
||||||
|
</inherit>
|
||||||
|
|
||||||
|
<typedef name="scoped_lock">
|
||||||
|
<type><emphasis>implementation-defined</emphasis></type>
|
||||||
|
</typedef>
|
||||||
|
|
||||||
|
<constructor>
|
||||||
|
<effects>Constructs a <classname>mutex</classname> object.
|
||||||
|
</effects>
|
||||||
|
|
||||||
|
<postconditions><code>*this</code> is in an unlocked state.
|
||||||
|
</postconditions>
|
||||||
|
</constructor>
|
||||||
|
|
||||||
|
<destructor>
|
||||||
|
<effects>Destroys a <classname>mutex</classname> object.</effects>
|
||||||
|
|
||||||
|
<requires><code>*this</code> is in an unlocked state.</requires>
|
||||||
|
|
||||||
|
<notes><emphasis role="bold">Danger:</emphasis> Destruction of a
|
||||||
|
locked mutex is a serious programming error resulting in undefined
|
||||||
|
behavior such as a program crash.</notes>
|
||||||
|
</destructor>
|
||||||
|
</class>
|
||||||
|
|
||||||
|
<class name="try_mutex">
|
||||||
|
<purpose>
|
||||||
|
<para>The <classname>try_mutex</classname> class is a model of the
|
||||||
|
<link linkend="threads.concepts.TryMutex">TryMutex</link> concept.</para>
|
||||||
|
</purpose>
|
||||||
|
|
||||||
|
<description>
|
||||||
|
<para>The <classname>try_mutex</classname> class is a model of the
|
||||||
|
<link linkend="threads.concepts.TryMutex">TryMutex</link> concept.
|
||||||
|
It should be used to synchronize access to shared resources using
|
||||||
|
<link linkend="threads.concepts.unspecified-locking-strategy">Unspecified</link>
|
||||||
|
locking mechanics.</para>
|
||||||
|
|
||||||
|
<para>For classes that model related mutex concepts, see
|
||||||
|
<classname>mutex</classname> and <classname>timed_mutex</classname>.</para>
|
||||||
|
|
||||||
|
<para>For <link linkend="threads.concepts.recursive-locking-strategy">Recursive</link>
|
||||||
|
locking mechanics, see <classname>recursive_mutex</classname>,
|
||||||
|
<classname>recursive_try_mutex</classname>, and <classname>recursive_timed_mutex</classname>.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>The <classname>try_mutex</classname> class supplies the following typedefs,
|
||||||
|
which <link linkend="threads.concepts.lock-models">model</link>
|
||||||
|
the specified locking strategies:
|
||||||
|
|
||||||
|
<informaltable>
|
||||||
|
<title>Supported Lock Types</title>
|
||||||
|
<tgroup cols="2" align="left">
|
||||||
|
<thead>
|
||||||
|
<row>
|
||||||
|
<entry>Lock Name</entry>
|
||||||
|
<entry>Lock Concept</entry>
|
||||||
|
</row>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<row>
|
||||||
|
<entry>scoped_lock</entry>
|
||||||
|
<entry><link linkend="threads.concepts.ScopedLock">ScopedLock</link></entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>scoped_try_lock</entry>
|
||||||
|
<entry><link linkend="threads.concepts.ScopedTryLock">ScopedTryLock</link></entry>
|
||||||
|
</row>
|
||||||
|
</tbody>
|
||||||
|
</tgroup>
|
||||||
|
</informaltable>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>The <classname>try_mutex</classname> class uses an
|
||||||
|
<link linkend="threads.concepts.unspecified-locking-strategy">Unspecified</link>
|
||||||
|
locking strategy, so attempts to recursively lock a <classname>try_mutex</classname>
|
||||||
|
object or attempts to unlock one by threads that don't own a lock on it result in
|
||||||
|
<emphasis role="bold">undefined behavior</emphasis>.
|
||||||
|
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.</para>
|
||||||
|
|
||||||
|
<para>Like all
|
||||||
|
<link linkend="threads.concepts.mutex-models">mutex models</link>
|
||||||
|
in &Boost.Threads;, <classname>try_mutex</classname> leaves the
|
||||||
|
<link linkend="threads.concepts.sheduling-policies">scheduling policy</link>
|
||||||
|
as <link linkend="threads.concepts.unspecified-scheduling-policy">Unspecified</link>.
|
||||||
|
Programmers should make no assumptions about the order in which
|
||||||
|
waiting threads acquire a lock.</para>
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<inherit access="private">
|
||||||
|
<type><classname>boost::noncopyable</classname></type>
|
||||||
|
<purpose>Exposition only</purpose>
|
||||||
|
</inherit>
|
||||||
|
|
||||||
|
<typedef name="scoped_lock">
|
||||||
|
<type><emphasis>implementation-defined</emphasis></type>
|
||||||
|
</typedef>
|
||||||
|
|
||||||
|
<typedef name="scoped_try_lock">
|
||||||
|
<type><emphasis>implementation-defined</emphasis></type>
|
||||||
|
</typedef>
|
||||||
|
|
||||||
|
<constructor>
|
||||||
|
<effects>Constructs a <classname>try_mutex</classname> object.
|
||||||
|
</effects>
|
||||||
|
|
||||||
|
<postconditions><code>*this</code> is in an unlocked state.
|
||||||
|
</postconditions>
|
||||||
|
</constructor>
|
||||||
|
|
||||||
|
<destructor>
|
||||||
|
<effects>Destroys a <classname>try_mutex</classname> object.
|
||||||
|
</effects>
|
||||||
|
|
||||||
|
<requires><code>*this</code> is in an unlocked state.</requires>
|
||||||
|
|
||||||
|
<notes><emphasis role="bold">Danger:</emphasis> Destruction of a
|
||||||
|
locked mutex is a serious programming error resulting in undefined
|
||||||
|
behavior such as a program crash.</notes>
|
||||||
|
</destructor>
|
||||||
|
</class>
|
||||||
|
|
||||||
|
<class name="timed_mutex">
|
||||||
|
<purpose>
|
||||||
|
<para>The <classname>timed_mutex</classname> class is a model of the
|
||||||
|
<link linkend="threads.concepts.TimedMutex">TimedMutex</link> concept.</para>
|
||||||
|
</purpose>
|
||||||
|
|
||||||
|
<description>
|
||||||
|
<para>The <classname>timed_mutex</classname> class is a model of the
|
||||||
|
<link linkend="threads.concepts.TimedMutex">TimedMutex</link> concept.
|
||||||
|
It should be used to synchronize access to shared resources using
|
||||||
|
<link linkend="threads.concepts.unspecified-locking-strategy">Unspecified</link>
|
||||||
|
locking mechanics.</para>
|
||||||
|
|
||||||
|
<para>For classes that model related mutex concepts, see
|
||||||
|
<classname>mutex</classname> and <classname>try_mutex</classname>.</para>
|
||||||
|
|
||||||
|
<para>For <link linkend="threads.concepts.recursive-locking-strategy">Recursive</link>
|
||||||
|
locking mechanics, see <classname>recursive_mutex</classname>,
|
||||||
|
<classname>recursive_try_mutex</classname>, and <classname>recursive_timed_mutex</classname>.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>The <classname>timed_mutex</classname> class supplies the following typedefs,
|
||||||
|
which <link linkend="threads.concepts.lock-models">model</link>
|
||||||
|
the specified locking strategies:
|
||||||
|
|
||||||
|
<informaltable>
|
||||||
|
<title>Supported Lock Types</title>
|
||||||
|
<tgroup cols="2" align="left">
|
||||||
|
<thead>
|
||||||
|
<row>
|
||||||
|
<entry>Lock Name</entry>
|
||||||
|
<entry>Lock Concept</entry>
|
||||||
|
</row>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<row>
|
||||||
|
<entry>scoped_lock</entry>
|
||||||
|
<entry><link linkend="threads.concepts.ScopedLock">ScopedLock</link></entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>scoped_try_lock</entry>
|
||||||
|
<entry><link linkend="threads.concepts.ScopedTryLock">ScopedTryLock</link></entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>scoped_timed_lock</entry>
|
||||||
|
<entry><link linkend="threads.concepts.ScopedTimedLock">ScopedTimedLock</link></entry>
|
||||||
|
</row>
|
||||||
|
</tbody>
|
||||||
|
</tgroup>
|
||||||
|
</informaltable>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>The <classname>timed_mutex</classname> class uses an
|
||||||
|
<link linkend="threads.concepts.unspecified-locking-strategy">Unspecified</link>
|
||||||
|
locking strategy, so attempts to recursively lock a <classname>timed_mutex</classname>
|
||||||
|
object or attempts to unlock one by threads that don't own a lock on it result in
|
||||||
|
<emphasis role="bold">undefined behavior</emphasis>.
|
||||||
|
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.</para>
|
||||||
|
|
||||||
|
<para>Like all
|
||||||
|
<link linkend="threads.concepts.mutex-models">mutex models</link>
|
||||||
|
in &Boost.Threads;, <classname>timed_mutex</classname> leaves the
|
||||||
|
<link linkend="threads.concepts.sheduling-policies">scheduling policy</link>
|
||||||
|
as <link linkend="threads.concepts.unspecified-scheduling-policy">Unspecified</link>.
|
||||||
|
Programmers should make no assumptions about the order in which
|
||||||
|
waiting threads acquire a lock.</para>
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<inherit access="private">
|
||||||
|
<type><classname>boost::noncopyable</classname></type>
|
||||||
|
<purpose>Exposition only</purpose>
|
||||||
|
</inherit>
|
||||||
|
|
||||||
|
<typedef name="scoped_lock">
|
||||||
|
<type><emphasis>implementation-defined</emphasis></type>
|
||||||
|
</typedef>
|
||||||
|
|
||||||
|
<typedef name="scoped_try_lock">
|
||||||
|
<type><emphasis>implementation-defined</emphasis></type>
|
||||||
|
</typedef>
|
||||||
|
|
||||||
|
<typedef name="scoped_timed_lock">
|
||||||
|
<type><emphasis>implementation-defined</emphasis></type>
|
||||||
|
</typedef>
|
||||||
|
|
||||||
|
<constructor>
|
||||||
|
<effects>Constructs a <classname>timed_mutex</classname> object.
|
||||||
|
</effects>
|
||||||
|
|
||||||
|
<postconditions><code>*this</code> is in an unlocked state.
|
||||||
|
</postconditions>
|
||||||
|
</constructor>
|
||||||
|
|
||||||
|
<destructor>
|
||||||
|
<effects>Destroys a <classname>timed_mutex</classname> object.</effects>
|
||||||
|
|
||||||
|
<requires><code>*this</code> is in an unlocked state.</requires>
|
||||||
|
|
||||||
|
<notes><emphasis role="bold">Danger:</emphasis> Destruction of a
|
||||||
|
locked mutex is a serious programming error resulting in undefined
|
||||||
|
behavior such as a program crash.</notes>
|
||||||
|
</destructor>
|
||||||
|
</class>
|
||||||
|
</namespace>
|
||||||
|
</header>
|
||||||
243
doc/mutex.html
243
doc/mutex.html
@@ -1,243 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
|
||||||
<link rel="stylesheet" type="text/css" href="../../../boost.css">
|
|
||||||
<title>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>
|
|
||||||
<p><a href="../example/mutex.cpp">libs/thread/example/mutex.cpp</a></p>
|
|
||||||
<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>
|
|
||||||
@@ -1,239 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
|
||||||
<link rel="stylesheet" type="text/css" href="../../../boost.css">
|
|
||||||
<title>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>
|
|
||||||
86
doc/once-ref.xml
Normal file
86
doc/once-ref.xml
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
||||||
|
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
|
||||||
|
<!ENTITY % threads.entities SYSTEM "entities.xml">
|
||||||
|
%threads.entities;
|
||||||
|
]>
|
||||||
|
<header name="boost/thread/once.hpp"
|
||||||
|
last-revision="$Date$">
|
||||||
|
<macro name="BOOST_ONCE_INIT">
|
||||||
|
<purpose>The <functionname>call_once</functionname> function and
|
||||||
|
<code>once_flag</code> type (statically initialized to
|
||||||
|
<macroname>BOOST_ONCE_INIT</macroname>) can be used to run a
|
||||||
|
routine exactly once. This can be used to initialize data in a
|
||||||
|
<link linkend="threads.glossary.thread-safe">thread-safe</link>
|
||||||
|
manner.</purpose>
|
||||||
|
|
||||||
|
<description>The implementation-defined macro
|
||||||
|
<macroname>BOOST_ONCE_INIT</macroname> is a constant value used to
|
||||||
|
initialize <code>once_flag</code> instances to indicate that the
|
||||||
|
logically associated routine has not been run yet. See
|
||||||
|
<functionname>call_once</functionname> for more details.</description>
|
||||||
|
</macro>
|
||||||
|
|
||||||
|
<namespace name="boost">
|
||||||
|
<typedef name="once_flag">
|
||||||
|
<purpose>The <functionname>call_once</functionname> function and
|
||||||
|
<code>once_flag</code> type (statically initialized to
|
||||||
|
<macroname>BOOST_ONCE_INIT</macroname>) can be used to run a
|
||||||
|
routine exactly once. This can be used to initialize data in a
|
||||||
|
<link linkend="threads.glossary.thread-safe">thread-safe</link>
|
||||||
|
manner.</purpose>
|
||||||
|
|
||||||
|
<description>The implementation-defined type <code>once_flag</code>
|
||||||
|
is used as a flag to insure a routine is called only once.
|
||||||
|
Instances of this type should be statically initialized to
|
||||||
|
<macroname>BOOST_ONCE_INIT</macroname>. See
|
||||||
|
<functionname>call_once</functionname> for more details.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<type><emphasis>implementation-defined</emphasis></type>
|
||||||
|
</typedef>
|
||||||
|
|
||||||
|
<function name="call_once">
|
||||||
|
<purpose>The <functionname>call_once</functionname> function and
|
||||||
|
<code>once_flag</code> type (statically initialized to
|
||||||
|
<macroname>BOOST_ONCE_INIT</macroname>) can be used to run a
|
||||||
|
routine exactly once. This can be used to initialize data in a
|
||||||
|
<link linkend="threads.glossary.thread-safe">thread-safe</link>
|
||||||
|
manner.</purpose>
|
||||||
|
|
||||||
|
<description>
|
||||||
|
<para>Example usage is as follows:</para>
|
||||||
|
<para>
|
||||||
|
<programlisting>//Example usage:
|
||||||
|
boost::once_flag once = BOOST_ONCE_INIT;
|
||||||
|
|
||||||
|
void init()
|
||||||
|
{
|
||||||
|
//...
|
||||||
|
}
|
||||||
|
|
||||||
|
void thread_proc()
|
||||||
|
{
|
||||||
|
boost::call_once(&init, once);
|
||||||
|
}</programlisting>
|
||||||
|
</para></description>
|
||||||
|
|
||||||
|
<parameter name="func">
|
||||||
|
<paramtype>void (*func)()</paramtype>
|
||||||
|
</parameter>
|
||||||
|
|
||||||
|
<parameter name="flag">
|
||||||
|
<paramtype>once_flag&</paramtype>
|
||||||
|
</parameter>
|
||||||
|
|
||||||
|
<requires>The function <code>func</code> shall not throw
|
||||||
|
exceptions.</requires>
|
||||||
|
|
||||||
|
<effects>As if (in an atomic fashion):
|
||||||
|
<code>if (flag == BOOST_ONCE_INIT) func();</code></effects>
|
||||||
|
|
||||||
|
<postconditions><code>flag != BOOST_ONCE_INIT</code>
|
||||||
|
</postconditions>
|
||||||
|
</function>
|
||||||
|
</namespace>
|
||||||
|
</header>
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
|
||||||
<link rel="stylesheet" type="text/css" href="../../../boost.css">
|
|
||||||
<title>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>
|
|
||||||
<p><a href="../example/once.cpp">libs/thread/example/once.cpp</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>
|
|
||||||
@@ -1,173 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
|
||||||
<link rel="stylesheet" type="text/css" href="../../../boost.css">
|
|
||||||
<title>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>
|
|
||||||
202
doc/overview.xml
Normal file
202
doc/overview.xml
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
||||||
|
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
|
||||||
|
<!ENTITY % threads.entities SYSTEM "entities.xml">
|
||||||
|
%threads.entities;
|
||||||
|
]>
|
||||||
|
<section id="threads.overview" last-revision="$Date$">
|
||||||
|
<title>Overview</title>
|
||||||
|
<section id="threads.introduction">
|
||||||
|
<title>Introduction</title>
|
||||||
|
<para>&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. The <link
|
||||||
|
linkend="threads.glossary">glossary</link> gives a more complete description
|
||||||
|
of the multithreading execution environment.</para>
|
||||||
|
<para>Multithreading provides several advantages:
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem>
|
||||||
|
<para>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.</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>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 than single-threaded programs.</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>Some program designs may be easier to formulate using a
|
||||||
|
multithreaded approach. After all, the real world is
|
||||||
|
asynchronous!</para>
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist></para>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<title>Dangers</title>
|
||||||
|
<section>
|
||||||
|
<title>General considerations</title>
|
||||||
|
<para>Beyond the errors which can occur in single-threaded programs,
|
||||||
|
multithreaded programs are subject to additional errors:
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem>
|
||||||
|
<para><link linkend="threads.glossary.race-condition">Race
|
||||||
|
conditions</link></para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para><link linkend="threads.glossary.deadlock">Deadlock</link>
|
||||||
|
(sometimes called "deadly embrace")</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para><link linkend="threads.glossary.priority-failure">Priority
|
||||||
|
failures</link> (priority inversion, infinite overtaking, starvation,
|
||||||
|
etc.)</para>
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist></para>
|
||||||
|
<para>Every multithreaded program must be designed carefully to avoid these
|
||||||
|
errors. 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.</para>
|
||||||
|
<para>The <link linkend="threads.design">&Boost.Threads; design</link>
|
||||||
|
attempts to minimize these errors, but they will still occur unless the
|
||||||
|
programmer proactively designs to avoid them.</para>
|
||||||
|
<note>Please also see <xref linkend="threads.implementation_notes"/>
|
||||||
|
for additional, implementation-specific considerations.</note>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<title>Testing and debugging considerations</title>
|
||||||
|
<para>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:
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem>
|
||||||
|
<para>Failures are often not repeatable.</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>Probe effect causes debuggers to produce very different results
|
||||||
|
from non-debug uses.</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>Debuggers require special support to show thread state.</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>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.</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>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.</para>
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist></para>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<title>Getting a head start</title>
|
||||||
|
<para>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.</para>
|
||||||
|
<para>Design patterns for reliable multithreaded programs, including the
|
||||||
|
important <emphasis>monitor</emphasis> pattern, are presented in
|
||||||
|
<emphasis>Pattern-Oriented Software Architecture Volume 2 - Patterns for
|
||||||
|
Concurrent and Networked Objects</emphasis>
|
||||||
|
&cite.SchmidtStalRohnertBuschmann;. Many important multithreading programming
|
||||||
|
considerations (independent of threading library) are discussed in
|
||||||
|
<emphasis>Programming with POSIX Threads</emphasis> &cite.Butenhof97;.</para>
|
||||||
|
<para>Doing some reading before attempting multithreaded designs will
|
||||||
|
give you a head start toward reliable multithreaded programs.</para>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<title>C++ Standard Library usage in multithreaded programs</title>
|
||||||
|
<section>
|
||||||
|
<title>Runtime libraries</title>
|
||||||
|
<para>
|
||||||
|
<emphasis role="bold">Warning:</emphasis> Multithreaded programs such as
|
||||||
|
those using &Boost.Threads; must link to <link
|
||||||
|
linkend="threads.glossary.thread-safe">thread-safe</link> versions of
|
||||||
|
all runtime libraries used by the program, including the runtime library
|
||||||
|
for the C++ Standard Library. Failure to do so will cause <link
|
||||||
|
linkend="threads.glossary.race-condition">race conditions</link> to occur
|
||||||
|
when multiple threads simultaneously execute runtime library functions for
|
||||||
|
<code>new</code>, <code>delete</code>, or other language features which
|
||||||
|
imply shared state.</para>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<title>Potentially non-thread-safe functions</title>
|
||||||
|
<para>Certain C++ Standard Library functions inherited from C are
|
||||||
|
particular problems because they hold internal state between
|
||||||
|
calls:
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem>
|
||||||
|
<para><code>rand</code></para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para><code>strtok</code></para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para><code>asctime</code></para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para><code>ctime</code></para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para><code>gmtime</code></para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para><code>localtime</code></para>
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist></para>
|
||||||
|
<para>It is possible to write thread-safe implementations of these by
|
||||||
|
using thread specific storage (see
|
||||||
|
<classname>boost::thread_specific_ptr</classname>), and several C++
|
||||||
|
compiler vendors do just that. The technique is well-know and is explained
|
||||||
|
in &cite.Butenhof97;.</para>
|
||||||
|
<para>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.</para>
|
||||||
|
<para><emphasis role="bold">Recommendation:</emphasis> For the most
|
||||||
|
portable, yet thread-safe code, use Boost replacements for the problem
|
||||||
|
functions. See the <libraryname>Boost Random Number Library</libraryname>
|
||||||
|
and <libraryname>Boost Tokenizer Library</libraryname>.</para>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<title>Common guarantees for all &Boost.Threads; components</title>
|
||||||
|
<section>
|
||||||
|
<title>Exceptions</title>
|
||||||
|
<para>&Boost.Threads; destructors never
|
||||||
|
throw exceptions. Unless otherwise specified, other
|
||||||
|
&Boost.Threads; functions that do not have
|
||||||
|
an exception-specification may throw implementation-defined
|
||||||
|
exceptions.</para>
|
||||||
|
<para>In particular, &Boost.Threads;
|
||||||
|
reports failure to allocate storage by throwing an exception of type
|
||||||
|
<code>std::bad_alloc</code> or a class derived from
|
||||||
|
<code>std::bad_alloc</code>, failure to obtain thread resources other than
|
||||||
|
memory by throwing an exception of type
|
||||||
|
<classname>boost::thread_resource_error</classname>, and certain lock
|
||||||
|
related failures by throwing an exception of type
|
||||||
|
<classname>boost::lock_error</classname>.</para>
|
||||||
|
<para><emphasis role="bold">Rationale:</emphasis> Follows the C++ Standard
|
||||||
|
Library practice of allowing all functions except destructors or other
|
||||||
|
specified functions to throw exceptions on errors.</para>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<title>NonCopyable requirement</title>
|
||||||
|
<para>&Boost.Threads; 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 <classname>boost::noncopyable</classname>. Users
|
||||||
|
should not depend on this derivation, however, as implementations are free
|
||||||
|
to meet the NonCopyable requirement in other ways.</para>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
@@ -1,399 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
|
||||||
<link rel="stylesheet" type="text/css" href="../../../boost.css">
|
|
||||||
<title>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>
|
|
||||||
434
doc/rationale.xml
Normal file
434
doc/rationale.xml
Normal file
@@ -0,0 +1,434 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
||||||
|
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
|
||||||
|
<!ENTITY % threads.entities SYSTEM "entities.xml">
|
||||||
|
%threads.entities;
|
||||||
|
]>
|
||||||
|
<section id="threads.rationale" last-revision="$Date$">
|
||||||
|
<title>Rationale</title>
|
||||||
|
<para>This page explains the rationale behind various design decisions in the
|
||||||
|
&Boost.Threads; 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.</para>
|
||||||
|
<section id="threads.rationale.Boost.Threads">
|
||||||
|
<title>Rationale for the Creation of &Boost.Threads;</title>
|
||||||
|
<para>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.</para>
|
||||||
|
<para>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.</para>
|
||||||
|
<para>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.</para>
|
||||||
|
<para>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.</para>
|
||||||
|
<para>The &Boost.Threads; 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.</para>
|
||||||
|
</section>
|
||||||
|
<section id="threads.rationale.primitives">
|
||||||
|
<title>Rationale for the Low Level Primitives Supported in &Boost.Threads;</title>
|
||||||
|
<para>The &Boost.Threads; library supplies a set of low level primitives for
|
||||||
|
writing multithreaded programs, such as mutexes and condition variables. In
|
||||||
|
fact, the first release of &Boost.Threads; 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 &Boost.Threads; support the
|
||||||
|
lower level concepts?</para>
|
||||||
|
<para>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.</para>
|
||||||
|
<para>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 unfamiliar with any of the higher
|
||||||
|
level concepts, supporting the lower level concepts provides
|
||||||
|
greater accessibility.</para>
|
||||||
|
</section>
|
||||||
|
<section id="threads.rationale.locks">
|
||||||
|
<title>Rationale for the Lock Design</title>
|
||||||
|
<para>Programmers who are used to multithreaded programming issues will
|
||||||
|
quickly note that the &Boost.Threads; design for mutex lock concepts is not
|
||||||
|
<link linkend="threads.glossary.thread-safe">thread-safe</link> (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?</para>
|
||||||
|
<para>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.</para>
|
||||||
|
<para>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.</para>
|
||||||
|
<para>So, to avoid the overhead of synchronizing access to the state
|
||||||
|
information and to avoid the race condition, the &Boost.Threads; 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.</para>
|
||||||
|
</section>
|
||||||
|
<section id="threads.rationale.non-copyable">
|
||||||
|
<title>Rationale for NonCopyable Thread Type</title>
|
||||||
|
<para>Programmers who are used to C libraries for multithreaded programming
|
||||||
|
are likely to wonder why &Boost.Threads; uses a noncopyable design for
|
||||||
|
<classname>boost::thread</classname>. 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.</para>
|
||||||
|
<para>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 resource. 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.</para>
|
||||||
|
<para>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.</para>
|
||||||
|
<para>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.</para>
|
||||||
|
<section id="threads.rationale.non-copyable.simple">
|
||||||
|
<title>1. Use case: Simple creation of a thread.</title>
|
||||||
|
<programlisting>
|
||||||
|
void foo()
|
||||||
|
{
|
||||||
|
create_thread(&bar);
|
||||||
|
}
|
||||||
|
</programlisting>
|
||||||
|
</section>
|
||||||
|
<section id="threads.rationale.non-copyable.joined">
|
||||||
|
<title>2. Use case: Creation of a thread that's later joined.</title>
|
||||||
|
<programlisting>
|
||||||
|
void foo()
|
||||||
|
{
|
||||||
|
thread = create_thread(&bar);
|
||||||
|
join(thread);
|
||||||
|
}
|
||||||
|
</programlisting>
|
||||||
|
</section>
|
||||||
|
<section id="threads.rationale.non-copyable.loop">
|
||||||
|
<title>3. Use case: Simple creation of several threads in a loop.</title>
|
||||||
|
<programlisting>
|
||||||
|
void foo()
|
||||||
|
{
|
||||||
|
for (int i=0; i<NUM_THREADS; ++i)
|
||||||
|
create_thread(&bar);
|
||||||
|
}
|
||||||
|
</programlisting>
|
||||||
|
</section>
|
||||||
|
<section id="threads.rationale.non-copyable.loop-join">
|
||||||
|
<title>4. Use case: Creation of several threads in a loop which are later joined.</title>
|
||||||
|
<programlisting>
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
</programlisting>
|
||||||
|
</section>
|
||||||
|
<section id="threads.rationale.non-copyable.pass">
|
||||||
|
<title>5. Use case: Creation of a thread whose ownership is passed to another object/method.</title>
|
||||||
|
<programlisting>
|
||||||
|
void foo()
|
||||||
|
{
|
||||||
|
thread = create_thread(&bar);
|
||||||
|
manager.owns(thread);
|
||||||
|
}
|
||||||
|
</programlisting>
|
||||||
|
</section>
|
||||||
|
<section id="threads.rationale.non-copyable.shared">
|
||||||
|
<title>6. Use case: Creation of a thread whose ownership is shared between multiple
|
||||||
|
objects.</title>
|
||||||
|
<programlisting>
|
||||||
|
void foo()
|
||||||
|
{
|
||||||
|
thread = create_thread(&bar);
|
||||||
|
manager1.add(thread);
|
||||||
|
manager2.add(thread);
|
||||||
|
}
|
||||||
|
</programlisting>
|
||||||
|
</section>
|
||||||
|
<para>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.</para>
|
||||||
|
<para>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.</para>
|
||||||
|
<para>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.</para>
|
||||||
|
<para>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.</para>
|
||||||
|
<section id="threads.rationale_comparison.non-copyable.simple">
|
||||||
|
<title>1. Comparison: simple creation of a thread.</title>
|
||||||
|
<programlisting>
|
||||||
|
void foo()
|
||||||
|
{
|
||||||
|
thread thrd(&bar);
|
||||||
|
}
|
||||||
|
void foo()
|
||||||
|
{
|
||||||
|
thread_ref thrd = create_thread(&bar);
|
||||||
|
}
|
||||||
|
</programlisting>
|
||||||
|
</section>
|
||||||
|
<section id="threads.rationale_comparison.non-copyable.joined">
|
||||||
|
<title>2. Comparison: creation of a thread that's later joined.</title>
|
||||||
|
<programlisting>
|
||||||
|
void foo()
|
||||||
|
{
|
||||||
|
thread thrd(&bar);
|
||||||
|
thrd.join();
|
||||||
|
}
|
||||||
|
void foo()
|
||||||
|
{
|
||||||
|
thread_ref thrd =
|
||||||
|
create_thread(&bar);thrd->join();
|
||||||
|
}
|
||||||
|
</programlisting>
|
||||||
|
</section>
|
||||||
|
<section id="threads.rationale_comparison.non-copyable.loop">
|
||||||
|
<title>3. Comparison: simple creation of several threads in a loop.</title>
|
||||||
|
<programlisting>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
</programlisting>
|
||||||
|
</section>
|
||||||
|
<section id="threads.rationale_comparison.non-copyable.loop-join">
|
||||||
|
<title>4. Comparison: creation of several threads in a loop which are later joined.</title>
|
||||||
|
<programlisting>
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
</programlisting>
|
||||||
|
</section>
|
||||||
|
<section id="threads.rationale_comparison.non-copyable.pass">
|
||||||
|
<title>5. Comparison: creation of a thread whose ownership is passed to another object/method.</title>
|
||||||
|
<programlisting>
|
||||||
|
void foo()
|
||||||
|
{
|
||||||
|
thread thrd* = new thread(&bar);
|
||||||
|
manager.owns(thread);
|
||||||
|
}
|
||||||
|
void foo()
|
||||||
|
{
|
||||||
|
thread_ref thrd = create_thread(&bar);
|
||||||
|
manager.owns(thrd);
|
||||||
|
}
|
||||||
|
</programlisting>
|
||||||
|
</section>
|
||||||
|
<section id="threads.rationale_comparison.non-copyable.shared">
|
||||||
|
<title>6. Comparison: creation of a thread whose ownership is shared
|
||||||
|
between multiple objects.</title>
|
||||||
|
<programlisting>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
</programlisting>
|
||||||
|
</section>
|
||||||
|
<para>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
|
||||||
|
<link linkend="threads.rationale_comparison.non-copyable.loop-join">(4)</link>,
|
||||||
|
<link linkend="threads.rationale_comparison.non-copyable.pass">(5)</link>, and
|
||||||
|
<link linkend="threads.rationale_comparison.non-copyable.shared">(6)</link>;
|
||||||
|
and the use of std::auto_ptr and boost::shared_ptr in
|
||||||
|
<link linkend="threads.rationale_comparison.non-copyable.loop-join">(4)</link> and
|
||||||
|
<link linkend="threads.rationale_comparison.non-copyable.shared">(6)</link>
|
||||||
|
respectively. However, that's not really
|
||||||
|
much added complexity, and C++ programmers are used to using these idioms
|
||||||
|
anyway. 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
|
||||||
|
<link linkend="threads.rationale_comparison.non-copyable.loop-join">(4)</link>
|
||||||
|
down to:</para>
|
||||||
|
<programlisting>
|
||||||
|
void foo()
|
||||||
|
{
|
||||||
|
thread_group threads;
|
||||||
|
for (int i=0; i<NUM_THREADS; ++i)
|
||||||
|
threads.create_thread(&bar);
|
||||||
|
threads.join_all();
|
||||||
|
}
|
||||||
|
</programlisting>
|
||||||
|
<para>So ease of use is really a wash and not much help in picking a
|
||||||
|
design.</para>
|
||||||
|
<para>So what about performance? Looking at the above code examples,
|
||||||
|
we can analyze the theoretical impact to performance that both designs
|
||||||
|
have. For <link linkend="threads.rationale_comparison.non-copyable.simple">(1)</link>
|
||||||
|
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 <link linkend="threads.rationale_comparison.non-copyable.joined">(2)</link>
|
||||||
|
and <link linkend="threads.rationale_comparison.non-copyable.loop">(3)</link>
|
||||||
|
the performance impact will be identical to
|
||||||
|
<link linkend="threads.rationale_comparison.non-copyable.simple">(1)</link>.
|
||||||
|
For <link linkend="threads.rationale_comparison.non-copyable.loop-join">(4)</link>
|
||||||
|
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
|
||||||
|
<link linkend="threads.rationale_comparison.non-copyable.pass">(5)</link> we see
|
||||||
|
the same impact as we do for
|
||||||
|
<link linkend="threads.rationale_comparison.non-copyable.loop-join">(4)</link>.
|
||||||
|
For <link linkend="threads.rationale_comparison.non-copyable.shared">(6)</link>
|
||||||
|
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
|
||||||
|
<link linkend="threads.rationale_comparison.non-copyable.simple">(1)</link>,
|
||||||
|
<link linkend="threads.rationale_comparison.non-copyable.joined">(2)</link> and
|
||||||
|
<link linkend="threads.rationale_comparison.non-copyable.loop">(3)</link>; with
|
||||||
|
<link linkend="threads.rationale_comparison.non-copyable.loop-join">(4)</link>
|
||||||
|
and <link linkend="threads.rationale_comparison.non-copyable.pass">(5)</link> the
|
||||||
|
winner depending on the implementation and the platform but with the thread design
|
||||||
|
probably having a better chance; and with
|
||||||
|
<link linkend="threads.rationale_comparison.non-copyable.shared">(6)</link>
|
||||||
|
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.</para>
|
||||||
|
<para>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 &Boost.Threads; library has gone with a noncopyable design.</para>
|
||||||
|
</section>
|
||||||
|
<section id="threads.rationale.events">
|
||||||
|
<title>Rationale for not providing <emphasis>Event Variables</emphasis></title>
|
||||||
|
<para><emphasis>Event variables</emphasis> are simply far too
|
||||||
|
error-prone. <classname>boost::condition</classname> variables are a much safer
|
||||||
|
alternative. [Note that Graphical User Interface <emphasis>events</emphasis> are
|
||||||
|
a different concept, and are not what is being discussed here.]</para>
|
||||||
|
<para>Event variables were one of the first synchronization primitives. They
|
||||||
|
are still used today, for example, in the native Windows multithreading
|
||||||
|
API. 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.</para>
|
||||||
|
<para>Per Brinch Hansen &cite.Hansen73; analyzed event variables in some
|
||||||
|
detail, pointing out [emphasis his] that "<emphasis>event operations force
|
||||||
|
the programmer to be aware of the relative speeds of the sending and
|
||||||
|
receiving processes</emphasis>". His summary:</para>
|
||||||
|
<blockquote>
|
||||||
|
<para>We must therefore conclude that event variables of the previous type
|
||||||
|
are impractical for system design. <emphasis>The effect of an interaction
|
||||||
|
between two processes must be independent of the speed at which it is
|
||||||
|
carried out.</emphasis></para>
|
||||||
|
</blockquote>
|
||||||
|
<para>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 <link
|
||||||
|
linkend="threads.glossary.race-condition">race condition</link> 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.</para>
|
||||||
|
<para>The decision to exclude event variables from &Boost.Threads; 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 will be less likely to contain latent defects.</para>
|
||||||
|
<para>[Rationale provided by Beman Dawes]</para>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
362
doc/read_write_mutex-ref.xml
Normal file
362
doc/read_write_mutex-ref.xml
Normal file
@@ -0,0 +1,362 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
||||||
|
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
|
||||||
|
<!ENTITY % threads.entities SYSTEM "entities.xml">
|
||||||
|
%threads.entities;
|
||||||
|
]>
|
||||||
|
<header name="boost/thread/read_write_mutex.hpp"
|
||||||
|
last-revision="$Date$">
|
||||||
|
<namespace name="boost">
|
||||||
|
<namespace name="read_write_scheduling_policy">
|
||||||
|
<enum name="read_write_scheduling_policy">
|
||||||
|
<enumvalue name="writer_priority" />
|
||||||
|
<enumvalue name="reader_priority" />
|
||||||
|
<enumvalue name="alternating_many_reads" />
|
||||||
|
<enumvalue name="alternating_single_read" />
|
||||||
|
|
||||||
|
<purpose>
|
||||||
|
<para>Specifies the
|
||||||
|
<link linkend="threads.concepts.read-write-scheduling-policies.inter-class">inter-class sheduling policy</link>
|
||||||
|
to use when a set of threads try to obtain different types of
|
||||||
|
locks simultaneously.</para>
|
||||||
|
</purpose>
|
||||||
|
|
||||||
|
<description>
|
||||||
|
<para>The only clock type supported by &Boost.Threads; is
|
||||||
|
<code>TIME_UTC</code>. The epoch for <code>TIME_UTC</code>
|
||||||
|
is 1970-01-01 00:00:00.</para>
|
||||||
|
</description>
|
||||||
|
</enum>
|
||||||
|
</namespace>
|
||||||
|
|
||||||
|
<class name="read_write_mutex">
|
||||||
|
<purpose>
|
||||||
|
<para>The <classname>read_write_mutex</classname> class is a model of the
|
||||||
|
<link linkend="threads.concepts.ReadWriteMutex">ReadWriteMutex</link> concept.</para>
|
||||||
|
</purpose>
|
||||||
|
|
||||||
|
<description>
|
||||||
|
<para>The <classname>read_write_mutex</classname> class is a model of the
|
||||||
|
<link linkend="threads.concepts.ReadWriteMutex">ReadWriteMutex</link> concept.
|
||||||
|
It should be used to synchronize access to shared resources using
|
||||||
|
<link linkend="threads.concepts.read-write-locking-strategies.unspecified">Unspecified</link>
|
||||||
|
locking mechanics.</para>
|
||||||
|
|
||||||
|
<para>For classes that model related mutex concepts, see
|
||||||
|
<classname>try_read_write_mutex</classname> and <classname>timed_read_write_mutex</classname>.</para>
|
||||||
|
|
||||||
|
<para>The <classname>read_write_mutex</classname> class supplies the following typedef,
|
||||||
|
which <link linkend="threads.concepts.read-write-lock-models">models</link>
|
||||||
|
the specified locking strategy:
|
||||||
|
|
||||||
|
<informaltable>
|
||||||
|
<tgroup cols="2" align="left">
|
||||||
|
<thead>
|
||||||
|
<row>
|
||||||
|
<entry>Lock Name</entry>
|
||||||
|
<entry>Lock Concept</entry>
|
||||||
|
</row>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<row>
|
||||||
|
<entry>scoped_lock</entry>
|
||||||
|
<entry><link linkend="threads.concepts.ScopedReadWriteLock">ScopedReadWriteLock</link></entry>
|
||||||
|
</row>
|
||||||
|
</tbody>
|
||||||
|
</tgroup>
|
||||||
|
</informaltable>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>The <classname>read_write_mutex</classname> class uses an
|
||||||
|
<link linkend="threads.concepts.read-write-locking-strategies.unspecified">Unspecified</link>
|
||||||
|
locking strategy, so attempts to recursively lock a <classname>read_write_mutex</classname>
|
||||||
|
object or attempts to unlock one by threads that don't own a lock on it result in
|
||||||
|
<emphasis role="bold">undefined behavior</emphasis>.
|
||||||
|
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.</para>
|
||||||
|
|
||||||
|
<para>Like all
|
||||||
|
<link linkend="threads.concepts.read-write-mutex-models">read/write mutex models</link>
|
||||||
|
in &Boost.Threads;, <classname>read_write_mutex</classname> has two types of
|
||||||
|
<link linkend="threads.concepts.read-write-scheduling-policies">scheduling policies</link>, an
|
||||||
|
<link linkend="threads.concepts.read-write-scheduling-policies.inter-class">inter-class sheduling policy</link>
|
||||||
|
between threads trying to obtain different types of locks and an
|
||||||
|
<link linkend="threads.concepts.read-write-scheduling-policies.intra-class">intra-class sheduling policy</link>
|
||||||
|
between threads trying to obtain the same type of lock.
|
||||||
|
The <classname>read_write_mutex</classname> class allows the
|
||||||
|
programmer to choose what
|
||||||
|
<link linkend="threads.concepts.read-write-scheduling-policies.inter-class">inter-class sheduling policy</link>
|
||||||
|
will be used; however, like all read/write mutex models,
|
||||||
|
<classname>read_write_mutex</classname> leaves the
|
||||||
|
<link linkend="threads.concepts.read-write-scheduling-policies.intra-class">intra-class sheduling policy</link> as
|
||||||
|
<link linkend="threads.concepts.read-write-locking-strategies.unspecified">Unspecified</link>.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<note>Self-deadlock is virtually guaranteed if a thread tries to
|
||||||
|
lock the same <classname>read_write_mutex</classname> multiple times
|
||||||
|
unless all locks are read-locks (but see below)</note>
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<inherit access="private">
|
||||||
|
<type><classname>boost::noncopyable</classname></type>
|
||||||
|
<purpose>Exposition only</purpose>
|
||||||
|
</inherit>
|
||||||
|
|
||||||
|
<inherit access="private">
|
||||||
|
<type><classname>boost::noncopyable</classname></type>
|
||||||
|
<purpose>Exposition only</purpose>
|
||||||
|
</inherit>
|
||||||
|
|
||||||
|
<typedef name="scoped_lock">
|
||||||
|
<type><emphasis>implementation-defined</emphasis></type>
|
||||||
|
</typedef>
|
||||||
|
|
||||||
|
<constructor>
|
||||||
|
<parameter name="count">
|
||||||
|
<paramtype>boost::read_write_scheduling_policy</paramtype>
|
||||||
|
</parameter>
|
||||||
|
|
||||||
|
<effects>Constructs a <classname>read_write_mutex</classname> object.
|
||||||
|
</effects>
|
||||||
|
|
||||||
|
<postconditions><code>*this</code> is in an unlocked state.
|
||||||
|
</postconditions>
|
||||||
|
</constructor>
|
||||||
|
|
||||||
|
<destructor>
|
||||||
|
<effects>Destroys a <classname>read_write_mutex</classname> object.</effects>
|
||||||
|
|
||||||
|
<requires><code>*this</code> is in an unlocked state.</requires>
|
||||||
|
|
||||||
|
<notes><emphasis role="bold">Danger:</emphasis> Destruction of a
|
||||||
|
locked mutex is a serious programming error resulting in undefined
|
||||||
|
behavior such as a program crash.</notes>
|
||||||
|
</destructor>
|
||||||
|
</class>
|
||||||
|
|
||||||
|
<class name="try_read_write_mutex">
|
||||||
|
<purpose>
|
||||||
|
<para>The <classname>try_read_write_mutex</classname> class is a model of the
|
||||||
|
<link linkend="threads.concepts.TryReadWriteMutex">TryReadWriteMutex</link> concept.</para>
|
||||||
|
</purpose>
|
||||||
|
|
||||||
|
<description>
|
||||||
|
<para>The <classname>try_read_write_mutex</classname> class is a model of the
|
||||||
|
<link linkend="threads.concepts.TryReadWriteMutex">TryReadWriteMutex</link> concept.
|
||||||
|
It should be used to synchronize access to shared resources using
|
||||||
|
<link linkend="threads.concepts.read-write-locking-strategies.unspecified">Unspecified</link>
|
||||||
|
locking mechanics.</para>
|
||||||
|
|
||||||
|
<para>For classes that model related mutex concepts, see
|
||||||
|
<classname>read_write_mutex</classname> and <classname>timed_read_write_mutex</classname>.</para>
|
||||||
|
|
||||||
|
<para>The <classname>try_read_write_mutex</classname> class supplies the following typedefs,
|
||||||
|
which <link linkend="threads.concepts.read-write-lock-models">model</link>
|
||||||
|
the specified locking strategy:
|
||||||
|
|
||||||
|
<informaltable>
|
||||||
|
<tgroup cols="2" align="left">
|
||||||
|
<thead>
|
||||||
|
<row>
|
||||||
|
<entry>Lock Name</entry>
|
||||||
|
<entry>Lock Concept</entry>
|
||||||
|
</row>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<row>
|
||||||
|
<entry>scoped_lock</entry>
|
||||||
|
<entry><link linkend="threads.concepts.ScopedReadWriteLock">ScopedReadWriteLock</link></entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>scoped_try_lock</entry>
|
||||||
|
<entry><link linkend="threads.concepts.ScopedTryReadWriteLock">ScopedTryReadWriteLock</link></entry>
|
||||||
|
</row>
|
||||||
|
</tbody>
|
||||||
|
</tgroup>
|
||||||
|
</informaltable>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>The <classname>try_read_write_mutex</classname> class uses an
|
||||||
|
<link linkend="threads.concepts.read-write-locking-strategies.unspecified">Unspecified</link>
|
||||||
|
locking strategy, so attempts to recursively lock a <classname>try_read_write_mutex</classname>
|
||||||
|
object or attempts to unlock one by threads that don't own a lock on it result in
|
||||||
|
<emphasis role="bold">undefined behavior</emphasis>.
|
||||||
|
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.</para>
|
||||||
|
|
||||||
|
<para>Like all
|
||||||
|
<link linkend="threads.concepts.read-write-mutex-models">read/write mutex models</link>
|
||||||
|
in &Boost.Threads;, <classname>try_read_write_mutex</classname> has two types of
|
||||||
|
<link linkend="threads.concepts.read-write-scheduling-policies">scheduling policies</link>, an
|
||||||
|
<link linkend="threads.concepts.read-write-scheduling-policies.inter-class">inter-class sheduling policy</link>
|
||||||
|
between threads trying to obtain different types of locks and an
|
||||||
|
<link linkend="threads.concepts.read-write-scheduling-policies.intra-class">intra-class sheduling policy</link>
|
||||||
|
between threads trying to obtain the same type of lock.
|
||||||
|
The <classname>try_read_write_mutex</classname> class allows the
|
||||||
|
programmer to choose what
|
||||||
|
<link linkend="threads.concepts.read-write-scheduling-policies.inter-class">inter-class sheduling policy</link>
|
||||||
|
will be used; however, like all read/write mutex models,
|
||||||
|
<classname>try_read_write_mutex</classname> leaves the
|
||||||
|
<link linkend="threads.concepts.read-write-scheduling-policies.intra-class">intra-class sheduling policy</link> as
|
||||||
|
<link linkend="threads.concepts.unspecified-scheduling-policy">Unspecified</link>.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<note>Self-deadlock is virtually guaranteed if a thread tries to
|
||||||
|
lock the same <classname>try_read_write_mutex</classname> multiple times
|
||||||
|
unless all locks are read-locks (but see below)</note>
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<inherit access="private">
|
||||||
|
<type><classname>boost::noncopyable</classname></type>
|
||||||
|
<purpose>Exposition only</purpose>
|
||||||
|
</inherit>
|
||||||
|
|
||||||
|
<typedef name="scoped_lock">
|
||||||
|
<type><emphasis>implementation-defined</emphasis></type>
|
||||||
|
</typedef>
|
||||||
|
|
||||||
|
<typedef name="scoped_try_lock">
|
||||||
|
<type><emphasis>implementation-defined</emphasis></type>
|
||||||
|
</typedef>
|
||||||
|
|
||||||
|
<constructor>
|
||||||
|
<parameter name="count">
|
||||||
|
<paramtype>boost::read_write_scheduling_policy</paramtype>
|
||||||
|
</parameter>
|
||||||
|
|
||||||
|
<effects>Constructs a <classname>try_read_write_mutex</classname> object.
|
||||||
|
</effects>
|
||||||
|
|
||||||
|
<postconditions><code>*this</code> is in an unlocked state.
|
||||||
|
</postconditions>
|
||||||
|
</constructor>
|
||||||
|
|
||||||
|
<destructor>
|
||||||
|
<effects>Destroys a <classname>try_read_write_mutex</classname> object.</effects>
|
||||||
|
|
||||||
|
<requires><code>*this</code> is in an unlocked state.</requires>
|
||||||
|
|
||||||
|
<notes><emphasis role="bold">Danger:</emphasis> Destruction of a
|
||||||
|
locked mutex is a serious programming error resulting in undefined
|
||||||
|
behavior such as a program crash.</notes>
|
||||||
|
</destructor>
|
||||||
|
</class>
|
||||||
|
|
||||||
|
<class name="timed_read_write_mutex">
|
||||||
|
<purpose>
|
||||||
|
<para>The <classname>timed_read_write_mutex</classname> class is a model of the
|
||||||
|
<link linkend="threads.concepts.TimedReadWriteMutex">TimedReadWriteMutex</link> concept.</para>
|
||||||
|
</purpose>
|
||||||
|
|
||||||
|
<description>
|
||||||
|
<para>The <classname>timed_read_write_mutex</classname> class is a model of the
|
||||||
|
<link linkend="threads.concepts.TimedReadWriteMutex">TimedReadWriteMutex</link> concept.
|
||||||
|
It should be used to synchronize access to shared resources using
|
||||||
|
<link linkend="threads.concepts.read-write-locking-strategies.unspecified">Unspecified</link>
|
||||||
|
locking mechanics.</para>
|
||||||
|
|
||||||
|
<para>For classes that model related mutex concepts, see
|
||||||
|
<classname>read_write_mutex</classname> and <classname>try_read_write_mutex</classname>.</para>
|
||||||
|
|
||||||
|
<para>The <classname>timed_read_write_mutex</classname> class supplies the following typedefs,
|
||||||
|
which <link linkend="threads.concepts.read-write-lock-models">model</link>
|
||||||
|
the specified locking strategy:
|
||||||
|
|
||||||
|
<informaltable>
|
||||||
|
<tgroup cols="2" align="left">
|
||||||
|
<thead>
|
||||||
|
<row>
|
||||||
|
<entry>Lock Name</entry>
|
||||||
|
<entry>Lock Concept</entry>
|
||||||
|
</row>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<row>
|
||||||
|
<entry>scoped_lock</entry>
|
||||||
|
<entry><link linkend="threads.concepts.ScopedReadWriteLock">ScopedReadWriteLock</link></entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>scoped_try_lock</entry>
|
||||||
|
<entry><link linkend="threads.concepts.ScopedTryReadWriteLock">ScopedTryReadWriteLock</link></entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>scoped_timed_lock</entry>
|
||||||
|
<entry><link linkend="threads.concepts.ScopedTimedReadWriteLock">ScopedTimedReadWriteLock</link></entry>
|
||||||
|
</row>
|
||||||
|
</tbody>
|
||||||
|
</tgroup>
|
||||||
|
</informaltable>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>The <classname>timed_read_write_mutex</classname> class uses an
|
||||||
|
<link linkend="threads.concepts.read-write-locking-strategies.unspecified">Unspecified</link>
|
||||||
|
locking strategy, so attempts to recursively lock a <classname>timed_read_write_mutex</classname>
|
||||||
|
object or attempts to unlock one by threads that don't own a lock on it result in
|
||||||
|
<emphasis role="bold">undefined behavior</emphasis>.
|
||||||
|
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.</para>
|
||||||
|
|
||||||
|
<para>Like all
|
||||||
|
<link linkend="threads.concepts.read-write-mutex-models">read/write mutex models</link>
|
||||||
|
in &Boost.Threads;, <classname>timed_read_write_mutex</classname> has two types of
|
||||||
|
<link linkend="threads.concepts.read-write-scheduling-policies">scheduling policies</link>, an
|
||||||
|
<link linkend="threads.concepts.read-write-scheduling-policies.inter-class">inter-class sheduling policy</link>
|
||||||
|
between threads trying to obtain different types of locks and an
|
||||||
|
<link linkend="threads.concepts.read-write-scheduling-policies.intra-class">intra-class sheduling policy</link>
|
||||||
|
between threads trying to obtain the same type of lock.
|
||||||
|
The <classname>timed_read_write_mutex</classname> class allows the
|
||||||
|
programmer to choose what
|
||||||
|
<link linkend="threads.concepts.read-write-scheduling-policies.inter-class">inter-class sheduling policy</link>
|
||||||
|
will be used; however, like all read/write mutex models,
|
||||||
|
<classname>timed_read_write_mutex</classname> leaves the
|
||||||
|
<link linkend="threads.concepts.read-write-scheduling-policies.intra-class">intra-class sheduling policy</link> as
|
||||||
|
<link linkend="threads.concepts.unspecified-scheduling-policy">Unspecified</link>.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<note>Self-deadlock is virtually guaranteed if a thread tries to
|
||||||
|
lock the same <classname>timed_read_write_mutex</classname> multiple times
|
||||||
|
unless all locks are read-locks (but see below)</note>
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<typedef name="scoped_lock">
|
||||||
|
<type><emphasis>implementation-defined</emphasis></type>
|
||||||
|
</typedef>
|
||||||
|
|
||||||
|
<typedef name="scoped_try_lock">
|
||||||
|
<type><emphasis>implementation-defined</emphasis></type>
|
||||||
|
</typedef>
|
||||||
|
|
||||||
|
<typedef name="scoped_timed_lock">
|
||||||
|
<type><emphasis>implementation-defined</emphasis></type>
|
||||||
|
</typedef>
|
||||||
|
|
||||||
|
<constructor>
|
||||||
|
<parameter name="count">
|
||||||
|
<paramtype>boost::read_write_scheduling_policy</paramtype>
|
||||||
|
</parameter>
|
||||||
|
|
||||||
|
<effects>Constructs a <classname>timed_read_write_mutex</classname> object.
|
||||||
|
</effects>
|
||||||
|
|
||||||
|
<postconditions><code>*this</code> is in an unlocked state.
|
||||||
|
</postconditions>
|
||||||
|
</constructor>
|
||||||
|
|
||||||
|
<destructor>
|
||||||
|
<effects>Destroys a <classname>timed_read_write_mutex</classname> object.</effects>
|
||||||
|
|
||||||
|
<requires><code>*this</code> is in an unlocked state.</requires>
|
||||||
|
|
||||||
|
<notes><emphasis role="bold">Danger:</emphasis> Destruction of a
|
||||||
|
locked mutex is a serious programming error resulting in undefined
|
||||||
|
behavior such as a program crash.</notes>
|
||||||
|
</destructor>
|
||||||
|
</class>
|
||||||
|
</namespace>
|
||||||
|
</header>
|
||||||
302
doc/recursive_mutex-ref.xml
Normal file
302
doc/recursive_mutex-ref.xml
Normal file
@@ -0,0 +1,302 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
||||||
|
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
|
||||||
|
<!ENTITY % threads.entities SYSTEM "entities.xml">
|
||||||
|
%threads.entities;
|
||||||
|
]>
|
||||||
|
<header name="boost/thread/recursive_mutex.hpp"
|
||||||
|
last-revision="$Date$">
|
||||||
|
<namespace name="boost">
|
||||||
|
<class name="recursive_mutex">
|
||||||
|
<purpose>
|
||||||
|
<para>The <classname>recursive_mutex</classname> class is a model of the
|
||||||
|
<link linkend="threads.concepts.Mutex">Mutex</link> concept.</para>
|
||||||
|
</purpose>
|
||||||
|
|
||||||
|
<description>
|
||||||
|
<para>The <classname>recursive_mutex</classname> class is a model of the
|
||||||
|
<link linkend="threads.concepts.Mutex">Mutex</link> concept.
|
||||||
|
It should be used to synchronize access to shared resources using
|
||||||
|
<link linkend="threads.concepts.recursive-locking-strategy">Recursive</link>
|
||||||
|
locking mechanics.</para>
|
||||||
|
|
||||||
|
<para>For classes that model related mutex concepts, see
|
||||||
|
<classname>recursive_try_mutex</classname> and <classname>recursive_timed_mutex</classname>.</para>
|
||||||
|
|
||||||
|
<para>For <link linkend="threads.concepts.unspecified-locking-strategy">Unspecified</link>
|
||||||
|
locking mechanics, see <classname>mutex</classname>,
|
||||||
|
<classname>try_mutex</classname>, and <classname>timed_mutex</classname>.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>The <classname>recursive_mutex</classname> class supplies the following typedef,
|
||||||
|
which models the specified locking strategy:
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<title>Supported Lock Types</title>
|
||||||
|
<tgroup cols="2" align="left">
|
||||||
|
<thead>
|
||||||
|
<row>
|
||||||
|
<entry>Lock Name</entry>
|
||||||
|
<entry>Lock Concept</entry>
|
||||||
|
</row>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<row>
|
||||||
|
<entry>scoped_lock</entry>
|
||||||
|
<entry><link linkend="threads.concepts.ScopedLock">ScopedLock</link></entry>
|
||||||
|
</row>
|
||||||
|
</tbody>
|
||||||
|
</tgroup>
|
||||||
|
</table>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>The <classname>recursive_mutex</classname> class uses a
|
||||||
|
<link linkend="threads.concepts.recursive-locking-strategy">Recursive</link>
|
||||||
|
locking strategy, so attempts to recursively lock a
|
||||||
|
<classname>recursive_mutex</classname> object
|
||||||
|
succeed and an internal "lock count" is maintained.
|
||||||
|
Attempts to unlock a <classname>recursive_mutex</classname> object
|
||||||
|
by threads that don't own a lock on it result in
|
||||||
|
<emphasis role="bold">undefined behavior</emphasis>.</para>
|
||||||
|
|
||||||
|
<para>Like all
|
||||||
|
<link linkend="threads.concepts.mutex-models">mutex models</link>
|
||||||
|
in &Boost.Threads;, <classname>recursive_mutex</classname> leaves the
|
||||||
|
<link linkend="threads.concepts.sheduling-policies">scheduling policy</link>
|
||||||
|
as <link linkend="threads.concepts.unspecified-scheduling-policy">Unspecified</link>.
|
||||||
|
Programmers should make no assumptions about the order in which
|
||||||
|
waiting threads acquire a lock.</para>
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<inherit access="private">
|
||||||
|
<type><classname>boost::noncopyable</classname></type>
|
||||||
|
<purpose>Exposition only</purpose>
|
||||||
|
</inherit>
|
||||||
|
|
||||||
|
<typedef name="scoped_lock">
|
||||||
|
<type><emphasis>implementation-defined</emphasis></type>
|
||||||
|
</typedef>
|
||||||
|
|
||||||
|
<constructor>
|
||||||
|
<effects>Constructs a <classname>recursive_mutex</classname> object.
|
||||||
|
</effects>
|
||||||
|
|
||||||
|
<postconditions><code>*this</code> is in an unlocked state.
|
||||||
|
</postconditions>
|
||||||
|
</constructor>
|
||||||
|
|
||||||
|
<destructor>
|
||||||
|
<effects>Destroys a <classname>recursive_mutex</classname> object.</effects>
|
||||||
|
|
||||||
|
<requires><code>*this</code> is in an unlocked state.</requires>
|
||||||
|
|
||||||
|
<notes><emphasis role="bold">Danger:</emphasis> Destruction of a
|
||||||
|
locked mutex is a serious programming error resulting in undefined
|
||||||
|
behavior such as a program crash.</notes>
|
||||||
|
</destructor>
|
||||||
|
</class>
|
||||||
|
|
||||||
|
<class name="recursive_try_mutex">
|
||||||
|
<purpose>
|
||||||
|
<para>The <classname>recursive_try_mutex</classname> class is a model of the
|
||||||
|
<link linkend="threads.concepts.TryMutex">TryMutex</link> concept.</para>
|
||||||
|
</purpose>
|
||||||
|
|
||||||
|
<description>
|
||||||
|
<para>The <classname>recursive_try_mutex</classname> class is a model of the
|
||||||
|
<link linkend="threads.concepts.TryMutex">TryMutex</link> concept.
|
||||||
|
It should be used to synchronize access to shared resources using
|
||||||
|
<link linkend="threads.concepts.recursive-locking-strategy">Recursive</link>
|
||||||
|
locking mechanics.</para>
|
||||||
|
|
||||||
|
<para>For classes that model related mutex concepts, see
|
||||||
|
<classname>recursive_mutex</classname> and <classname>recursive_timed_mutex</classname>.</para>
|
||||||
|
|
||||||
|
<para>For <link linkend="threads.concepts.unspecified-locking-strategy">Unspecified</link>
|
||||||
|
locking mechanics, see <classname>mutex</classname>,
|
||||||
|
<classname>try_mutex</classname>, and <classname>timed_mutex</classname>.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>The <classname>recursive_try_mutex</classname> class supplies the following typedefs,
|
||||||
|
which model the specified locking strategies:
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<title>Supported Lock Types</title>
|
||||||
|
<tgroup cols="2" align="left">
|
||||||
|
<thead>
|
||||||
|
<row>
|
||||||
|
<entry>Lock Name</entry>
|
||||||
|
<entry>Lock Concept</entry>
|
||||||
|
</row>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<row>
|
||||||
|
<entry>scoped_lock</entry>
|
||||||
|
<entry><link linkend="threads.concepts.ScopedLock">ScopedLock</link></entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>scoped_try_lock</entry>
|
||||||
|
<entry><link linkend="threads.concepts.ScopedTryLock">ScopedTryLock</link></entry>
|
||||||
|
</row>
|
||||||
|
</tbody>
|
||||||
|
</tgroup>
|
||||||
|
</table>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>The <classname>recursive_try_mutex</classname> class uses a
|
||||||
|
<link linkend="threads.concepts.recursive-locking-strategy">Recursive</link>
|
||||||
|
locking strategy, so attempts to recursively lock a
|
||||||
|
<classname>recursive_try_mutex</classname> object
|
||||||
|
succeed and an internal "lock count" is maintained.
|
||||||
|
Attempts to unlock a <classname>recursive_mutex</classname> object
|
||||||
|
by threads that don't own a lock on it result in
|
||||||
|
<emphasis role="bold">undefined behavior</emphasis>.</para>
|
||||||
|
|
||||||
|
<para>Like all
|
||||||
|
<link linkend="threads.concepts.mutex-models">mutex models</link>
|
||||||
|
in &Boost.Threads;, <classname>recursive_try_mutex</classname> leaves the
|
||||||
|
<link linkend="threads.concepts.sheduling-policies">scheduling policy</link>
|
||||||
|
as <link linkend="threads.concepts.unspecified-scheduling-policy">Unspecified</link>.
|
||||||
|
Programmers should make no assumptions about the order in which
|
||||||
|
waiting threads acquire a lock.</para>
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<inherit access="private">
|
||||||
|
<type><classname>boost::noncopyable</classname></type>
|
||||||
|
<purpose>Exposition only</purpose>
|
||||||
|
</inherit>
|
||||||
|
|
||||||
|
<typedef name="scoped_lock">
|
||||||
|
<type><emphasis>implementation-defined</emphasis></type>
|
||||||
|
</typedef>
|
||||||
|
|
||||||
|
<typedef name="scoped_try_lock">
|
||||||
|
<type><emphasis>implementation-defined</emphasis></type>
|
||||||
|
</typedef>
|
||||||
|
|
||||||
|
<constructor>
|
||||||
|
<effects>Constructs a <classname>recursive_try_mutex</classname> object.
|
||||||
|
</effects>
|
||||||
|
|
||||||
|
<postconditions><code>*this</code> is in an unlocked state.
|
||||||
|
</postconditions>
|
||||||
|
</constructor>
|
||||||
|
|
||||||
|
<destructor>
|
||||||
|
<effects>Destroys a <classname>recursive_try_mutex</classname> object.
|
||||||
|
</effects>
|
||||||
|
|
||||||
|
<requires><code>*this</code> is in an unlocked state.</requires>
|
||||||
|
|
||||||
|
<notes><emphasis role="bold">Danger:</emphasis> Destruction of a
|
||||||
|
locked mutex is a serious programming error resulting in undefined
|
||||||
|
behavior such as a program crash.</notes>
|
||||||
|
</destructor>
|
||||||
|
</class>
|
||||||
|
|
||||||
|
<class name="recursive_timed_mutex">
|
||||||
|
<purpose>
|
||||||
|
<para>The <classname>recursive_timed_mutex</classname> class is a model of the
|
||||||
|
<link linkend="threads.concepts.TimedMutex">TimedMutex</link> concept.</para>
|
||||||
|
</purpose>
|
||||||
|
|
||||||
|
<description>
|
||||||
|
<para>The <classname>recursive_timed_mutex</classname> class is a model of the
|
||||||
|
<link linkend="threads.concepts.TimedMutex">TimedMutex</link> concept.
|
||||||
|
It should be used to synchronize access to shared resources using
|
||||||
|
<link linkend="threads.concepts.recursive-locking-strategy">Recursive</link>
|
||||||
|
locking mechanics.</para>
|
||||||
|
|
||||||
|
<para>For classes that model related mutex concepts, see
|
||||||
|
<classname>recursive_mutex</classname> and <classname>recursive_try_mutex</classname>.</para>
|
||||||
|
|
||||||
|
<para>For <link linkend="threads.concepts.unspecified-locking-strategy">Unspecified</link>
|
||||||
|
locking mechanics, see <classname>mutex</classname>,
|
||||||
|
<classname>try_mutex</classname>, and <classname>timed_mutex</classname>.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>The <classname>recursive_timed_mutex</classname> class supplies the following typedefs,
|
||||||
|
which model the specified locking strategies:
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<title>Supported Lock Types</title>
|
||||||
|
<tgroup cols="2" align="left">
|
||||||
|
<thead>
|
||||||
|
<row>
|
||||||
|
<entry>Lock Name</entry>
|
||||||
|
<entry>Lock Concept</entry>
|
||||||
|
</row>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<row>
|
||||||
|
<entry>scoped_lock</entry>
|
||||||
|
<entry><link linkend="threads.concepts.ScopedLock">ScopedLock</link></entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>scoped_try_lock</entry>
|
||||||
|
<entry><link linkend="threads.concepts.ScopedTryLock">ScopedTryLock</link></entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>scoped_timed_lock</entry>
|
||||||
|
<entry><link linkend="threads.concepts.ScopedTimedLock">ScopedTimedLock</link></entry>
|
||||||
|
</row>
|
||||||
|
</tbody>
|
||||||
|
</tgroup>
|
||||||
|
</table>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>The <classname>recursive_timed_mutex</classname> class uses a
|
||||||
|
<link linkend="threads.concepts.recursive-locking-strategy">Recursive</link>
|
||||||
|
locking strategy, so attempts to recursively lock a
|
||||||
|
<classname>recursive_timed_mutex</classname> object
|
||||||
|
succeed and an internal "lock count" is maintained.
|
||||||
|
Attempts to unlock a <classname>recursive_mutex</classname> object
|
||||||
|
by threads that don't own a lock on it result in
|
||||||
|
<emphasis role="bold">undefined behavior</emphasis>.</para>
|
||||||
|
|
||||||
|
<para>Like all
|
||||||
|
<link linkend="threads.concepts.mutex-models">mutex models</link>
|
||||||
|
in &Boost.Threads;, <classname>recursive_timed_mutex</classname> leaves the
|
||||||
|
<link linkend="threads.concepts.sheduling-policies">scheduling policy</link>
|
||||||
|
as <link linkend="threads.concepts.unspecified-scheduling-policy">Unspecified</link>.
|
||||||
|
Programmers should make no assumptions about the order in which
|
||||||
|
waiting threads acquire a lock.</para>
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<inherit access="private">
|
||||||
|
<type><classname>boost::noncopyable</classname></type>
|
||||||
|
<purpose>Exposition only</purpose>
|
||||||
|
</inherit>
|
||||||
|
|
||||||
|
<typedef name="scoped_lock">
|
||||||
|
<type><emphasis>implementation-defined</emphasis></type>
|
||||||
|
</typedef>
|
||||||
|
|
||||||
|
<typedef name="scoped_try_lock">
|
||||||
|
<type><emphasis>implementation-defined</emphasis></type>
|
||||||
|
</typedef>
|
||||||
|
|
||||||
|
<typedef name="scoped_timed_lock">
|
||||||
|
<type><emphasis>implementation-defined</emphasis></type>
|
||||||
|
</typedef>
|
||||||
|
|
||||||
|
<constructor>
|
||||||
|
<effects>Constructs a <classname>recursive_timed_mutex</classname> object.
|
||||||
|
</effects>
|
||||||
|
|
||||||
|
<postconditions><code>*this</code> is in an unlocked state.
|
||||||
|
</postconditions>
|
||||||
|
</constructor>
|
||||||
|
|
||||||
|
<destructor>
|
||||||
|
<effects>Destroys a <classname>recursive_timed_mutex</classname> object.</effects>
|
||||||
|
|
||||||
|
<requires><code>*this</code> is in an unlocked state.</requires>
|
||||||
|
|
||||||
|
<notes><emphasis role="bold">Danger:</emphasis> Destruction of a
|
||||||
|
locked mutex is a serious programming error resulting in undefined
|
||||||
|
behavior such as a program crash.</notes>
|
||||||
|
</destructor>
|
||||||
|
</class>
|
||||||
|
</namespace>
|
||||||
|
</header>
|
||||||
@@ -1,244 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
|
||||||
<link rel="stylesheet" type="text/css" href="../../../boost.css">
|
|
||||||
<title>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>
|
|
||||||
<p><a href="../example/recursive_mutex.cpp">libs/thread/example/recursive_mutex.cpp</a></p>
|
|
||||||
<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>
|
|
||||||
20
doc/reference.xml
Normal file
20
doc/reference.xml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
||||||
|
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
|
||||||
|
<!ENTITY % threads.entities SYSTEM "entities.xml">
|
||||||
|
%threads.entities;
|
||||||
|
]>
|
||||||
|
<library-reference id="threads.reference"
|
||||||
|
last-revision="$Date$"
|
||||||
|
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||||
|
<xi:include href="barrier-ref.xml"/>
|
||||||
|
<xi:include href="condition-ref.xml"/>
|
||||||
|
<xi:include href="exceptions-ref.xml"/>
|
||||||
|
<xi:include href="mutex-ref.xml"/>
|
||||||
|
<xi:include href="once-ref.xml"/>
|
||||||
|
<xi:include href="recursive_mutex-ref.xml"/>
|
||||||
|
<xi:include href="read_write_mutex-ref.xml"/>
|
||||||
|
<xi:include href="thread-ref.xml"/>
|
||||||
|
<xi:include href="tss-ref.xml"/>
|
||||||
|
<xi:include href="xtime-ref.xml"/>
|
||||||
|
</library-reference>
|
||||||
112
doc/release_notes.xml
Normal file
112
doc/release_notes.xml
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
||||||
|
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
|
||||||
|
<!ENTITY % threads.entities SYSTEM "entities.xml">
|
||||||
|
%threads.entities;
|
||||||
|
]>
|
||||||
|
<section id="threads.release_notes" last-revision="$Date$">
|
||||||
|
<title>Release Notes</title>
|
||||||
|
<section id="threads.release_notes.boost_1_32_0">
|
||||||
|
<title>Boost 1.32.0</title>
|
||||||
|
|
||||||
|
<section id="threads.release_notes.boost_1_32_0.change_log.documentation">
|
||||||
|
<title>Documentation converted to BoostBook</title>
|
||||||
|
|
||||||
|
<para>The documentation was converted to BoostBook format,
|
||||||
|
and a number of errors and inconsistencies were
|
||||||
|
fixed in the process.
|
||||||
|
Since this was a fairly large task, there are likely to be
|
||||||
|
more errors and inconsistencies remaining. If you find any,
|
||||||
|
please report them!</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id="threads.release_notes.boost_1_32_0.change_log.static_link">
|
||||||
|
<title>Static-link build option added</title>
|
||||||
|
|
||||||
|
<para>The option to link &Boost.Threads; as a static
|
||||||
|
library has been added back with some limitations.
|
||||||
|
This feature was originally removed because
|
||||||
|
<classname>boost::thread_specific_ptr</classname> required
|
||||||
|
that &Boost.Threads; be dynamically linked in order for its
|
||||||
|
cleanup functionality to work on Win32 platforms.
|
||||||
|
Several options are currently being explored to resolve
|
||||||
|
this issue. In the meantime, the ability to link
|
||||||
|
&Boost.Threads; statically has been added back
|
||||||
|
<emphasis>with <classname>boost::thread_specific_ptr</classname>
|
||||||
|
support removed</emphasis> from the statically linked version.
|
||||||
|
The decision to add it back was made because its lack is
|
||||||
|
one of the most frequent complaints about &Boost.Threads;
|
||||||
|
and because the other approaches that are being investigated
|
||||||
|
to deal with <classname>boost::thread_specific_ptr</classname>
|
||||||
|
cleanup look fairly promising.
|
||||||
|
<note>&Boost.Threads; is still dynamically linked by default.
|
||||||
|
In order to force it to be statically linked, it is necessary to
|
||||||
|
#define BOOST_THREAD_USE_LIB before any of the &Boost.Threads;
|
||||||
|
header files are #included.</note>
|
||||||
|
<note>If the <classname>boost::thread_specific_ptr</classname> cleanup
|
||||||
|
issue cannot be resolved by some other means, it is highly
|
||||||
|
likely that the option to statically link &Boost.Threads;
|
||||||
|
will be removed again in a future version of Boost, at least
|
||||||
|
for Win32 platforms. This is because the
|
||||||
|
<classname>boost::thread_specific_ptr</classname> functionality
|
||||||
|
will be increasingly used by &Boost.Threads; itself,
|
||||||
|
so that proper cleanup will become essential
|
||||||
|
in future versions of &Boost.Threads;.</note>
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id="threads.release_notes.boost_1_32_0.change_log.barrier">
|
||||||
|
<title>Barrier functionality added</title>
|
||||||
|
|
||||||
|
<para>A new class, <classname>boost::barrier</classname>, was added.</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id="threads.release_notes.boost_1_32_0.change_log.read_write_mutex">
|
||||||
|
<title>Read/write mutex functionality added</title>
|
||||||
|
|
||||||
|
<para>New classes,
|
||||||
|
<classname>boost::read_write_mutex</classname>,
|
||||||
|
<classname>boost::try_read_write_mutex</classname>, and
|
||||||
|
<classname>boost::timed_read_write_mutex</classname>
|
||||||
|
were added.</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id="threads.release_notes.boost_1_32_0.change_log.thread_specific_ptr">
|
||||||
|
<title>Thread-specific pointer functionality changed</title>
|
||||||
|
|
||||||
|
<para>The <classname>boost::thread_specific_ptr</classname>
|
||||||
|
constructor now takes an optional pointer to a cleanup function that
|
||||||
|
is called to release the thread-specific data that is being pointed
|
||||||
|
to by <classname>boost::thread_specific_ptr</classname> objects.</para>
|
||||||
|
|
||||||
|
<para>Fixed: the number of available thread-specific storage "slots"
|
||||||
|
is too small on some platforms.</para>
|
||||||
|
|
||||||
|
<para>Fixed: <functionname>thread_specific_ptr::reset()</functionname>
|
||||||
|
doesn't check error returned by <functionname>tss::set()</functionname>
|
||||||
|
(the <functionname>tss::set()</functionname> function now throws
|
||||||
|
if it fails instead of returning an error code).</para>
|
||||||
|
|
||||||
|
<para>Fixed: calling
|
||||||
|
<functionname>boost::thread_specific_ptr::reset()</functionname> or
|
||||||
|
<functionname>boost::thread_specific_ptr::release()</functionname>
|
||||||
|
causes double-delete: once when
|
||||||
|
<functionname>boost::thread_specific_ptr::reset()</functionname> or
|
||||||
|
<functionname>boost::thread_specific_ptr::release()</functionname>
|
||||||
|
is called and once when
|
||||||
|
<functionname>boost::thread_specific_ptr::~thread_specific_ptr()</functionname>
|
||||||
|
is called.</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id="threads.release_notes.boost_1_32_0.change_log.mutex">
|
||||||
|
<title>Mutex implementation changed for Win32</title>
|
||||||
|
|
||||||
|
<para>On Win32, <classname>boost::mutex</classname>,
|
||||||
|
<classname>boost::try_mutex</classname>, <classname>boost::recursive_mutex</classname>,
|
||||||
|
and <classname>boost::recursive_try_mutex</classname> now use a Win32 critical section
|
||||||
|
whenever possible; otherwise they use a Win32 mutex. As before,
|
||||||
|
<classname>boost::timed_mutex</classname> and
|
||||||
|
<classname>boost::recursive_timed_mutex</classname> use a Win32 mutex.</para>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
266
doc/thread-ref.xml
Normal file
266
doc/thread-ref.xml
Normal file
@@ -0,0 +1,266 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
||||||
|
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
|
||||||
|
<!ENTITY % threads.entities SYSTEM "entities.xml">
|
||||||
|
%threads.entities;
|
||||||
|
]>
|
||||||
|
<header name="boost/thread/thread.hpp"
|
||||||
|
last-revision="$Date$">
|
||||||
|
<namespace name="boost">
|
||||||
|
<class name="thread">
|
||||||
|
<purpose>
|
||||||
|
<para>The <classname>thread</classname> class represents threads of
|
||||||
|
execution, and provides the functionality to create and manage
|
||||||
|
threads within the &Boost.Threads; library. See
|
||||||
|
<xref linkend="threads.glossary"/> for a precise description of
|
||||||
|
<link linkend="threads.glossary.thread">thread of execution</link>,
|
||||||
|
and for definitions of threading-related terms and of thread states such as
|
||||||
|
<link linkend="threads.glossary.thread-state">blocked</link>.</para>
|
||||||
|
</purpose>
|
||||||
|
|
||||||
|
<description>
|
||||||
|
<para>A <link linkend="threads.glossary.thread">thread of execution</link>
|
||||||
|
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 <classname>thread</classname> object's constructor.</para>
|
||||||
|
|
||||||
|
<para>A thread of execution is said to be "finished"
|
||||||
|
or to have "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.</para>
|
||||||
|
|
||||||
|
<para>A thread object has an associated state which is either
|
||||||
|
"joinable" or "non-joinable".</para>
|
||||||
|
|
||||||
|
<para>Except as described below, the policy used by an implementation
|
||||||
|
of &Boost.Threads; to schedule transitions between thread states is
|
||||||
|
unspecified.</para>
|
||||||
|
|
||||||
|
<para><note>Just as the lifetime of a file may be different from the
|
||||||
|
lifetime of an <code>iostream</code> object which represents the file, the lifetime
|
||||||
|
of a thread of execution may be different from the
|
||||||
|
<classname>thread</classname> 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
|
||||||
|
<classname>thread</classname> object continues to exist until the
|
||||||
|
end of its normal lifetime. The converse is also possible; if
|
||||||
|
a <classname>thread</classname> object is destroyed without
|
||||||
|
<code>join()</code> first having been called, the thread of execution
|
||||||
|
continues until its initial function completes.</note></para>
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<inherit access="private">
|
||||||
|
<type><classname>boost::noncopyable</classname></type>
|
||||||
|
<purpose>Exposition only</purpose>
|
||||||
|
</inherit>
|
||||||
|
|
||||||
|
<constructor>
|
||||||
|
<effects>Constructs a <classname>thread</classname> object
|
||||||
|
representing the current thread of execution.</effects>
|
||||||
|
|
||||||
|
<postconditions><code>*this</code> is non-joinable.</postconditions>
|
||||||
|
|
||||||
|
<notes><emphasis role="bold">Danger:</emphasis>
|
||||||
|
<code>*this</code> is valid only within the current thread.</notes>
|
||||||
|
</constructor>
|
||||||
|
|
||||||
|
<constructor specifiers="explicit">
|
||||||
|
<parameter name="threadfunc">
|
||||||
|
<paramtype>const boost::function0<void>&</paramtype>
|
||||||
|
</parameter>
|
||||||
|
|
||||||
|
<effects>
|
||||||
|
Starts a new thread of execution and constructs a
|
||||||
|
<classname>thread</classname> 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.
|
||||||
|
</effects>
|
||||||
|
|
||||||
|
<postconditions><code>*this</code> is joinable.</postconditions>
|
||||||
|
|
||||||
|
<throws><code>boost::thread_resource_error</code> if a new thread
|
||||||
|
of execution cannot be started.</throws>
|
||||||
|
</constructor>
|
||||||
|
|
||||||
|
<destructor>
|
||||||
|
<effects>Destroys <code>*this</code>. The actual thread of
|
||||||
|
execution may continue to execute after the
|
||||||
|
<classname>thread</classname> object has been destroyed.
|
||||||
|
</effects>
|
||||||
|
|
||||||
|
<notes>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 <classname>thread</classname> object is destroyed, call
|
||||||
|
<code>join()</code>.</notes>
|
||||||
|
</destructor>
|
||||||
|
|
||||||
|
<method-group name="comparison">
|
||||||
|
<method name="operator==" cv="const">
|
||||||
|
<type>bool</type>
|
||||||
|
|
||||||
|
<parameter name="rhs">
|
||||||
|
<type>const thread&</type>
|
||||||
|
</parameter>
|
||||||
|
|
||||||
|
<requires>The thread is non-terminated or <code>*this</code>
|
||||||
|
is joinable.</requires>
|
||||||
|
|
||||||
|
<returns><code>true</code> if <code>*this</code> and
|
||||||
|
<code>rhs</code> represent the same thread of
|
||||||
|
execution.</returns>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="operator!=" cv="const">
|
||||||
|
<type>bool</type>
|
||||||
|
|
||||||
|
<parameter name="rhs">
|
||||||
|
<type>const thread&</type>
|
||||||
|
</parameter>
|
||||||
|
|
||||||
|
<requires>The thread is non-terminated or <code>*this</code>
|
||||||
|
is joinable.</requires>
|
||||||
|
|
||||||
|
<returns><code>!(*this==rhs)</code>.</returns>
|
||||||
|
</method>
|
||||||
|
</method-group>
|
||||||
|
|
||||||
|
<method-group name="modifier">
|
||||||
|
<method name="join">
|
||||||
|
<type>void</type>
|
||||||
|
|
||||||
|
<requires><code>*this</code> is joinable.</requires>
|
||||||
|
|
||||||
|
<effects>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.</effects>
|
||||||
|
|
||||||
|
<postcondition><code>*this</code> is non-joinable.</postcondition>
|
||||||
|
|
||||||
|
<notes>If <code>*this == thread()</code> the result is
|
||||||
|
implementation-defined. If the implementation doesn't
|
||||||
|
detect this the result will be
|
||||||
|
<link linkend="threads.glossary.deadlock">deadlock</link>.
|
||||||
|
</notes>
|
||||||
|
</method>
|
||||||
|
</method-group>
|
||||||
|
|
||||||
|
<method-group name="static">
|
||||||
|
<method name="sleep" specifiers="static">
|
||||||
|
<type>void</type>
|
||||||
|
|
||||||
|
<parameter name="xt">
|
||||||
|
<paramtype>const <classname>xtime</classname>&</paramtype>
|
||||||
|
</parameter>
|
||||||
|
|
||||||
|
<effects>The current thread of execution blocks until
|
||||||
|
<code>xt</code> is reached.</effects>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="yield" specifiers="static">
|
||||||
|
<type>void</type>
|
||||||
|
|
||||||
|
<effects>The current thread of execution is placed in the
|
||||||
|
<link linkend="threads.glossary.thread-state">ready</link>
|
||||||
|
state.</effects>
|
||||||
|
|
||||||
|
<notes>
|
||||||
|
<simpara>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.</simpara>
|
||||||
|
</notes>
|
||||||
|
</method>
|
||||||
|
</method-group>
|
||||||
|
</class>
|
||||||
|
|
||||||
|
<class name="thread_group">
|
||||||
|
<purpose>
|
||||||
|
The <classname>thread_group</classname> class provides a container
|
||||||
|
for easy grouping of threads to simplify several common thread
|
||||||
|
creation and management idioms.
|
||||||
|
</purpose>
|
||||||
|
|
||||||
|
<inherit access="private">
|
||||||
|
<type><classname>boost::noncopyable</classname></type>
|
||||||
|
<purpose>Exposition only</purpose>
|
||||||
|
</inherit>
|
||||||
|
|
||||||
|
|
||||||
|
<constructor>
|
||||||
|
<effects>Constructs an empty <classname>thread_group</classname>
|
||||||
|
container.</effects>
|
||||||
|
</constructor>
|
||||||
|
|
||||||
|
<destructor>
|
||||||
|
<effects>Destroys each contained thread object. Destroys <code>*this</code>.</effects>
|
||||||
|
|
||||||
|
<notes>Behavior is undefined if another thread references
|
||||||
|
<code>*this </code> during the execution of the destructor.
|
||||||
|
</notes>
|
||||||
|
</destructor>
|
||||||
|
|
||||||
|
<method-group name="modifier">
|
||||||
|
<method name="create_thread">
|
||||||
|
<type><classname>thread</classname>*</type>
|
||||||
|
|
||||||
|
<parameter name="threadfunc">
|
||||||
|
<paramtype>const boost::function0<void>&</paramtype>
|
||||||
|
</parameter>
|
||||||
|
|
||||||
|
<effects>Creates a new <classname>thread</classname> object
|
||||||
|
that executes <code>threadfunc</code> and adds it to the
|
||||||
|
<code>thread_group</code> container object's list of managed
|
||||||
|
<classname>thread</classname> objects.</effects>
|
||||||
|
|
||||||
|
<returns>Pointer to the newly created
|
||||||
|
<classname>thread</classname> object.</returns>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="add_thread">
|
||||||
|
<type>void</type>
|
||||||
|
|
||||||
|
<parameter name="thrd">
|
||||||
|
<paramtype><classname>thread</classname>* thrd</paramtype>
|
||||||
|
</parameter>
|
||||||
|
|
||||||
|
<effects>Adds <code>thrd</code> to the
|
||||||
|
<classname>thread_group</classname> object's list of managed
|
||||||
|
<classname>thread</classname> objects. The <code>thrd</code>
|
||||||
|
object must have been allocated via <code>operator new</code> and will
|
||||||
|
be deleted when the group is destroyed.</effects>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="remove_thread">
|
||||||
|
<type>void</type>
|
||||||
|
|
||||||
|
<parameter name="thrd">
|
||||||
|
<paramtype><classname>thread</classname>* thrd</paramtype>
|
||||||
|
</parameter>
|
||||||
|
|
||||||
|
<effects>Removes <code>thread</code> from <code>*this</code>'s
|
||||||
|
list of managed <classname>thread</classname> objects.</effects>
|
||||||
|
|
||||||
|
<throws><emphasis role="bold">???</emphasis> if
|
||||||
|
<code>thrd</code> is not in <code>*this</code>'s list
|
||||||
|
of managed <classname>thread</classname> objects.</throws>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="join_all">
|
||||||
|
<type>void</type>
|
||||||
|
|
||||||
|
<effects>Calls <code>join()</code> on each of the managed
|
||||||
|
<classname>thread</classname> objects.</effects>
|
||||||
|
</method>
|
||||||
|
</method-group>
|
||||||
|
</class>
|
||||||
|
</namespace>
|
||||||
|
</header>
|
||||||
323
doc/thread.html
323
doc/thread.html
@@ -1,323 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
|
||||||
<link rel="stylesheet" type="text/css" href="../../../boost.css">
|
|
||||||
<title>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>
|
|
||||||
<p><a href="../example/thread.cpp">libs/thread/example/thread.cpp</a></p>
|
|
||||||
<p>The output is:</p>
|
|
||||||
<pre>
|
|
||||||
setting alarm for 5 seconds...
|
|
||||||
alarm sounded...
|
|
||||||
</pre>
|
|
||||||
<h3><a name="example-thread_group"></a>Simple usage of <code>boost::thread_group</code></h3>
|
|
||||||
<p><a href="../example/thread_group.cpp">libs/thread/example/thread_group.cpp</a></p>
|
|
||||||
<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>
|
|
||||||
54
doc/thread.xml
Normal file
54
doc/thread.xml
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
||||||
|
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
|
||||||
|
<!ENTITY % threads.entities SYSTEM "entities.xml">
|
||||||
|
%threads.entities;
|
||||||
|
]>
|
||||||
|
<library name="Threads" dirname="thread" id="threads"
|
||||||
|
last-revision="$Date$"
|
||||||
|
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||||
|
<libraryinfo>
|
||||||
|
<author>
|
||||||
|
<firstname>William</firstname>
|
||||||
|
<othername>E.</othername>
|
||||||
|
<surname>Kempf</surname>
|
||||||
|
</author>
|
||||||
|
|
||||||
|
<copyright>
|
||||||
|
<year>2001</year>
|
||||||
|
<year>2002</year>
|
||||||
|
<year>2003</year>
|
||||||
|
<holder>William E. Kempf</holder>
|
||||||
|
</copyright>
|
||||||
|
|
||||||
|
<legalnotice>
|
||||||
|
<para>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.</para>
|
||||||
|
</legalnotice>
|
||||||
|
|
||||||
|
<librarypurpose>Portable C++ multi-threading</librarypurpose>
|
||||||
|
|
||||||
|
<librarycategory name="category:concurrent" />
|
||||||
|
|
||||||
|
<title>Boost.Threads</title>
|
||||||
|
</libraryinfo>
|
||||||
|
<title>&Boost.Threads;</title>
|
||||||
|
<xi:include href="overview.xml"/>
|
||||||
|
<xi:include href="design.xml"/>
|
||||||
|
<xi:include href="concepts.xml"/>
|
||||||
|
<xi:include href="rationale.xml"/>
|
||||||
|
<xi:include href="reference.xml"/>
|
||||||
|
<xi:include href="faq.xml"/>
|
||||||
|
<xi:include href="configuration.xml"/>
|
||||||
|
<xi:include href="build.xml"/>
|
||||||
|
<xi:include href="implementation_notes.xml"/>
|
||||||
|
<xi:include href="release_notes.xml"/>
|
||||||
|
<xi:include href="glossary.xml"/>
|
||||||
|
<xi:include href="acknowledgements.xml"/>
|
||||||
|
<xi:include href="bibliography.xml"/>
|
||||||
|
</library>
|
||||||
13
doc/thread_pool-ref.xml
Normal file
13
doc/thread_pool-ref.xml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
||||||
|
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
|
||||||
|
<!ENTITY % threads.entities SYSTEM "entities.xml">
|
||||||
|
%threads.entities;
|
||||||
|
]>
|
||||||
|
<header name="boost/thread/thread_pool.hpp"
|
||||||
|
last-revision="$Date$">
|
||||||
|
<namespace name="boost">
|
||||||
|
<class name="thread_pool">
|
||||||
|
</class>
|
||||||
|
</namespace>
|
||||||
|
</header>
|
||||||
207
doc/thread_pool.html
Normal file
207
doc/thread_pool.html
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||||
|
<link rel="stylesheet" type="text/css" href="../../../boost.css">
|
||||||
|
<title>Boost.Threads - Header <boost/thread/thread_pool.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_pool.hpp">boost/thread/thread_pool.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_pool">Class <code>thread_pool</code></a></dt>
|
||||||
|
<dl class="page-index">
|
||||||
|
<dt><a href="#class-thread_pool-synopsis">Class <code>thread_pool</code> synopsis</a></dt>
|
||||||
|
<dt><a href="#class-thread_pool-ctors">Class <code>thread_pool</code> constructors and destructor</a></dt>
|
||||||
|
<dt><a href="#class-thread_pool-modifiers">Class <code>thread_pool</code> modifier functions</a></dt>
|
||||||
|
</dl>
|
||||||
|
</dl>
|
||||||
|
<dt><a href="#examples">Example(s)</a></dt>
|
||||||
|
</dl>
|
||||||
|
<hr>
|
||||||
|
<h2><a name="introduction"></a>Introduction</h2>
|
||||||
|
<p>Include the header <<a href="../../../boost/thread/thread_pool.hpp">boost/thread/thread_pool.hpp</a>>
|
||||||
|
to define the <a href="#class-thread_pool">thread_pool</a> class.</p>
|
||||||
|
<h2><a name="classes"></a>Classes</h2>
|
||||||
|
<h3><a name="class-thread_pool"></a>Class <code>thread_pool</code></h3>
|
||||||
|
|
||||||
|
<p>The <tt>thread_pool</tt> class provides an interface for running
|
||||||
|
jobs on a dynamically managed set of worker threads called a pool.
|
||||||
|
When a job is added, it can execute on any available thread in the pool.
|
||||||
|
This class controls both the maximum and minimum number of threads in
|
||||||
|
the pool. If a thread in the pool is sitting idle for a period of
|
||||||
|
time, it will exit unless by exiting the number of threads would dip below
|
||||||
|
the minimum. Thread pools provide an optimization over creating a new thread
|
||||||
|
for each job since the pool can often remove the overhead of thread creation.</p>
|
||||||
|
<h4><a name="class-thread_pool-synopsis"></a>Class <code>thread_pool</code> synopsis</h4>
|
||||||
|
<pre>
|
||||||
|
namespace boost
|
||||||
|
{
|
||||||
|
class thread_pool : <a href="../../utility/utility.htm#Class noncopyable">boost::noncopyable</a> // Exposition only.
|
||||||
|
// Class thread meets the <a href="overview.html#non-copyable">NonCopyable</a> requirement.
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
thread_pool(int max_threads=std::numeric_limits<int>::max(),
|
||||||
|
int min_threads=0,
|
||||||
|
int timeout_secs=5);
|
||||||
|
~thread_pool();
|
||||||
|
|
||||||
|
void add(const boost::function0<void> &job);
|
||||||
|
void join();
|
||||||
|
void cancel();
|
||||||
|
void detach();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
</pre>
|
||||||
|
<h4><a name="class-spec-ctors"></a>Class <code>thread_pool</code> constructors and destructor</h4>
|
||||||
|
<pre>
|
||||||
|
thread_pool(int max_threads=std::numeric_limits<int>::max(),
|
||||||
|
int min_threads=0,
|
||||||
|
int timeout_secs=5);
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<dt><b>Effects:</b> Constructs a thread pool object and starts min_threads threads
|
||||||
|
running in the pool.</dt>
|
||||||
|
</dl>
|
||||||
|
<pre>
|
||||||
|
~thread_pool();
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<dt><b>Effects:</b> Calls join() if neither join() nor detach() were called
|
||||||
|
previously for this thread_pool. If detach() was not called, destroys all
|
||||||
|
resources associated with the threads in the pool and with the queue of jobs
|
||||||
|
still waiting to be executed.</dt>
|
||||||
|
</dl>
|
||||||
|
<h4><a name="class-spec-modifiers"></a>Class <code>thread_pool</code> modifier
|
||||||
|
functions</h4>
|
||||||
|
<pre>
|
||||||
|
void add(const boost::function0<void>& job);
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<dt><b>Effects:</b> Adds <tt>job</tt> to the <tt>thread_pool</tt> object's list of
|
||||||
|
jobs waiting to be executed. If any threads in the pool are idle, the job
|
||||||
|
will be execute as soon as the idle thread is scheduled by the operating
|
||||||
|
system. If no threads are idle and the number of threads in the pool is
|
||||||
|
less than the maximum number provided to the constructor, an additional thread
|
||||||
|
is created and added to the pool. That new thread will execute this job
|
||||||
|
as soon as it is scheduled by the operating system. If no threads are
|
||||||
|
idle and the thread count is at the maximum, this job will be queued until
|
||||||
|
a thread becomes available. Currently, queued jobs are processed in FIFO
|
||||||
|
order.</dt>
|
||||||
|
<dt><b>Throws:</b> std::runtime_error if join() or detach() have
|
||||||
|
previously been called for this thread_pool object.</dt>
|
||||||
|
</dl>
|
||||||
|
<pre>
|
||||||
|
void detach();
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<dt><b>Effects:</b> Relinquishes control of the pool of threads by this thread_pool
|
||||||
|
object. Any threads in the pool will continue to run and continue to
|
||||||
|
process any queued jobs, but no new threads will be created, and any subsequent
|
||||||
|
attempts to add new jobs will result in an exception.</dt>
|
||||||
|
<dt><b>Throws:</b> std::runtime_error if join() has previously
|
||||||
|
been called for this thread_pool object.</dt>
|
||||||
|
</dl>
|
||||||
|
<pre>
|
||||||
|
void cancel();
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<dt><b>Effects:</b> Removes all queued jobs from the thread_pool's internal queue,
|
||||||
|
and calls cancel() on all boost::thread objects in the pool. The specific
|
||||||
|
behavior of those threads will be dictated by their cancellation behavior - the
|
||||||
|
pool threads may be executing a user's job that deferrs cancellation, for
|
||||||
|
example.</dt>
|
||||||
|
<dt><b>Throws:</b> std::runtime_error if join() or detach() have
|
||||||
|
previously been called for this thread_pool object.</dt>
|
||||||
|
<dt><b>Note:</b> for the current version (1.27.0) of Boost.Threads, thread::cancel() is
|
||||||
|
not provided. This function -will- clear out all queued jobs, but any
|
||||||
|
currently executing jobs will not be cancelled.</dt>
|
||||||
|
</dl>
|
||||||
|
<pre>
|
||||||
|
void join();
|
||||||
|
</pre>
|
||||||
|
<dl class="function-semantics">
|
||||||
|
<dt><b>Effects:</b> Waits until all queued jobs are completed by the thread pool,
|
||||||
|
and then join()s will all of the threads in the pool. When join()
|
||||||
|
returns, no running threads will remain in the pool, and this object is invalid
|
||||||
|
for anything except destruction. Any calls to cancel(), join(), detach(),
|
||||||
|
or add() will result in an exception.</dt>
|
||||||
|
</dl>
|
||||||
|
<h2><a name="examples"></a>Example(s)</h2>
|
||||||
|
<pre>
|
||||||
|
#include <boost/thread/thread_pool.hpp>
|
||||||
|
#include <boost/thread/mutex.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
boost::mutex io_mutex;
|
||||||
|
|
||||||
|
class job_adapter {
|
||||||
|
public:
|
||||||
|
job_adapter(void (*func)(int), int param) :
|
||||||
|
_func(func), _param(param){ }
|
||||||
|
void operator()() const { _func(_param); }
|
||||||
|
private:
|
||||||
|
void (*_func)(int);
|
||||||
|
int _param;
|
||||||
|
};
|
||||||
|
|
||||||
|
void simple_job(int param)
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock l(io_mutex);
|
||||||
|
std::cout << param << " squared is " << (param*param) << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
boost::thread_pool tp;
|
||||||
|
for (int i = 1; i <= 10; ++i)
|
||||||
|
tp.add(simple_job);
|
||||||
|
tp.join();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
<p>Typical output would be:</p>
|
||||||
|
<pre>
|
||||||
|
1 squared is 1
|
||||||
|
2 squared is 4
|
||||||
|
3 squared is 9
|
||||||
|
4 squared is 16
|
||||||
|
5 squared is 25
|
||||||
|
7 squared is 49
|
||||||
|
6 squared is 36
|
||||||
|
8 squared is 64
|
||||||
|
10 squared is 100
|
||||||
|
9 squared is 81
|
||||||
|
</pre>
|
||||||
|
<P>While the jobs are dispatched in the order they are received, the scheduling of
|
||||||
|
the individual threads in the pool is platform-dependent.</P>
|
||||||
|
<P>
|
||||||
|
<p>Revised
|
||||||
|
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
||||||
|
05 November, 2001
|
||||||
|
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
|
||||||
|
</p>
|
||||||
|
<p><i>© Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a>, David Moore 2001-2002.
|
||||||
|
All Rights Reserved.</i></p>
|
||||||
|
<p>Permission to use, copy, modify, distribute and sell this software and its
|
||||||
|
documentation for any purpose is hereby granted without fee, provided that the
|
||||||
|
above copyright notice appear in all copies and that both that copyright notice
|
||||||
|
and this permission notice appear in supporting documentation. William E. Kempf
|
||||||
|
makes no representations about the suitability of this software for any purpose.
|
||||||
|
It is provided "as is" without express or implied warranty.</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
202
doc/tss-ref.xml
Normal file
202
doc/tss-ref.xml
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
||||||
|
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
|
||||||
|
<!ENTITY % threads.entities SYSTEM "entities.xml">
|
||||||
|
%threads.entities;
|
||||||
|
]>
|
||||||
|
<header name="boost/thread/tss.hpp"
|
||||||
|
last-revision="$Date$">
|
||||||
|
<namespace name="boost">
|
||||||
|
<class name="thread_specific_ptr">
|
||||||
|
<purpose>
|
||||||
|
The <classname>thread_specific_ptr</classname> class defines
|
||||||
|
an interface for using thread specific storage.
|
||||||
|
</purpose>
|
||||||
|
|
||||||
|
<description>
|
||||||
|
<para>Thread specific storage is data associated with
|
||||||
|
individual threads and is often used to make operations
|
||||||
|
that rely on global data
|
||||||
|
<link linkend="threads.glossary.thread-safe">thread-safe</link>.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>Template <classname>thread_specific_ptr</classname>
|
||||||
|
stores a pointer to an object obtained on a thread-by-thread
|
||||||
|
basis and calls a specified cleanup handler on the contained
|
||||||
|
pointer when the thread terminates. The cleanup handlers are
|
||||||
|
called in the reverse order of construction of the
|
||||||
|
<classname>thread_specific_ptr</classname>s, and for the
|
||||||
|
initial thread are called by the destructor, providing the
|
||||||
|
same ordering guarantees as for normal declarations. Each
|
||||||
|
thread initially stores the null pointer in each
|
||||||
|
<classname>thread_specific_ptr</classname> instance.</para>
|
||||||
|
|
||||||
|
<para>The template <classname>thread_specific_ptr</classname>
|
||||||
|
is useful in the following cases:
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem>An interface was originally written assuming
|
||||||
|
a single thread of control and it is being ported to a
|
||||||
|
multithreaded environment.</listitem>
|
||||||
|
|
||||||
|
<listitem>Each thread of control invokes sequences of
|
||||||
|
methods that share data that are physically unique
|
||||||
|
for each thread, but must be logically accessed
|
||||||
|
through a globally visible access point instead of
|
||||||
|
being explicitly passed.</listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
</para>
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<inherit access="private">
|
||||||
|
<type><classname>boost::noncopyable</classname></type>
|
||||||
|
<purpose>Exposition only</purpose>
|
||||||
|
</inherit>
|
||||||
|
|
||||||
|
<constructor>
|
||||||
|
<requires>The expression <code>delete get()</code> is well
|
||||||
|
formed.</requires>
|
||||||
|
|
||||||
|
<effects>A thread-specific data key is allocated and visible to
|
||||||
|
all threads in the process. Upon creation, the value
|
||||||
|
<code>NULL</code> will be associated with the new key in all
|
||||||
|
active threads. A cleanup method is registered with the key
|
||||||
|
that will call <code>delete</code> on the value associated
|
||||||
|
with the key for a thread when it exits. When a thread exits,
|
||||||
|
if a key has a registered cleanup method and the thread has a
|
||||||
|
non-<code>NULL</code> value associated with that key, the value
|
||||||
|
of the key is set to <code>NULL</code> and then the cleanup
|
||||||
|
method is called with the previously associated value as its
|
||||||
|
sole argument. The order in which registered cleanup methods
|
||||||
|
are called when a thread exits is undefined. If after all the
|
||||||
|
cleanup methods have been called for all non-<code>NULL</code>
|
||||||
|
values, there are still some non-<code>NULL</code> values
|
||||||
|
with associated cleanup handlers the result is undefined
|
||||||
|
behavior.</effects>
|
||||||
|
|
||||||
|
<throws><classname>boost::thread_resource_error</classname> if
|
||||||
|
the necessary resources can not be obtained.</throws>
|
||||||
|
|
||||||
|
<notes>There may be an implementation specific limit to the
|
||||||
|
number of thread specific storage objects that can be created,
|
||||||
|
and this limit may be small.</notes>
|
||||||
|
|
||||||
|
<rationale>The most common need for cleanup will be to call
|
||||||
|
<code>delete</code> on the associated value. If other forms
|
||||||
|
of cleanup are required the overloaded constructor should be
|
||||||
|
called instead.</rationale>
|
||||||
|
</constructor>
|
||||||
|
|
||||||
|
<constructor>
|
||||||
|
<parameter name="cleanup">
|
||||||
|
<paramtype>void (*cleanup)(void*)</paramtype>
|
||||||
|
</parameter>
|
||||||
|
|
||||||
|
<effects>A thread-specific data key is allocated and visible to
|
||||||
|
all threads in the process. Upon creation, the value
|
||||||
|
<code>NULL</code> will be associated with the new key in all
|
||||||
|
active threads. The <code>cleanup</code> method is registered
|
||||||
|
with the key and will be called for a thread with the value
|
||||||
|
associated with the key for that thread when it exits. When a
|
||||||
|
thread exits, if a key has a registered cleanup method and the
|
||||||
|
thread has a non-<code>NULL</code> value associated with that
|
||||||
|
key, the value of the key is set to <code>NULL</code> and then
|
||||||
|
the cleanup method is called with the previously associated
|
||||||
|
value as its sole argument. The order in which registered
|
||||||
|
cleanup methods are called when a thread exits is undefined.
|
||||||
|
If after all the cleanup methods have been called for all
|
||||||
|
non-<code>NULL</code> values, there are still some
|
||||||
|
non-<code>NULL</code> values with associated cleanup handlers
|
||||||
|
the result is undefined behavior.</effects>
|
||||||
|
|
||||||
|
<throws><classname>boost::thread_resource_error</classname> if
|
||||||
|
the necessary resources can not be obtained.</throws>
|
||||||
|
|
||||||
|
<notes>There may be an implementation specific limit to the
|
||||||
|
number of thread specific storage objects that can be created,
|
||||||
|
and this limit may be small.</notes>
|
||||||
|
|
||||||
|
<rationale>There is the occasional need to register
|
||||||
|
specialized cleanup methods, or to register no cleanup method
|
||||||
|
at all (done by passing <code>NULL</code> to this constructor.
|
||||||
|
</rationale>
|
||||||
|
</constructor>
|
||||||
|
|
||||||
|
<destructor>
|
||||||
|
<effects>Deletes the thread-specific data key allocated by the
|
||||||
|
constructor. The thread-specific data values associated with
|
||||||
|
the key need not be <code>NULL</code>. It is the responsibility
|
||||||
|
of the application to perform any cleanup actions for data
|
||||||
|
associated with the key.</effects>
|
||||||
|
|
||||||
|
<notes>Does not destroy any data that may be stored in any
|
||||||
|
thread's thread specific storage. For this reason you should
|
||||||
|
not destroy a <classname>thread_specific_ptr</classname> object
|
||||||
|
until you are certain there are no threads running that have
|
||||||
|
made use of its thread specific storage.</notes>
|
||||||
|
|
||||||
|
<rationale>Associated data is not cleaned up because registered
|
||||||
|
cleanup methods need to be run in the thread that allocated the
|
||||||
|
associated data to be guarranteed to work correctly. There's no
|
||||||
|
safe way to inject the call into another thread's execution
|
||||||
|
path, making it impossible to call the cleanup methods safely.
|
||||||
|
</rationale>
|
||||||
|
</destructor>
|
||||||
|
|
||||||
|
<method-group name="modifier functions">
|
||||||
|
<method name="release">
|
||||||
|
<type>T*</type>
|
||||||
|
|
||||||
|
<postconditions><code>*this</code> holds the null pointer
|
||||||
|
for the current thread.</postconditions>
|
||||||
|
|
||||||
|
<returns><code>this->get()</code> prior to the call.</returns>
|
||||||
|
|
||||||
|
<rationale>This method provides a mechanism for the user to
|
||||||
|
relinquish control of the data associated with the
|
||||||
|
thread-specific key.</rationale>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="reset">
|
||||||
|
<type>void</type>
|
||||||
|
|
||||||
|
<parameter name="p">
|
||||||
|
<paramtype>T*</paramtype>
|
||||||
|
<default>0</default>
|
||||||
|
</parameter>
|
||||||
|
|
||||||
|
<effects>If <code>this->get() != p &&
|
||||||
|
this->get() != NULL</code> then call the
|
||||||
|
associated cleanup function.</effects>
|
||||||
|
|
||||||
|
<postconditions><code>*this</code> holds the pointer
|
||||||
|
<code>p</code> for the current thread.</postconditions>
|
||||||
|
</method>
|
||||||
|
</method-group>
|
||||||
|
|
||||||
|
<method-group name="observer functions">
|
||||||
|
<method name="get" cv="const">
|
||||||
|
<type>T*</type>
|
||||||
|
|
||||||
|
<returns>The object stored in thread specific storage for
|
||||||
|
the current thread for <code>*this</code>.</returns>
|
||||||
|
|
||||||
|
<notes>Each thread initially returns 0.</notes>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="operator->" cv="const">
|
||||||
|
<type>T*</type>
|
||||||
|
|
||||||
|
<returns><code>this->get()</code>.</returns>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="operator*()" cv="const">
|
||||||
|
<type>T&</type>
|
||||||
|
|
||||||
|
<requires><code>this->get() != 0</code></requires>
|
||||||
|
|
||||||
|
<returns><code>this->get()</code>.</returns>
|
||||||
|
</method>
|
||||||
|
</method-group>
|
||||||
|
</class>
|
||||||
|
</namespace>
|
||||||
|
</header>
|
||||||
169
doc/tss.html
169
doc/tss.html
@@ -1,169 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
|
||||||
<link rel="stylesheet" type="text/css" href="../../../boost.css">
|
|
||||||
<title>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>
|
|
||||||
<p><a href="../example/tss.cpp">libs/thread/example/tss.cpp</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>
|
|
||||||
78
doc/xtime-ref.xml
Normal file
78
doc/xtime-ref.xml
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
||||||
|
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
|
||||||
|
<!ENTITY % threads.entities SYSTEM "entities.xml">
|
||||||
|
%threads.entities;
|
||||||
|
]>
|
||||||
|
<header name="boost/thread/xtime.hpp"
|
||||||
|
last-revision="$Date$">
|
||||||
|
<namespace name="boost">
|
||||||
|
<enum name="xtime_clock_types">
|
||||||
|
<enumvalue name="TIME_UTC" />
|
||||||
|
|
||||||
|
<purpose>
|
||||||
|
<para>Specifies the clock type to use when creating
|
||||||
|
an object of type <classname>xtime</classname>.</para>
|
||||||
|
</purpose>
|
||||||
|
|
||||||
|
<description>
|
||||||
|
<para>The only clock type supported by &Boost.Threads; is
|
||||||
|
<code>TIME_UTC</code>. The epoch for <code>TIME_UTC</code>
|
||||||
|
is 1970-01-01 00:00:00.</para>
|
||||||
|
</description>
|
||||||
|
</enum>
|
||||||
|
|
||||||
|
<struct name="xtime">
|
||||||
|
<purpose>
|
||||||
|
<simpara>An object of type <classname>xtime</classname>
|
||||||
|
defines a time that is 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.</simpara>
|
||||||
|
</purpose>
|
||||||
|
|
||||||
|
<description>
|
||||||
|
<simpara>The <classname>xtime</classname> 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. &Boost.Threads; provides only a very minimal implementation of this
|
||||||
|
proposal; it is expected that a full implementation (or some other time
|
||||||
|
library) will be provided in Boost as a separate library, at which time &Boost.Threads;
|
||||||
|
will deprecate its own implementation.</simpara>
|
||||||
|
|
||||||
|
<simpara><emphasis role="bold">Note</emphasis> that 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.</simpara>
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<free-function-group name="creation">
|
||||||
|
<function name="xtime_get">
|
||||||
|
<type>int</type>
|
||||||
|
|
||||||
|
<parameter name="xtp">
|
||||||
|
<paramtype><classname>xtime</classname>*</paramtype>
|
||||||
|
</parameter>
|
||||||
|
|
||||||
|
<parameter name="clock_type">
|
||||||
|
<paramtype>int</paramtype>
|
||||||
|
</parameter>
|
||||||
|
|
||||||
|
<postconditions>
|
||||||
|
<simpara><code>xtp</code> represents the current point in
|
||||||
|
time as a duration since the epoch specified by
|
||||||
|
<code>clock_type</code>.</simpara>
|
||||||
|
</postconditions>
|
||||||
|
|
||||||
|
<returns>
|
||||||
|
<simpara><code>clock_type</code> if successful, otherwise 0.</simpara>
|
||||||
|
</returns>
|
||||||
|
</function>
|
||||||
|
</free-function-group>
|
||||||
|
|
||||||
|
<data-member name="sec">
|
||||||
|
<type><emphasis>platform-specific-type</emphasis></type>
|
||||||
|
</data-member>
|
||||||
|
</struct>
|
||||||
|
</namespace>
|
||||||
|
</header>
|
||||||
110
doc/xtime.html
110
doc/xtime.html
@@ -1,110 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
|
||||||
<link rel="stylesheet" type="text/css" href="../../../boost.css">
|
|
||||||
<title>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>
|
|
||||||
<p><a href="../example/xtime.cpp">libs/thread/example/xtime.cpp</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>
|
|
||||||
@@ -1,7 +1,25 @@
|
|||||||
# (C) Copyright William E. Kempf 2001. Permission to copy, use, modify, sell and
|
# Copyright (C) 2001-2003
|
||||||
# distribute this software is granted provided this copyright notice appears
|
# William E. Kempf
|
||||||
# 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.
|
# 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.
|
||||||
|
#
|
||||||
|
# Boost.Threads example Jamfile
|
||||||
|
#
|
||||||
|
# Additional configuration variables used:
|
||||||
|
# 1. PTW32 may be used on Win32 platforms to specify that the pthreads-win32
|
||||||
|
# library should be used instead of "native" threads. This feature is
|
||||||
|
# mostly used for testing and it's generally recommended you use the
|
||||||
|
# native threading libraries instead. PTW32 should be set to be a list
|
||||||
|
# of two strings, the first specifying the installation path of the
|
||||||
|
# pthreads-win32 library and the second specifying which library
|
||||||
|
# variant to link against (see the pthreads-win32 documentation).
|
||||||
|
# Example: jam -sPTW32="c:\pthreads-win32 pthreadVCE.lib"
|
||||||
|
|
||||||
# Declare the location of this subproject relative to the root.
|
# Declare the location of this subproject relative to the root.
|
||||||
subproject libs/thread/example ;
|
subproject libs/thread/example ;
|
||||||
@@ -9,28 +27,28 @@ subproject libs/thread/example ;
|
|||||||
# Include threads.jam for Boost.Threads global build information.
|
# Include threads.jam for Boost.Threads global build information.
|
||||||
# This greatly simplifies the Jam code needed to configure the build
|
# This greatly simplifies the Jam code needed to configure the build
|
||||||
# for the various Win32 build types.
|
# for the various Win32 build types.
|
||||||
SEARCH on <module@>threads.jam = $(BOOST_ROOT)/libs/thread/build ;
|
import ../build/threads ;
|
||||||
include <module@>threads.jam ;
|
|
||||||
|
|
||||||
template example
|
{
|
||||||
## sources ##
|
template example
|
||||||
: <template>thread_base
|
## sources ##
|
||||||
<dll>../build/boost_thread
|
: <template>thread_base
|
||||||
$(threadmon)
|
<dll>../build/boost_thread
|
||||||
## requirements ##
|
## requirements ##
|
||||||
:
|
:
|
||||||
## default build ##
|
## default build ##
|
||||||
: release <runtime-link>dynamic
|
:
|
||||||
;
|
;
|
||||||
|
|
||||||
exe monitor : <template>example monitor.cpp ;
|
exe monitor : <template>example monitor.cpp ;
|
||||||
exe starvephil : <template>example starvephil.cpp ;
|
exe starvephil : <template>example starvephil.cpp ;
|
||||||
exe tennis : <template>example tennis.cpp ;
|
exe tennis : <template>example tennis.cpp ;
|
||||||
exe condition : <template>example condition.cpp ;
|
exe condition : <template>example condition.cpp ;
|
||||||
exe mutex : <template>example mutex.cpp ;
|
exe mutex : <template>example mutex.cpp ;
|
||||||
exe once : <template>example once.cpp ;
|
exe once : <template>example once.cpp ;
|
||||||
exe recursive_mutex : <template>example recursive_mutex.cpp ;
|
exe recursive_mutex : <template>example recursive_mutex.cpp ;
|
||||||
exe thread : <template>example thread.cpp ;
|
exe thread : <template>example thread.cpp ;
|
||||||
exe thread_group : <template>example thread_group.cpp ;
|
exe thread_group : <template>example thread_group.cpp ;
|
||||||
exe tss : <template>example tss.cpp ;
|
exe tss : <template>example tss.cpp ;
|
||||||
exe xtime : <template>example xtime.cpp ;
|
exe xtime : <template>example xtime.cpp ;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,3 +1,14 @@
|
|||||||
|
// Copyright (C) 2001-2003
|
||||||
|
// William E. Kempf
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
|
// and its documentation for any purpose is hereby granted without fee,
|
||||||
|
// provided that the above copyright notice appear in all copies and
|
||||||
|
// that both that copyright notice and this permission notice appear
|
||||||
|
// in supporting documentation. William E. Kempf makes no representations
|
||||||
|
// about the suitability of this software for any purpose.
|
||||||
|
// It is provided "as is" without express or implied warranty.
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <boost/utility.hpp>
|
#include <boost/utility.hpp>
|
||||||
@@ -43,9 +54,9 @@ bounded_buffer buf(2);
|
|||||||
void sender() {
|
void sender() {
|
||||||
int n = 0;
|
int n = 0;
|
||||||
while (n < 100) {
|
while (n < 100) {
|
||||||
buf.send(n);
|
buf.send(n);
|
||||||
std::cout << "sent: " << n << std::endl;
|
std::cout << "sent: " << n << std::endl;
|
||||||
++n;
|
++n;
|
||||||
}
|
}
|
||||||
buf.send(-1);
|
buf.send(-1);
|
||||||
}
|
}
|
||||||
@@ -53,8 +64,8 @@ void sender() {
|
|||||||
void receiver() {
|
void receiver() {
|
||||||
int n;
|
int n;
|
||||||
do {
|
do {
|
||||||
n = buf.receive();
|
n = buf.receive();
|
||||||
std::cout << "received: " << n << std::endl;
|
std::cout << "received: " << n << std::endl;
|
||||||
} while (n != -1); // -1 indicates end of buffer
|
} while (n != -1); // -1 indicates end of buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,14 @@
|
|||||||
|
// Copyright (C) 2001-2003
|
||||||
|
// William E. Kempf
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
|
// and its documentation for any purpose is hereby granted without fee,
|
||||||
|
// provided that the above copyright notice appear in all copies and
|
||||||
|
// that both that copyright notice and this permission notice appear
|
||||||
|
// in supporting documentation. William E. Kempf makes no representations
|
||||||
|
// about the suitability of this software for any purpose.
|
||||||
|
// It is provided "as is" without express or implied warranty.
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <boost/thread/condition.hpp>
|
#include <boost/thread/condition.hpp>
|
||||||
@@ -6,9 +17,9 @@
|
|||||||
#include <boost/thread/thread.hpp>
|
#include <boost/thread/thread.hpp>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
const int ITERS = 100;
|
const int ITERS = 100;
|
||||||
boost::mutex io_mutex;
|
boost::mutex io_mutex;
|
||||||
}
|
} // namespace
|
||||||
|
|
||||||
template <typename M>
|
template <typename M>
|
||||||
class buffer_t
|
class buffer_t
|
||||||
|
|||||||
@@ -1,3 +1,14 @@
|
|||||||
|
// Copyright (C) 2001-2003
|
||||||
|
// William E. Kempf
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
|
// and its documentation for any purpose is hereby granted without fee,
|
||||||
|
// provided that the above copyright notice appear in all copies and
|
||||||
|
// that both that copyright notice and this permission notice appear
|
||||||
|
// in supporting documentation. William E. Kempf makes no representations
|
||||||
|
// about the suitability of this software for any purpose.
|
||||||
|
// It is provided "as is" without express or implied warranty.
|
||||||
|
|
||||||
#include <boost/thread/mutex.hpp>
|
#include <boost/thread/mutex.hpp>
|
||||||
#include <boost/thread/thread.hpp>
|
#include <boost/thread/thread.hpp>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|||||||
@@ -1,3 +1,14 @@
|
|||||||
|
// Copyright (C) 2001-2003
|
||||||
|
// William E. Kempf
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
|
// and its documentation for any purpose is hereby granted without fee,
|
||||||
|
// provided that the above copyright notice appear in all copies and
|
||||||
|
// that both that copyright notice and this permission notice appear
|
||||||
|
// in supporting documentation. William E. Kempf makes no representations
|
||||||
|
// about the suitability of this software for any purpose.
|
||||||
|
// It is provided "as is" without express or implied warranty.
|
||||||
|
|
||||||
#include <boost/thread/thread.hpp>
|
#include <boost/thread/thread.hpp>
|
||||||
#include <boost/thread/once.hpp>
|
#include <boost/thread/once.hpp>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
@@ -12,14 +23,14 @@ void init()
|
|||||||
|
|
||||||
void thread_proc()
|
void thread_proc()
|
||||||
{
|
{
|
||||||
boost::call_once(&init, once);
|
boost::call_once(&init, once);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
boost::thread_group threads;
|
boost::thread_group threads;
|
||||||
for (int i=0; i<5; ++i)
|
for (int i=0; i<5; ++i)
|
||||||
threads.create_thread(&thread_proc);
|
threads.create_thread(&thread_proc);
|
||||||
threads.join_all();
|
threads.join_all();
|
||||||
assert(value == 1);
|
assert(value == 1);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,14 @@
|
|||||||
|
// Copyright (C) 2001-2003
|
||||||
|
// William E. Kempf
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
|
// and its documentation for any purpose is hereby granted without fee,
|
||||||
|
// provided that the above copyright notice appear in all copies and
|
||||||
|
// that both that copyright notice and this permission notice appear
|
||||||
|
// in supporting documentation. William E. Kempf makes no representations
|
||||||
|
// about the suitability of this software for any purpose.
|
||||||
|
// It is provided "as is" without express or implied warranty.
|
||||||
|
|
||||||
#include <boost/thread/recursive_mutex.hpp>
|
#include <boost/thread/recursive_mutex.hpp>
|
||||||
#include <boost/thread/thread.hpp>
|
#include <boost/thread/thread.hpp>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|||||||
@@ -1,3 +1,14 @@
|
|||||||
|
// Copyright (C) 2001-2003
|
||||||
|
// William E. Kempf
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
|
// and its documentation for any purpose is hereby granted without fee,
|
||||||
|
// provided that the above copyright notice appear in all copies and
|
||||||
|
// that both that copyright notice and this permission notice appear
|
||||||
|
// in supporting documentation. William E. Kempf makes no representations
|
||||||
|
// about the suitability of this software for any purpose.
|
||||||
|
// It is provided "as is" without express or implied warranty.
|
||||||
|
|
||||||
#include <boost/thread/mutex.hpp>
|
#include <boost/thread/mutex.hpp>
|
||||||
#include <boost/thread/condition.hpp>
|
#include <boost/thread/condition.hpp>
|
||||||
#include <boost/thread/thread.hpp>
|
#include <boost/thread/thread.hpp>
|
||||||
@@ -7,7 +18,7 @@
|
|||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
boost::mutex iomx;
|
boost::mutex iomx;
|
||||||
}
|
}
|
||||||
|
|
||||||
class canteen
|
class canteen
|
||||||
@@ -39,8 +50,9 @@ public:
|
|||||||
boost::mutex::scoped_lock lock(m_mutex);
|
boost::mutex::scoped_lock lock(m_mutex);
|
||||||
{
|
{
|
||||||
boost::mutex::scoped_lock lock(iomx);
|
boost::mutex::scoped_lock lock(iomx);
|
||||||
std::cout << "(" << clock() <<
|
std::cout << "(" << clock()
|
||||||
") Chef: ouch ... make room ... this dish is very hot ..." << std::endl;
|
<< ") Chef: ouch ... make room ... this dish is "
|
||||||
|
<< "very hot ..." << std::endl;
|
||||||
}
|
}
|
||||||
boost::xtime xt;
|
boost::xtime xt;
|
||||||
boost::xtime_get(&xt, boost::TIME_UTC);
|
boost::xtime_get(&xt, boost::TIME_UTC);
|
||||||
@@ -84,7 +96,7 @@ void chef()
|
|||||||
{
|
{
|
||||||
boost::mutex::scoped_lock lock(iomx);
|
boost::mutex::scoped_lock lock(iomx);
|
||||||
std::cout << "(" << clock() << ") Chef: " << chickens
|
std::cout << "(" << clock() << ") Chef: " << chickens
|
||||||
<< " chickens, ready-to-go ..." << std::endl;
|
<< " chickens, ready-to-go ..." << std::endl;
|
||||||
}
|
}
|
||||||
g_canteen.put(chickens);
|
g_canteen.put(chickens);
|
||||||
}
|
}
|
||||||
@@ -96,7 +108,8 @@ struct phil
|
|||||||
void run() {
|
void run() {
|
||||||
{
|
{
|
||||||
boost::mutex::scoped_lock lock(iomx);
|
boost::mutex::scoped_lock lock(iomx);
|
||||||
std::cout << "(" << clock() << ") Phil" << m_id << ": starting ..." << std::endl;
|
std::cout << "(" << clock() << ") Phil" << m_id
|
||||||
|
<< ": starting ..." << std::endl;
|
||||||
}
|
}
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
@@ -110,13 +123,13 @@ struct phil
|
|||||||
{
|
{
|
||||||
boost::mutex::scoped_lock lock(iomx);
|
boost::mutex::scoped_lock lock(iomx);
|
||||||
std::cout << "(" << clock() << ") Phil" << m_id
|
std::cout << "(" << clock() << ") Phil" << m_id
|
||||||
<< ": gotta eat ..." << std::endl;
|
<< ": gotta eat ..." << std::endl;
|
||||||
}
|
}
|
||||||
g_canteen.get(m_id);
|
g_canteen.get(m_id);
|
||||||
{
|
{
|
||||||
boost::mutex::scoped_lock lock(iomx);
|
boost::mutex::scoped_lock lock(iomx);
|
||||||
std::cout << "(" << clock() << ") Phil" << m_id
|
std::cout << "(" << clock() << ") Phil" << m_id
|
||||||
<< ": mmm ... that's good ..." << std::endl;
|
<< ": mmm ... that's good ..." << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -129,7 +142,10 @@ struct phil
|
|||||||
|
|
||||||
struct thread_adapt
|
struct thread_adapt
|
||||||
{
|
{
|
||||||
thread_adapt(void (*func)(void*), void* param) : _func(func), _param(param) { }
|
thread_adapt(void (*func)(void*), void* param)
|
||||||
|
: _func(func), _param(param)
|
||||||
|
{
|
||||||
|
}
|
||||||
int operator()() const
|
int operator()() const
|
||||||
{
|
{
|
||||||
_func(_param);
|
_func(_param);
|
||||||
@@ -143,7 +159,10 @@ struct thread_adapt
|
|||||||
class thread_adapter
|
class thread_adapter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
thread_adapter(void (*func)(void*), void* param) : _func(func), _param(param) { }
|
thread_adapter(void (*func)(void*), void* param)
|
||||||
|
: _func(func), _param(param)
|
||||||
|
{
|
||||||
|
}
|
||||||
void operator()() const { _func(_param); }
|
void operator()() const { _func(_param); }
|
||||||
private:
|
private:
|
||||||
void (*_func)(void*);
|
void (*_func)(void*);
|
||||||
|
|||||||
@@ -1,3 +1,14 @@
|
|||||||
|
// Copyright (C) 2001-2003
|
||||||
|
// William E. Kempf
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
|
// and its documentation for any purpose is hereby granted without fee,
|
||||||
|
// provided that the above copyright notice appear in all copies and
|
||||||
|
// that both that copyright notice and this permission notice appear
|
||||||
|
// in supporting documentation. William E. Kempf makes no representations
|
||||||
|
// about the suitability of this software for any purpose.
|
||||||
|
// It is provided "as is" without express or implied warranty.
|
||||||
|
|
||||||
#include <boost/thread/mutex.hpp>
|
#include <boost/thread/mutex.hpp>
|
||||||
#include <boost/thread/condition.hpp>
|
#include <boost/thread/condition.hpp>
|
||||||
#include <boost/thread/thread.hpp>
|
#include <boost/thread/thread.hpp>
|
||||||
@@ -49,7 +60,10 @@ void player(void* param)
|
|||||||
{
|
{
|
||||||
cond.wait(lock);
|
cond.wait(lock);
|
||||||
if (state == other)
|
if (state == other)
|
||||||
std::cout << "---" << player_name(active) << ": Spurious wakeup!" << std::endl;
|
{
|
||||||
|
std::cout << "---" << player_name(active)
|
||||||
|
<< ": Spurious wakeup!" << std::endl;
|
||||||
|
}
|
||||||
} while (state == other);
|
} while (state == other);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,7 +74,10 @@ void player(void* param)
|
|||||||
|
|
||||||
struct thread_adapt
|
struct thread_adapt
|
||||||
{
|
{
|
||||||
thread_adapt(void (*func)(void*), void* param) : _func(func), _param(param) { }
|
thread_adapt(void (*func)(void*), void* param)
|
||||||
|
: _func(func), _param(param)
|
||||||
|
{
|
||||||
|
}
|
||||||
int operator()() const
|
int operator()() const
|
||||||
{
|
{
|
||||||
_func(_param);
|
_func(_param);
|
||||||
@@ -74,7 +91,10 @@ struct thread_adapt
|
|||||||
class thread_adapter
|
class thread_adapter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
thread_adapter(void (*func)(void*), void* param) : _func(func), _param(param) { }
|
thread_adapter(void (*func)(void*), void* param)
|
||||||
|
: _func(func), _param(param)
|
||||||
|
{
|
||||||
|
}
|
||||||
void operator()() const { _func(_param); }
|
void operator()() const { _func(_param); }
|
||||||
private:
|
private:
|
||||||
void (*_func)(void*);
|
void (*_func)(void*);
|
||||||
|
|||||||
@@ -1,29 +1,40 @@
|
|||||||
|
// Copyright (C) 2001-2003
|
||||||
|
// William E. Kempf
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
|
// and its documentation for any purpose is hereby granted without fee,
|
||||||
|
// provided that the above copyright notice appear in all copies and
|
||||||
|
// that both that copyright notice and this permission notice appear
|
||||||
|
// in supporting documentation. William E. Kempf makes no representations
|
||||||
|
// about the suitability of this software for any purpose.
|
||||||
|
// It is provided "as is" without express or implied warranty.
|
||||||
|
|
||||||
#include <boost/thread/thread.hpp>
|
#include <boost/thread/thread.hpp>
|
||||||
#include <boost/thread/xtime.hpp>
|
#include <boost/thread/xtime.hpp>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
struct thread_alarm
|
struct thread_alarm
|
||||||
{
|
{
|
||||||
thread_alarm(int secs) : m_secs(secs) { }
|
thread_alarm(int secs) : m_secs(secs) { }
|
||||||
void operator()()
|
void operator()()
|
||||||
{
|
{
|
||||||
boost::xtime xt;
|
boost::xtime xt;
|
||||||
boost::xtime_get(&xt, boost::TIME_UTC);
|
boost::xtime_get(&xt, boost::TIME_UTC);
|
||||||
xt.sec += m_secs;
|
xt.sec += m_secs;
|
||||||
|
|
||||||
boost::thread::sleep(xt);
|
boost::thread::sleep(xt);
|
||||||
|
|
||||||
std::cout << "alarm sounded..." << std::endl;
|
std::cout << "alarm sounded..." << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
int m_secs;
|
int m_secs;
|
||||||
};
|
};
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
int secs = 5;
|
int secs = 5;
|
||||||
std::cout << "setting alarm for 5 seconds..." << std::endl;
|
std::cout << "setting alarm for 5 seconds..." << std::endl;
|
||||||
thread_alarm alarm(secs);
|
thread_alarm alarm(secs);
|
||||||
boost::thread thrd(alarm);
|
boost::thread thrd(alarm);
|
||||||
thrd.join();
|
thrd.join();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,14 @@
|
|||||||
|
// Copyright (C) 2001-2003
|
||||||
|
// William E. Kempf
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
|
// and its documentation for any purpose is hereby granted without fee,
|
||||||
|
// provided that the above copyright notice appear in all copies and
|
||||||
|
// that both that copyright notice and this permission notice appear
|
||||||
|
// in supporting documentation. William E. Kempf makes no representations
|
||||||
|
// about the suitability of this software for any purpose.
|
||||||
|
// It is provided "as is" without express or implied warranty.
|
||||||
|
|
||||||
#include <boost/thread/thread.hpp>
|
#include <boost/thread/thread.hpp>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
@@ -6,14 +17,14 @@ boost::mutex mutex;
|
|||||||
|
|
||||||
void increment_count()
|
void increment_count()
|
||||||
{
|
{
|
||||||
boost::mutex::scoped_lock lock(mutex);
|
boost::mutex::scoped_lock lock(mutex);
|
||||||
std::cout << "count = " << ++count << std::endl;
|
std::cout << "count = " << ++count << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
boost::thread_group threads;
|
boost::thread_group threads;
|
||||||
for (int i = 0; i < 10; ++i)
|
for (int i = 0; i < 10; ++i)
|
||||||
threads.create_thread(&increment_count);
|
threads.create_thread(&increment_count);
|
||||||
threads.join_all();
|
threads.join_all();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,14 @@
|
|||||||
|
// Copyright (C) 2001-2003
|
||||||
|
// William E. Kempf
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
|
// and its documentation for any purpose is hereby granted without fee,
|
||||||
|
// provided that the above copyright notice appear in all copies and
|
||||||
|
// that both that copyright notice and this permission notice appear
|
||||||
|
// in supporting documentation. William E. Kempf makes no representations
|
||||||
|
// about the suitability of this software for any purpose.
|
||||||
|
// It is provided "as is" without express or implied warranty.
|
||||||
|
|
||||||
#include <boost/thread/thread.hpp>
|
#include <boost/thread/thread.hpp>
|
||||||
#include <boost/thread/tss.hpp>
|
#include <boost/thread/tss.hpp>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
@@ -6,25 +17,25 @@ boost::thread_specific_ptr<int> value;
|
|||||||
|
|
||||||
void increment()
|
void increment()
|
||||||
{
|
{
|
||||||
int* p = value.get();
|
int* p = value.get();
|
||||||
++*p;
|
++*p;
|
||||||
}
|
}
|
||||||
|
|
||||||
void thread_proc()
|
void thread_proc()
|
||||||
{
|
{
|
||||||
value.reset(new int(0)); // initialize the thread's storage
|
value.reset(new int(0)); // initialize the thread's storage
|
||||||
for (int i=0; i<10; ++i)
|
for (int i=0; i<10; ++i)
|
||||||
{
|
{
|
||||||
increment();
|
increment();
|
||||||
int* p = value.get();
|
int* p = value.get();
|
||||||
assert(*p == i+1);
|
assert(*p == i+1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
boost::thread_group threads;
|
boost::thread_group threads;
|
||||||
for (int i=0; i<5; ++i)
|
for (int i=0; i<5; ++i)
|
||||||
threads.create_thread(&thread_proc);
|
threads.create_thread(&thread_proc);
|
||||||
threads.join_all();
|
threads.join_all();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,21 @@
|
|||||||
|
// Copyright (C) 2001-2003
|
||||||
|
// William E. Kempf
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
|
// and its documentation for any purpose is hereby granted without fee,
|
||||||
|
// provided that the above copyright notice appear in all copies and
|
||||||
|
// that both that copyright notice and this permission notice appear
|
||||||
|
// in supporting documentation. William E. Kempf makes no representations
|
||||||
|
// about the suitability of this software for any purpose.
|
||||||
|
// It is provided "as is" without express or implied warranty.
|
||||||
|
|
||||||
#include <boost/thread/thread.hpp>
|
#include <boost/thread/thread.hpp>
|
||||||
#include <boost/thread/xtime.hpp>
|
#include <boost/thread/xtime.hpp>
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
boost::xtime xt;
|
boost::xtime xt;
|
||||||
boost::xtime_get(&xt, boost::TIME_UTC);
|
boost::xtime_get(&xt, boost::TIME_UTC);
|
||||||
xt.sec += 1;
|
xt.sec += 1;
|
||||||
boost::thread::sleep(xt); // Sleep for 1 second
|
boost::thread::sleep(xt); // Sleep for 1 second
|
||||||
}
|
}
|
||||||
|
|||||||
40
include/boost/thread/barrier.hpp
Normal file
40
include/boost/thread/barrier.hpp
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
// Copyright (C) 2002-2003
|
||||||
|
// David Moore, William E. Kempf
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
|
// and its documentation for any purpose is hereby granted without fee,
|
||||||
|
// provided that the above copyright notice appear in all copies and
|
||||||
|
// that both that copyright notice and this permission notice appear
|
||||||
|
// in supporting documentation. William E. Kempf makes no representations
|
||||||
|
// about the suitability of this software for any purpose.
|
||||||
|
// It is provided "as is" without express or implied warranty.
|
||||||
|
|
||||||
|
#ifndef BOOST_BARRIER_JDM030602_HPP
|
||||||
|
#define BOOST_BARRIER_JDM030602_HPP
|
||||||
|
|
||||||
|
#include <boost/thread/detail/config.hpp>
|
||||||
|
|
||||||
|
#include <boost/thread/mutex.hpp>
|
||||||
|
#include <boost/thread/condition.hpp>
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
class BOOST_THREAD_DECL barrier
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
barrier(unsigned int count);
|
||||||
|
~barrier();
|
||||||
|
|
||||||
|
bool wait();
|
||||||
|
|
||||||
|
private:
|
||||||
|
mutex m_mutex;
|
||||||
|
condition m_cond;
|
||||||
|
unsigned int m_threshold;
|
||||||
|
unsigned int m_count;
|
||||||
|
unsigned int m_generation;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2001
|
// Copyright (C) 2001-2003
|
||||||
// William E. Kempf
|
// William E. Kempf
|
||||||
//
|
//
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
@@ -12,15 +12,11 @@
|
|||||||
#ifndef BOOST_CONDITION_WEK070601_HPP
|
#ifndef BOOST_CONDITION_WEK070601_HPP
|
||||||
#define BOOST_CONDITION_WEK070601_HPP
|
#define BOOST_CONDITION_WEK070601_HPP
|
||||||
|
|
||||||
#include <boost/config.hpp>
|
#include <boost/thread/detail/config.hpp>
|
||||||
#ifndef BOOST_HAS_THREADS
|
|
||||||
# error Thread support is unavailable!
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <boost/thread/exceptions.hpp>
|
#include <boost/thread/exceptions.hpp>
|
||||||
#include <boost/utility.hpp>
|
#include <boost/utility.hpp>
|
||||||
#include <boost/thread/detail/lock.hpp>
|
#include <boost/thread/detail/lock.hpp>
|
||||||
#include <boost/thread/detail/config.hpp>
|
|
||||||
|
|
||||||
#if defined(BOOST_HAS_PTHREADS)
|
#if defined(BOOST_HAS_PTHREADS)
|
||||||
# include <pthread.h>
|
# include <pthread.h>
|
||||||
@@ -143,9 +139,9 @@ private:
|
|||||||
typedef detail::thread::lock_ops<M>
|
typedef detail::thread::lock_ops<M>
|
||||||
#if defined(__HP_aCC) && __HP_aCC <= 33900 && !defined(BOOST_STRICT_CONFIG)
|
#if defined(__HP_aCC) && __HP_aCC <= 33900 && !defined(BOOST_STRICT_CONFIG)
|
||||||
# define lock_ops lock_ops_ // HP confuses lock_ops witht the template
|
# define lock_ops lock_ops_ // HP confuses lock_ops witht the template
|
||||||
#endif
|
#endif
|
||||||
lock_ops;
|
lock_ops;
|
||||||
|
|
||||||
typename lock_ops::lock_state state;
|
typename lock_ops::lock_state state;
|
||||||
lock_ops::unlock(mutex, state);
|
lock_ops::unlock(mutex, state);
|
||||||
|
|
||||||
@@ -169,9 +165,9 @@ private:
|
|||||||
typedef detail::thread::lock_ops<M>
|
typedef detail::thread::lock_ops<M>
|
||||||
#if defined(__HP_aCC) && __HP_aCC <= 33900 && !defined(BOOST_STRICT_CONFIG)
|
#if defined(__HP_aCC) && __HP_aCC <= 33900 && !defined(BOOST_STRICT_CONFIG)
|
||||||
# define lock_ops lock_ops_ // HP confuses lock_ops witht the template
|
# define lock_ops lock_ops_ // HP confuses lock_ops witht the template
|
||||||
#endif
|
#endif
|
||||||
lock_ops;
|
lock_ops;
|
||||||
|
|
||||||
typename lock_ops::lock_state state;
|
typename lock_ops::lock_state state;
|
||||||
lock_ops::unlock(mutex, state);
|
lock_ops::unlock(mutex, state);
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,60 @@
|
|||||||
|
// Copyright (C) 2001-2003
|
||||||
|
// William E. Kempf
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
|
// and its documentation for any purpose is hereby granted without fee,
|
||||||
|
// provided that the above copyright notice appear in all copies and
|
||||||
|
// that both that copyright notice and this permission notice appear
|
||||||
|
// in supporting documentation. William E. Kempf makes no representations
|
||||||
|
// about the suitability of this software for any purpose.
|
||||||
|
// It is provided "as is" without express or implied warranty.
|
||||||
|
|
||||||
#ifndef BOOST_THREAD_CONFIG_WEK01032003_HPP
|
#ifndef BOOST_THREAD_CONFIG_WEK01032003_HPP
|
||||||
#define BOOST_THREAD_CONFIG_WEK01032003_HPP
|
#define BOOST_THREAD_CONFIG_WEK01032003_HPP
|
||||||
|
|
||||||
|
#include <boost/config.hpp>
|
||||||
|
|
||||||
|
// insist on threading support being available:
|
||||||
|
#include <boost/config/requires_threads.hpp>
|
||||||
|
|
||||||
#if defined(BOOST_HAS_WINTHREADS)
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
# if defined(BOOST_THREAD_BUILD_DLL)
|
# if defined(BOOST_THREAD_BUILD_DLL) //Build dll
|
||||||
# define BOOST_THREAD_DECL __declspec(dllexport)
|
# define BOOST_THREAD_DECL __declspec(dllexport)
|
||||||
# else
|
# elif defined(BOOST_THREAD_BUILD_LIB) //Build lib
|
||||||
|
# define BOOST_THREAD_DECL
|
||||||
|
# elif defined(BOOST_THREAD_USE_LIB) //Use lib
|
||||||
|
# define BOOST_THREAD_DECL
|
||||||
|
# else //Use dll
|
||||||
# define BOOST_THREAD_DECL __declspec(dllimport)
|
# define BOOST_THREAD_DECL __declspec(dllimport)
|
||||||
|
# define BOOST_DYN_LINK
|
||||||
# endif
|
# endif
|
||||||
#else
|
#else
|
||||||
# define BOOST_THREAD_DECL
|
# define BOOST_THREAD_DECL
|
||||||
#endif // BOOST_THREAD_SHARED_LIB
|
# if defined(BOOST_THREAD_USE_LIB) //Use lib
|
||||||
|
# else //Use dll
|
||||||
|
# define BOOST_DYN_LINK
|
||||||
|
# endif
|
||||||
|
#endif // BOOST_HAS_WINTHREADS
|
||||||
|
|
||||||
|
//
|
||||||
|
// Automatically link to the correct build variant where possible.
|
||||||
|
//
|
||||||
|
#if !defined(BOOST_ALL_NO_LIB) && !defined(BOOST_THREAD_NO_LIB) && !defined(BOOST_THREAD_BUILD_DLL) && !defined(BOOST_THREAD_BUILD_LIB)
|
||||||
|
//
|
||||||
|
// Set the name of our library, this will get undef'ed by auto_link.hpp
|
||||||
|
// once it's done with it:
|
||||||
|
//
|
||||||
|
#if defined(BOOST_THREAD_LIB_NAME)
|
||||||
|
# define BOOST_LIB_NAME BOOST_THREAD_LIB_NAME
|
||||||
|
#else
|
||||||
|
# define BOOST_LIB_NAME boost_thread
|
||||||
|
#endif
|
||||||
|
//
|
||||||
|
// If we're importing code from a dll, then tell auto_link.hpp about it:
|
||||||
|
//
|
||||||
|
// And include the header that does the work:
|
||||||
|
//
|
||||||
|
#include <boost/config/auto_link.hpp>
|
||||||
|
#endif // auto-linking disabled
|
||||||
|
|
||||||
#endif // BOOST_THREAD_CONFIG_WEK1032003_HPP
|
#endif // BOOST_THREAD_CONFIG_WEK1032003_HPP
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2001
|
// Copyright (C) 2001-2003
|
||||||
// Mac Murrett
|
// Mac Murrett
|
||||||
//
|
//
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
@@ -14,31 +14,30 @@
|
|||||||
#ifndef BOOST_FORCE_CAST_MJM012402_HPP
|
#ifndef BOOST_FORCE_CAST_MJM012402_HPP
|
||||||
#define BOOST_FORCE_CAST_MJM012402_HPP
|
#define BOOST_FORCE_CAST_MJM012402_HPP
|
||||||
|
|
||||||
|
#include <boost/thread/detail/config.hpp>
|
||||||
|
|
||||||
namespace boost {
|
namespace boost {
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
namespace thread {
|
namespace thread {
|
||||||
|
|
||||||
|
|
||||||
// force_cast will convert anything to anything.
|
// force_cast will convert anything to anything.
|
||||||
|
|
||||||
// general case
|
// general case
|
||||||
template<class Return_Type, class Argument_Type>
|
template<class Return_Type, class Argument_Type>
|
||||||
inline Return_Type &force_cast(Argument_Type &rSrc)
|
inline Return_Type &force_cast(Argument_Type &rSrc)
|
||||||
{ return(*reinterpret_cast<Return_Type *>(&rSrc)); }
|
{
|
||||||
|
return(*reinterpret_cast<Return_Type *>(&rSrc));
|
||||||
|
}
|
||||||
|
|
||||||
// specialization for const
|
// specialization for const
|
||||||
template<class Return_Type, class Argument_Type>
|
template<class Return_Type, class Argument_Type>
|
||||||
inline const Return_Type &force_cast(const Argument_Type &rSrc)
|
inline const Return_Type &force_cast(const Argument_Type &rSrc)
|
||||||
{ return(*reinterpret_cast<const Return_Type *>(&rSrc)); }
|
{
|
||||||
|
return(*reinterpret_cast<const Return_Type *>(&rSrc));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace thread
|
} // namespace thread
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
} // namespace boost
|
} // namespace boost
|
||||||
|
|
||||||
|
|
||||||
#endif // BOOST_FORCE_CAST_MJM012402_HPP
|
#endif // BOOST_FORCE_CAST_MJM012402_HPP
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2001
|
// Copyright (C) 2001-2003
|
||||||
// William E. Kempf
|
// William E. Kempf
|
||||||
//
|
//
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
@@ -12,6 +12,8 @@
|
|||||||
#ifndef BOOST_XLOCK_WEK070601_HPP
|
#ifndef BOOST_XLOCK_WEK070601_HPP
|
||||||
#define BOOST_XLOCK_WEK070601_HPP
|
#define BOOST_XLOCK_WEK070601_HPP
|
||||||
|
|
||||||
|
#include <boost/thread/detail/config.hpp>
|
||||||
|
|
||||||
#include <boost/utility.hpp>
|
#include <boost/utility.hpp>
|
||||||
#include <boost/thread/exceptions.hpp>
|
#include <boost/thread/exceptions.hpp>
|
||||||
|
|
||||||
@@ -20,188 +22,193 @@ namespace boost {
|
|||||||
class condition;
|
class condition;
|
||||||
struct xtime;
|
struct xtime;
|
||||||
|
|
||||||
namespace detail { namespace thread {
|
namespace detail { namespace thread {
|
||||||
|
|
||||||
template <typename Mutex>
|
template <typename Mutex>
|
||||||
class lock_ops : private noncopyable
|
class lock_ops : private noncopyable
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
lock_ops() { }
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef typename Mutex::cv_state lock_state;
|
||||||
|
|
||||||
|
static void lock(Mutex& m)
|
||||||
{
|
{
|
||||||
private:
|
m.do_lock();
|
||||||
lock_ops() { }
|
}
|
||||||
|
static bool trylock(Mutex& m)
|
||||||
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:
|
return m.do_trylock();
|
||||||
typedef Mutex mutex_type;
|
}
|
||||||
|
static bool timedlock(Mutex& m, const xtime& xt)
|
||||||
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:
|
return m.do_timedlock(xt);
|
||||||
typedef TryMutex mutex_type;
|
}
|
||||||
|
static void unlock(Mutex& m)
|
||||||
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:
|
m.do_unlock();
|
||||||
typedef TimedMutex mutex_type;
|
}
|
||||||
|
static void lock(Mutex& m, lock_state& state)
|
||||||
|
{
|
||||||
|
m.do_lock(state);
|
||||||
|
}
|
||||||
|
static void unlock(Mutex& m, lock_state& state)
|
||||||
|
{
|
||||||
|
m.do_unlock(state);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
scoped_timed_lock(TimedMutex& mx, const xtime& xt)
|
template <typename Mutex>
|
||||||
: m_mutex(mx), m_locked(false)
|
class scoped_lock : private noncopyable
|
||||||
{
|
{
|
||||||
timed_lock(xt);
|
public:
|
||||||
}
|
typedef Mutex mutex_type;
|
||||||
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()
|
explicit scoped_lock(Mutex& mx, bool initially_locked=true)
|
||||||
{
|
: m_mutex(mx), m_locked(false)
|
||||||
if (m_locked) throw lock_error();
|
{
|
||||||
lock_ops<TimedMutex>::lock(m_mutex);
|
if (initially_locked) lock();
|
||||||
m_locked = true;
|
}
|
||||||
}
|
~scoped_lock()
|
||||||
bool timed_lock(const xtime& xt)
|
{
|
||||||
{
|
if (m_locked) unlock();
|
||||||
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; }
|
void lock()
|
||||||
operator const void*() const { return m_locked ? this : 0; }
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
bool locked() const { return m_locked; }
|
||||||
friend class boost::condition;
|
operator const void*() const { return m_locked ? this : 0; }
|
||||||
|
|
||||||
TimedMutex& m_mutex;
|
private:
|
||||||
bool m_locked;
|
friend class boost::condition;
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace thread
|
Mutex& m_mutex;
|
||||||
} // namespace detail
|
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 try_lock()
|
||||||
|
{
|
||||||
|
if (m_locked) throw lock_error();
|
||||||
|
return (m_locked = lock_ops<TimedMutex>::trylock(m_mutex));
|
||||||
|
}
|
||||||
|
bool timed_lock(const xtime& xt)
|
||||||
|
{
|
||||||
|
if (m_locked) throw lock_error();
|
||||||
|
return (m_locked = lock_ops<TimedMutex>::timedlock(m_mutex, xt));
|
||||||
|
}
|
||||||
|
void unlock()
|
||||||
|
{
|
||||||
|
if (!m_locked) throw lock_error();
|
||||||
|
lock_ops<TimedMutex>::unlock(m_mutex);
|
||||||
|
m_locked = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool locked() const { return m_locked; }
|
||||||
|
operator const void*() const { return m_locked ? this : 0; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class boost::condition;
|
||||||
|
|
||||||
|
TimedMutex& m_mutex;
|
||||||
|
bool m_locked;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace thread
|
||||||
|
} // namespace detail
|
||||||
} // namespace boost
|
} // namespace boost
|
||||||
|
|
||||||
|
#endif // BOOST_XLOCK_WEK070601_HPP
|
||||||
|
|
||||||
// Change Log:
|
// Change Log:
|
||||||
// 8 Feb 01 WEKEMPF Initial version.
|
// 8 Feb 01 WEKEMPF Initial version.
|
||||||
// 22 May 01 WEKEMPF Modified to use xtime for time outs.
|
// 22 May 01 WEKEMPF Modified to use xtime for time outs.
|
||||||
// 30 Jul 01 WEKEMPF Moved lock types into boost::detail::thread. Renamed some types.
|
// 30 Jul 01 WEKEMPF Moved lock types into boost::detail::thread. Renamed
|
||||||
// Added locked() methods.
|
// some types. Added locked() methods.
|
||||||
|
|
||||||
#endif // BOOST_XLOCK_WEK070601_HPP
|
|
||||||
|
|||||||
38
include/boost/thread/detail/named.hpp
Normal file
38
include/boost/thread/detail/named.hpp
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
// Copyright (C) 2001-2003
|
||||||
|
// William E. Kempf
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
|
// and its documentation for any purpose is hereby granted without fee,
|
||||||
|
// provided that the above copyright notice appear in all copies and
|
||||||
|
// that both that copyright notice and this permission notice appear
|
||||||
|
// in supporting documentation. William E. Kempf makes no representations
|
||||||
|
// about the suitability of this software for any purpose.
|
||||||
|
// It is provided "as is" without express or implied warranty.
|
||||||
|
|
||||||
|
#ifndef BOOST_NAMED_WEK031703_HPP
|
||||||
|
#define BOOST_NAMED_WEK031703_HPP
|
||||||
|
|
||||||
|
#include <boost/thread/detail/config.hpp>
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
class named_object
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
named_object(const char* name=0);
|
||||||
|
~named_object();
|
||||||
|
|
||||||
|
public:
|
||||||
|
const char* name() const;
|
||||||
|
const char* effective_name() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
char* m_name;
|
||||||
|
char* m_ename;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
#endif // BOOST_NAMED_WEK031703_HPP
|
||||||
1111
include/boost/thread/detail/read_write_lock.hpp
Normal file
1111
include/boost/thread/detail/read_write_lock.hpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2001
|
// Copyright (C) 2001-2003
|
||||||
// Mac Murrett
|
// Mac Murrett
|
||||||
//
|
//
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
@@ -14,51 +14,50 @@
|
|||||||
#ifndef BOOST_SINGLETON_MJM012402_HPP
|
#ifndef BOOST_SINGLETON_MJM012402_HPP
|
||||||
#define BOOST_SINGLETON_MJM012402_HPP
|
#define BOOST_SINGLETON_MJM012402_HPP
|
||||||
|
|
||||||
|
#include <boost/thread/detail/config.hpp>
|
||||||
|
|
||||||
namespace boost {
|
namespace boost {
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
namespace thread {
|
namespace thread {
|
||||||
|
|
||||||
// class singleton has the same goal as all singletons: create one instance of a
|
// class singleton has the same goal as all singletons: create one instance of
|
||||||
// class on demand, then dish it out as requested.
|
// a class on demand, then dish it out as requested.
|
||||||
|
|
||||||
template<class T>
|
template <class T>
|
||||||
class singleton: private T
|
class singleton : private T
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
singleton();
|
singleton();
|
||||||
~singleton();
|
~singleton();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static T &instance();
|
static T &instance();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template<class T>
|
template <class T>
|
||||||
inline singleton<T>::singleton()
|
inline singleton<T>::singleton()
|
||||||
{ /* no-op */ }
|
{
|
||||||
|
/* no-op */
|
||||||
|
}
|
||||||
|
|
||||||
template<class T>
|
template <class T>
|
||||||
inline singleton<T>::~singleton()
|
inline singleton<T>::~singleton()
|
||||||
{ /* no-op */ }
|
{
|
||||||
|
/* no-op */
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
template<class T>
|
|
||||||
/*static*/ T &singleton<T>::instance()
|
/*static*/ T &singleton<T>::instance()
|
||||||
{
|
{
|
||||||
// function-local static to force this to work correctly at static initialization
|
// function-local static to force this to work correctly at static
|
||||||
// time.
|
// initialization time.
|
||||||
static singleton<T> s_oT;
|
static singleton<T> s_oT;
|
||||||
return(s_oT);
|
return(s_oT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace thread
|
} // namespace thread
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
} // namespace boost
|
} // namespace boost
|
||||||
|
|
||||||
|
|
||||||
#endif // BOOST_SINGLETON_MJM012402_HPP
|
#endif // BOOST_SINGLETON_MJM012402_HPP
|
||||||
|
|||||||
@@ -1,14 +1,35 @@
|
|||||||
#include <boost/config.hpp>
|
// Copyright (C) 2001-2003
|
||||||
#ifndef BOOST_HAS_THREADS
|
// William E. Kempf
|
||||||
# error Thread support is unavailable!
|
//
|
||||||
#endif
|
// 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_THREADMON_WEK062504_HPP
|
||||||
|
#define BOOST_THREADMON_WEK062504_HPP
|
||||||
|
|
||||||
#include <boost/thread/detail/config.hpp>
|
#include <boost/thread/detail/config.hpp>
|
||||||
|
|
||||||
#ifdef BOOST_HAS_WINTHREADS
|
#ifdef BOOST_HAS_WINTHREADS
|
||||||
|
|
||||||
#include <boost/thread/detail/config.hpp>
|
extern "C" BOOST_THREAD_DECL int at_thread_exit(void (__cdecl * func)(void));
|
||||||
|
//Add a function to the list of thread-exit functions
|
||||||
|
|
||||||
extern "C" BOOST_THREAD_DECL int on_thread_exit(void (__cdecl * func)(void));
|
extern "C" BOOST_THREAD_DECL void on_process_enter(void);
|
||||||
|
//To be called when the process starts, when the dll is loaded, etc.
|
||||||
|
//Called automatically by Boost.Thread when possible
|
||||||
|
extern "C" BOOST_THREAD_DECL void on_thread_exit(void);
|
||||||
|
//To be called for each thread when it exits
|
||||||
|
//Must be called in the context of the thread that is exiting
|
||||||
|
//Called automatically by Boost.Thread when possible
|
||||||
|
extern "C" BOOST_THREAD_DECL void on_process_exit(void);
|
||||||
|
//To be called when the process exits, when the dll is unloaded, etc.
|
||||||
|
//Called automatically by Boost.Thread when possible
|
||||||
|
|
||||||
#endif // BOOST_HAS_WINTHREADS
|
#endif // BOOST_HAS_WINTHREADS
|
||||||
|
|
||||||
|
#endif // BOOST_THREADMON_WEK062504_HPP
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2001
|
// Copyright (C) 2001-2003
|
||||||
// William E. Kempf
|
// William E. Kempf
|
||||||
//
|
//
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
@@ -12,7 +12,6 @@
|
|||||||
#ifndef BOOST_THREAD_EXCEPTIONS_PDM070801_H
|
#ifndef BOOST_THREAD_EXCEPTIONS_PDM070801_H
|
||||||
#define BOOST_THREAD_EXCEPTIONS_PDM070801_H
|
#define BOOST_THREAD_EXCEPTIONS_PDM070801_H
|
||||||
|
|
||||||
#include <boost/config.hpp>
|
|
||||||
#include <boost/thread/detail/config.hpp>
|
#include <boost/thread/detail/config.hpp>
|
||||||
|
|
||||||
// pdm: Sorry, but this class is used all over the place & I end up
|
// pdm: Sorry, but this class is used all over the place & I end up
|
||||||
@@ -25,21 +24,77 @@
|
|||||||
|
|
||||||
namespace boost {
|
namespace boost {
|
||||||
|
|
||||||
class BOOST_THREAD_DECL lock_error : public std::logic_error
|
class BOOST_THREAD_DECL thread_exception : public std::exception
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
thread_exception();
|
||||||
|
thread_exception(int sys_err_code);
|
||||||
|
|
||||||
|
public:
|
||||||
|
~thread_exception() throw();
|
||||||
|
|
||||||
|
int native_error() const { return m_sys_err; }
|
||||||
|
|
||||||
|
const char* message() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_sys_err;
|
||||||
|
};
|
||||||
|
|
||||||
|
class BOOST_THREAD_DECL lock_error : public thread_exception
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
lock_error();
|
lock_error();
|
||||||
|
lock_error(int sys_err_code);
|
||||||
|
~lock_error() throw();
|
||||||
|
|
||||||
|
virtual const char* what() const throw();
|
||||||
};
|
};
|
||||||
|
|
||||||
class BOOST_THREAD_DECL thread_resource_error : public std::runtime_error
|
class BOOST_THREAD_DECL thread_resource_error : public thread_exception
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
thread_resource_error();
|
thread_resource_error();
|
||||||
|
thread_resource_error(int sys_err_code);
|
||||||
|
~thread_resource_error() throw();
|
||||||
|
|
||||||
|
virtual const char* what() const throw();
|
||||||
|
};
|
||||||
|
|
||||||
|
class BOOST_THREAD_DECL unsupported_thread_option : public thread_exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
unsupported_thread_option();
|
||||||
|
unsupported_thread_option(int sys_err_code);
|
||||||
|
~unsupported_thread_option() throw();
|
||||||
|
|
||||||
|
virtual const char* what() const throw();
|
||||||
|
};
|
||||||
|
|
||||||
|
class BOOST_THREAD_DECL invalid_thread_argument : public thread_exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
invalid_thread_argument();
|
||||||
|
invalid_thread_argument(int sys_err_code);
|
||||||
|
~invalid_thread_argument() throw();
|
||||||
|
|
||||||
|
virtual const char* what() const throw();
|
||||||
|
};
|
||||||
|
|
||||||
|
class BOOST_THREAD_DECL thread_permission_error : public thread_exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
thread_permission_error();
|
||||||
|
thread_permission_error(int sys_err_code);
|
||||||
|
~thread_permission_error() throw();
|
||||||
|
|
||||||
|
virtual const char* what() const throw();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace boost
|
} // namespace boost
|
||||||
|
|
||||||
|
#endif // BOOST_THREAD_CONFIG_PDM070801_H
|
||||||
|
|
||||||
// Change log:
|
// Change log:
|
||||||
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
|
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
|
||||||
|
|
||||||
#endif // BOOST_THREAD_CONFIG_PDM070801_H
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2001
|
// Copyright (C) 2001-2003
|
||||||
// William E. Kempf
|
// William E. Kempf
|
||||||
//
|
//
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
@@ -12,14 +12,11 @@
|
|||||||
#ifndef BOOST_MUTEX_WEK070601_HPP
|
#ifndef BOOST_MUTEX_WEK070601_HPP
|
||||||
#define BOOST_MUTEX_WEK070601_HPP
|
#define BOOST_MUTEX_WEK070601_HPP
|
||||||
|
|
||||||
#include <boost/config.hpp>
|
#include <boost/thread/detail/config.hpp>
|
||||||
#ifndef BOOST_HAS_THREADS
|
|
||||||
# error Thread support is unavailable!
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <boost/utility.hpp>
|
#include <boost/utility.hpp>
|
||||||
#include <boost/thread/detail/lock.hpp>
|
#include <boost/thread/detail/lock.hpp>
|
||||||
#include <boost/thread/detail/config.hpp>
|
#include <boost/thread/detail/named.hpp>
|
||||||
|
|
||||||
#if defined(BOOST_HAS_PTHREADS)
|
#if defined(BOOST_HAS_PTHREADS)
|
||||||
# include <pthread.h>
|
# include <pthread.h>
|
||||||
@@ -33,14 +30,16 @@ namespace boost {
|
|||||||
|
|
||||||
struct xtime;
|
struct xtime;
|
||||||
|
|
||||||
class BOOST_THREAD_DECL mutex : private noncopyable
|
class BOOST_THREAD_DECL mutex
|
||||||
|
: private noncopyable
|
||||||
|
, public boost::detail::named_object
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
friend class detail::thread::lock_ops<mutex>;
|
friend class detail::thread::lock_ops<mutex>;
|
||||||
|
|
||||||
typedef detail::thread::scoped_lock<mutex> scoped_lock;
|
typedef detail::thread::scoped_lock<mutex> scoped_lock;
|
||||||
|
|
||||||
mutex();
|
mutex(const char* name=0);
|
||||||
~mutex();
|
~mutex();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -63,6 +62,7 @@ private:
|
|||||||
|
|
||||||
#if defined(BOOST_HAS_WINTHREADS)
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
void* m_mutex;
|
void* m_mutex;
|
||||||
|
bool m_critical_section;
|
||||||
#elif defined(BOOST_HAS_PTHREADS)
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
pthread_mutex_t m_mutex;
|
pthread_mutex_t m_mutex;
|
||||||
#elif defined(BOOST_HAS_MPTASKS)
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
@@ -71,7 +71,9 @@ private:
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
class BOOST_THREAD_DECL try_mutex : private noncopyable
|
class BOOST_THREAD_DECL try_mutex
|
||||||
|
: private noncopyable
|
||||||
|
, public boost::detail::named_object
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
friend class detail::thread::lock_ops<try_mutex>;
|
friend class detail::thread::lock_ops<try_mutex>;
|
||||||
@@ -79,7 +81,7 @@ public:
|
|||||||
typedef detail::thread::scoped_lock<try_mutex> scoped_lock;
|
typedef detail::thread::scoped_lock<try_mutex> scoped_lock;
|
||||||
typedef detail::thread::scoped_try_lock<try_mutex> scoped_try_lock;
|
typedef detail::thread::scoped_try_lock<try_mutex> scoped_try_lock;
|
||||||
|
|
||||||
try_mutex();
|
try_mutex(const char* name=0);
|
||||||
~try_mutex();
|
~try_mutex();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -103,6 +105,7 @@ private:
|
|||||||
|
|
||||||
#if defined(BOOST_HAS_WINTHREADS)
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
void* m_mutex;
|
void* m_mutex;
|
||||||
|
bool m_critical_section;
|
||||||
#elif defined(BOOST_HAS_PTHREADS)
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
pthread_mutex_t m_mutex;
|
pthread_mutex_t m_mutex;
|
||||||
#elif defined(BOOST_HAS_MPTASKS)
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
@@ -111,7 +114,9 @@ private:
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
class BOOST_THREAD_DECL timed_mutex : private noncopyable
|
class BOOST_THREAD_DECL timed_mutex
|
||||||
|
: private noncopyable
|
||||||
|
, public boost::detail::named_object
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
friend class detail::thread::lock_ops<timed_mutex>;
|
friend class detail::thread::lock_ops<timed_mutex>;
|
||||||
@@ -120,7 +125,7 @@ public:
|
|||||||
typedef detail::thread::scoped_try_lock<timed_mutex> scoped_try_lock;
|
typedef detail::thread::scoped_try_lock<timed_mutex> scoped_try_lock;
|
||||||
typedef detail::thread::scoped_timed_lock<timed_mutex> scoped_timed_lock;
|
typedef detail::thread::scoped_timed_lock<timed_mutex> scoped_timed_lock;
|
||||||
|
|
||||||
timed_mutex();
|
timed_mutex(const char* name=0);
|
||||||
~timed_mutex();
|
~timed_mutex();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2001
|
// Copyright (C) 2001-2003
|
||||||
// William E. Kempf
|
// William E. Kempf
|
||||||
//
|
//
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
@@ -12,11 +12,6 @@
|
|||||||
#ifndef BOOST_ONCE_WEK080101_HPP
|
#ifndef BOOST_ONCE_WEK080101_HPP
|
||||||
#define BOOST_ONCE_WEK080101_HPP
|
#define BOOST_ONCE_WEK080101_HPP
|
||||||
|
|
||||||
#include <boost/config.hpp>
|
|
||||||
#ifndef BOOST_HAS_THREADS
|
|
||||||
# error Thread support is unavailable!
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <boost/thread/detail/config.hpp>
|
#include <boost/thread/detail/config.hpp>
|
||||||
|
|
||||||
#if defined(BOOST_HAS_PTHREADS)
|
#if defined(BOOST_HAS_PTHREADS)
|
||||||
|
|||||||
271
include/boost/thread/read_write_mutex.hpp
Normal file
271
include/boost/thread/read_write_mutex.hpp
Normal file
@@ -0,0 +1,271 @@
|
|||||||
|
// Copyright (C) 2002-2003
|
||||||
|
// David Moore, William E. Kempf
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
|
// and its documentation for any purpose is hereby granted without fee,
|
||||||
|
// provided that the above copyright notice appear in all copies and
|
||||||
|
// that both that copyright notice and this permission notice appear
|
||||||
|
// in supporting documentation. David Moore makes no representations
|
||||||
|
// about the suitability of this software for any purpose.
|
||||||
|
// It is provided "as is" without express or implied warranty.
|
||||||
|
|
||||||
|
// A Boost::threads implementation of a synchronization
|
||||||
|
// primitive which can allow multiple readers or a single
|
||||||
|
// writer to have access to a shared resource.
|
||||||
|
|
||||||
|
#ifndef BOOST_READ_WRITE_MUTEX_JDM030602_HPP
|
||||||
|
#define BOOST_READ_WRITE_MUTEX_JDM030602_HPP
|
||||||
|
|
||||||
|
#include <boost/thread/detail/config.hpp>
|
||||||
|
|
||||||
|
#include <boost/utility.hpp>
|
||||||
|
|
||||||
|
#include <boost/thread/mutex.hpp>
|
||||||
|
#include <boost/thread/detail/lock.hpp>
|
||||||
|
#include <boost/thread/detail/read_write_lock.hpp>
|
||||||
|
#include <boost/thread/condition.hpp>
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
namespace read_write_scheduling_policy {
|
||||||
|
enum read_write_scheduling_policy_enum
|
||||||
|
{
|
||||||
|
writer_priority, //Prefer writers; can starve readers
|
||||||
|
reader_priority, //Prefer readers; can starve writers
|
||||||
|
alternating_many_reads, //Alternate readers and writers; before a writer, release all queued readers
|
||||||
|
alternating_single_read //Alternate readers and writers; before a writer, release only on queued reader
|
||||||
|
};
|
||||||
|
} // namespace read_write_scheduling_policy
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
namespace thread {
|
||||||
|
|
||||||
|
// Shared implementation construct for explicit Scheduling Policies
|
||||||
|
// This implementation is susceptible to self-deadlock, though....
|
||||||
|
template<typename Mutex>
|
||||||
|
struct read_write_mutex_impl
|
||||||
|
{
|
||||||
|
typedef Mutex mutex_type;
|
||||||
|
typedef detail::thread::scoped_lock<Mutex> scoped_lock;
|
||||||
|
typedef detail::thread::scoped_try_lock<Mutex> scoped_try_lock;
|
||||||
|
typedef detail::thread::scoped_timed_lock<Mutex> scoped_timed_lock;
|
||||||
|
|
||||||
|
read_write_mutex_impl(read_write_scheduling_policy::read_write_scheduling_policy_enum sp)
|
||||||
|
: m_num_waiting_writers(0),
|
||||||
|
m_num_waiting_readers(0),
|
||||||
|
m_num_readers_to_wake(0),
|
||||||
|
m_state_waiting_promotion(false),
|
||||||
|
m_state(0),
|
||||||
|
m_sp(sp),
|
||||||
|
m_readers_next(true) { }
|
||||||
|
|
||||||
|
Mutex m_prot;
|
||||||
|
boost::condition m_waiting_writers;
|
||||||
|
boost::condition m_waiting_readers;
|
||||||
|
int m_num_waiting_writers;
|
||||||
|
int m_num_waiting_readers;
|
||||||
|
int m_num_readers_to_wake;
|
||||||
|
boost::condition m_waiting_promotion;
|
||||||
|
bool m_state_waiting_promotion;
|
||||||
|
int m_state; // -1 = excl locked
|
||||||
|
// 0 = unlocked
|
||||||
|
// 1-> INT_MAX - shared locked
|
||||||
|
const read_write_scheduling_policy::read_write_scheduling_policy_enum m_sp;
|
||||||
|
bool m_readers_next;
|
||||||
|
|
||||||
|
void do_read_lock();
|
||||||
|
void do_write_lock();
|
||||||
|
void do_write_unlock();
|
||||||
|
void do_read_unlock();
|
||||||
|
bool do_try_write_lock();
|
||||||
|
bool do_try_read_lock();
|
||||||
|
bool do_timed_write_lock(const xtime &xt);
|
||||||
|
bool do_timed_read_lock(const xtime &xt);
|
||||||
|
|
||||||
|
void do_demote_to_read_lock();
|
||||||
|
bool do_try_demote_to_read_lock();
|
||||||
|
bool do_timed_demote_to_read_lock(const xtime &xt);
|
||||||
|
|
||||||
|
void do_promote_to_write_lock();
|
||||||
|
bool do_try_promote_to_write_lock();
|
||||||
|
bool do_timed_promote_to_write_lock(const xtime &xt);
|
||||||
|
|
||||||
|
bool locked();
|
||||||
|
read_write_lock_state::read_write_lock_state_enum state();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void do_unlock_scheduling_impl();
|
||||||
|
void do_demote_scheduling_impl();
|
||||||
|
void do_scheduling_impl();
|
||||||
|
bool do_demote_to_read_lock_impl();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
} // namespace thread
|
||||||
|
|
||||||
|
class BOOST_THREAD_DECL read_write_mutex : private noncopyable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
read_write_mutex(read_write_scheduling_policy::read_write_scheduling_policy_enum sp) : m_impl(sp) { }
|
||||||
|
~read_write_mutex() { }
|
||||||
|
|
||||||
|
read_write_scheduling_policy::read_write_scheduling_policy_enum policy() const { return m_impl.m_sp; }
|
||||||
|
|
||||||
|
friend class detail::thread::read_write_lock_ops<read_write_mutex>;
|
||||||
|
|
||||||
|
typedef detail::thread::scoped_read_write_lock<
|
||||||
|
read_write_mutex> scoped_read_write_lock;
|
||||||
|
|
||||||
|
typedef detail::thread::scoped_read_lock<
|
||||||
|
read_write_mutex> scoped_read_lock;
|
||||||
|
|
||||||
|
typedef detail::thread::scoped_write_lock<
|
||||||
|
read_write_mutex> scoped_write_lock;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// Operations that will eventually be done only
|
||||||
|
// via lock types
|
||||||
|
void do_write_lock();
|
||||||
|
void do_read_lock();
|
||||||
|
void do_write_unlock();
|
||||||
|
void do_read_unlock();
|
||||||
|
|
||||||
|
void do_demote_to_read_lock();
|
||||||
|
|
||||||
|
void do_promote_to_write_lock();
|
||||||
|
|
||||||
|
bool locked();
|
||||||
|
read_write_lock_state::read_write_lock_state_enum state();
|
||||||
|
|
||||||
|
detail::thread::read_write_mutex_impl<mutex> m_impl;
|
||||||
|
};
|
||||||
|
|
||||||
|
class BOOST_THREAD_DECL try_read_write_mutex : private noncopyable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
try_read_write_mutex(read_write_scheduling_policy::read_write_scheduling_policy_enum sp) : m_impl(sp) { }
|
||||||
|
~try_read_write_mutex() { }
|
||||||
|
|
||||||
|
read_write_scheduling_policy::read_write_scheduling_policy_enum policy() const { return m_impl.m_sp; }
|
||||||
|
|
||||||
|
friend class detail::thread::read_write_lock_ops<try_read_write_mutex>;
|
||||||
|
|
||||||
|
typedef detail::thread::scoped_read_write_lock<
|
||||||
|
try_read_write_mutex> scoped_read_write_lock;
|
||||||
|
typedef detail::thread::scoped_try_read_write_lock<
|
||||||
|
try_read_write_mutex> scoped_try_read_write_lock;
|
||||||
|
|
||||||
|
typedef detail::thread::scoped_read_lock<
|
||||||
|
try_read_write_mutex> scoped_read_lock;
|
||||||
|
typedef detail::thread::scoped_try_read_lock<
|
||||||
|
try_read_write_mutex> scoped_try_read_lock;
|
||||||
|
|
||||||
|
typedef detail::thread::scoped_write_lock<
|
||||||
|
try_read_write_mutex> scoped_write_lock;
|
||||||
|
typedef detail::thread::scoped_try_write_lock<
|
||||||
|
try_read_write_mutex> scoped_try_write_lock;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// Operations that will eventually be done only
|
||||||
|
// via lock types
|
||||||
|
void do_write_lock();
|
||||||
|
void do_read_lock();
|
||||||
|
void do_write_unlock();
|
||||||
|
void do_read_unlock();
|
||||||
|
bool do_try_write_lock();
|
||||||
|
bool do_try_read_lock();
|
||||||
|
|
||||||
|
|
||||||
|
void do_demote_to_read_lock();
|
||||||
|
bool do_try_demote_to_read_lock();
|
||||||
|
|
||||||
|
void do_promote_to_write_lock();
|
||||||
|
bool do_try_promote_to_write_lock();
|
||||||
|
|
||||||
|
bool locked();
|
||||||
|
read_write_lock_state::read_write_lock_state_enum state();
|
||||||
|
|
||||||
|
detail::thread::read_write_mutex_impl<try_mutex> m_impl;
|
||||||
|
};
|
||||||
|
|
||||||
|
class BOOST_THREAD_DECL timed_read_write_mutex : private noncopyable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
timed_read_write_mutex(read_write_scheduling_policy::read_write_scheduling_policy_enum sp) : m_impl(sp) { }
|
||||||
|
~timed_read_write_mutex() { }
|
||||||
|
|
||||||
|
read_write_scheduling_policy::read_write_scheduling_policy_enum policy() const { return m_impl.m_sp; }
|
||||||
|
|
||||||
|
friend class detail::thread::read_write_lock_ops<timed_read_write_mutex>;
|
||||||
|
|
||||||
|
typedef detail::thread::scoped_read_write_lock<
|
||||||
|
timed_read_write_mutex> scoped_read_write_lock;
|
||||||
|
typedef detail::thread::scoped_try_read_write_lock<
|
||||||
|
timed_read_write_mutex> scoped_try_read_write_lock;
|
||||||
|
typedef detail::thread::scoped_timed_read_write_lock<
|
||||||
|
timed_read_write_mutex> scoped_timed_read_write_lock;
|
||||||
|
|
||||||
|
typedef detail::thread::scoped_read_lock<
|
||||||
|
timed_read_write_mutex> scoped_read_lock;
|
||||||
|
typedef detail::thread::scoped_try_read_lock<
|
||||||
|
timed_read_write_mutex> scoped_try_read_lock;
|
||||||
|
typedef detail::thread::scoped_timed_read_lock<
|
||||||
|
timed_read_write_mutex> scoped_timed_read_lock;
|
||||||
|
|
||||||
|
typedef detail::thread::scoped_write_lock<
|
||||||
|
timed_read_write_mutex> scoped_write_lock;
|
||||||
|
typedef detail::thread::scoped_try_write_lock<
|
||||||
|
timed_read_write_mutex> scoped_try_write_lock;
|
||||||
|
typedef detail::thread::scoped_timed_write_lock<
|
||||||
|
timed_read_write_mutex> scoped_timed_write_lock;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// Operations that will eventually be done only
|
||||||
|
// via lock types
|
||||||
|
void do_write_lock();
|
||||||
|
void do_read_lock();
|
||||||
|
void do_write_unlock();
|
||||||
|
void do_read_unlock();
|
||||||
|
bool do_try_write_lock();
|
||||||
|
bool do_try_read_lock();
|
||||||
|
bool do_timed_write_lock(const xtime &xt);
|
||||||
|
bool do_timed_read_lock(const xtime &xt);
|
||||||
|
|
||||||
|
void do_demote_to_read_lock();
|
||||||
|
bool do_try_demote_to_read_lock();
|
||||||
|
bool do_timed_demote_to_read_lock(const xtime &xt);
|
||||||
|
|
||||||
|
void do_promote_to_write_lock();
|
||||||
|
bool do_try_promote_to_write_lock();
|
||||||
|
bool do_timed_promote_to_write_lock(const xtime &xt);
|
||||||
|
|
||||||
|
bool locked();
|
||||||
|
read_write_lock_state::read_write_lock_state_enum state();
|
||||||
|
|
||||||
|
detail::thread::read_write_mutex_impl<timed_mutex> m_impl;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Change Log:
|
||||||
|
// 10 Mar 02
|
||||||
|
// Original version.
|
||||||
|
// 4 May 04 GlassfordM
|
||||||
|
// Implement lock promotion and demotion.
|
||||||
|
// Add locked() and state() member functions for debugging
|
||||||
|
// (should these be made public?).
|
||||||
|
// Rename to improve consistency and eliminate abbreviations:
|
||||||
|
// Use "read" and "write" instead of "shared" and "exclusive".
|
||||||
|
// Change "rd" to "read", "wr" to "write", "rw" to "read_write".
|
||||||
|
// Add mutex_type typdef.
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2001
|
// Copyright (C) 2001-2003
|
||||||
// William E. Kempf
|
// William E. Kempf
|
||||||
//
|
//
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
@@ -12,18 +12,17 @@
|
|||||||
#ifndef BOOST_RECURSIVE_MUTEX_WEK070601_HPP
|
#ifndef BOOST_RECURSIVE_MUTEX_WEK070601_HPP
|
||||||
#define BOOST_RECURSIVE_MUTEX_WEK070601_HPP
|
#define BOOST_RECURSIVE_MUTEX_WEK070601_HPP
|
||||||
|
|
||||||
#include <boost/config.hpp>
|
#include <boost/thread/detail/config.hpp>
|
||||||
#ifndef BOOST_HAS_THREADS
|
|
||||||
# error Thread support is unavailable!
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <boost/utility.hpp>
|
#include <boost/utility.hpp>
|
||||||
#include <boost/thread/detail/lock.hpp>
|
#include <boost/thread/detail/lock.hpp>
|
||||||
#include <boost/thread/detail/config.hpp>
|
#include <boost/thread/detail/named.hpp>
|
||||||
|
|
||||||
#if defined(BOOST_HAS_PTHREADS)
|
#if defined(BOOST_HAS_PTHREADS)
|
||||||
# include <pthread.h>
|
# include <pthread.h>
|
||||||
#elif defined(BOOST_HAS_MPTASKS)
|
#endif
|
||||||
|
|
||||||
|
#if defined(BOOST_HAS_MPTASKS)
|
||||||
# include "scoped_critical_region.hpp"
|
# include "scoped_critical_region.hpp"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -31,14 +30,16 @@ namespace boost {
|
|||||||
|
|
||||||
struct xtime;
|
struct xtime;
|
||||||
|
|
||||||
class BOOST_THREAD_DECL recursive_mutex : private noncopyable
|
class BOOST_THREAD_DECL recursive_mutex
|
||||||
|
: private noncopyable
|
||||||
|
, public boost::detail::named_object
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
friend class detail::thread::lock_ops<recursive_mutex>;
|
friend class detail::thread::lock_ops<recursive_mutex>;
|
||||||
|
|
||||||
typedef detail::thread::scoped_lock<recursive_mutex> scoped_lock;
|
typedef detail::thread::scoped_lock<recursive_mutex> scoped_lock;
|
||||||
|
|
||||||
recursive_mutex();
|
recursive_mutex(const char* name=0);
|
||||||
~recursive_mutex();
|
~recursive_mutex();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -58,6 +59,7 @@ private:
|
|||||||
|
|
||||||
#if defined(BOOST_HAS_WINTHREADS)
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
void* m_mutex;
|
void* m_mutex;
|
||||||
|
bool m_critical_section;
|
||||||
unsigned long m_count;
|
unsigned long m_count;
|
||||||
#elif defined(BOOST_HAS_PTHREADS)
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
pthread_mutex_t m_mutex;
|
pthread_mutex_t m_mutex;
|
||||||
@@ -74,15 +76,18 @@ private:
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
class BOOST_THREAD_DECL recursive_try_mutex : private noncopyable
|
class BOOST_THREAD_DECL recursive_try_mutex
|
||||||
|
: private noncopyable
|
||||||
|
, public boost::detail::named_object
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
friend class detail::thread::lock_ops<recursive_try_mutex>;
|
friend class detail::thread::lock_ops<recursive_try_mutex>;
|
||||||
|
|
||||||
typedef detail::thread::scoped_lock<recursive_try_mutex> scoped_lock;
|
typedef detail::thread::scoped_lock<recursive_try_mutex> scoped_lock;
|
||||||
typedef detail::thread::scoped_try_lock<recursive_try_mutex> scoped_try_lock;
|
typedef detail::thread::scoped_try_lock<
|
||||||
|
recursive_try_mutex> scoped_try_lock;
|
||||||
|
|
||||||
recursive_try_mutex();
|
recursive_try_mutex(const char* name=0);
|
||||||
~recursive_try_mutex();
|
~recursive_try_mutex();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -103,6 +108,7 @@ private:
|
|||||||
|
|
||||||
#if defined(BOOST_HAS_WINTHREADS)
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
void* m_mutex;
|
void* m_mutex;
|
||||||
|
bool m_critical_section;
|
||||||
unsigned long m_count;
|
unsigned long m_count;
|
||||||
#elif defined(BOOST_HAS_PTHREADS)
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
pthread_mutex_t m_mutex;
|
pthread_mutex_t m_mutex;
|
||||||
@@ -119,16 +125,20 @@ private:
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
class BOOST_THREAD_DECL recursive_timed_mutex : private noncopyable
|
class BOOST_THREAD_DECL recursive_timed_mutex
|
||||||
|
: private noncopyable
|
||||||
|
, public boost::detail::named_object
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
friend class detail::thread::lock_ops<recursive_timed_mutex>;
|
friend class detail::thread::lock_ops<recursive_timed_mutex>;
|
||||||
|
|
||||||
typedef detail::thread::scoped_lock<recursive_timed_mutex> scoped_lock;
|
typedef detail::thread::scoped_lock<recursive_timed_mutex> scoped_lock;
|
||||||
typedef detail::thread::scoped_try_lock<recursive_timed_mutex> scoped_try_lock;
|
typedef detail::thread::scoped_try_lock<
|
||||||
typedef detail::thread::scoped_timed_lock<recursive_timed_mutex> scoped_timed_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(const char* name=0);
|
||||||
~recursive_timed_mutex();
|
~recursive_timed_mutex();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -166,12 +176,11 @@ private:
|
|||||||
|
|
||||||
} // namespace boost
|
} // namespace boost
|
||||||
|
|
||||||
|
#endif // BOOST_RECURSIVE_MUTEX_WEK070601_HPP
|
||||||
|
|
||||||
// Change Log:
|
// Change Log:
|
||||||
// 8 Feb 01 WEKEMPF Initial version.
|
// 8 Feb 01 WEKEMPF Initial version.
|
||||||
// 1 Jun 01 WEKEMPF Modified to use xtime for time outs. Factored out
|
// 1 Jun 01 WEKEMPF Modified to use xtime for time outs. Factored out
|
||||||
// to three classes, mutex, try_mutex and timed_mutex.
|
// to three classes, mutex, try_mutex and timed_mutex.
|
||||||
// 11 Jun 01 WEKEMPF Modified to use PTHREAD_MUTEX_RECURSIVE if available.
|
// 11 Jun 01 WEKEMPF Modified to use PTHREAD_MUTEX_RECURSIVE if available.
|
||||||
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
|
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
|
||||||
|
|
||||||
|
|
||||||
#endif // BOOST_RECURSIVE_MUTEX_WEK070601_HPP
|
|
||||||
58
include/boost/thread/shared_memory.hpp
Normal file
58
include/boost/thread/shared_memory.hpp
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
// Copyright (C) 2002-2003
|
||||||
|
// William E. Kempf, David Moore
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
|
// and its documentation for any purpose is hereby granted without fee,
|
||||||
|
// provided that the above copyright notice appear in all copies and
|
||||||
|
// that both that copyright notice and this permission notice appear
|
||||||
|
// in supporting documentation. William E. Kempf makes no representations
|
||||||
|
// about the suitability of this software for any purpose.
|
||||||
|
// It is provided "as is" without express or implied warranty.
|
||||||
|
|
||||||
|
#ifndef BOOST_MUTEX_JDM062402_HPP
|
||||||
|
#define BOOST_MUTEX_JDM062402_HPP
|
||||||
|
|
||||||
|
#include <boost/thread/detail/config.hpp>
|
||||||
|
|
||||||
|
#include <boost/utility.hpp>
|
||||||
|
#include <boost/function.hpp>
|
||||||
|
|
||||||
|
#include <boost/thread/exceptions.hpp>
|
||||||
|
#include <boost/thread/detail/named.hpp>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
class shared_memory : public boost::detail::named_object
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum {
|
||||||
|
write=0x1,
|
||||||
|
create=0x2,
|
||||||
|
exclusive=0x4,
|
||||||
|
};
|
||||||
|
|
||||||
|
shared_memory(const char *name, std::size_t len, int flags);
|
||||||
|
shared_memory(const char *name, std::size_t len, int flags,
|
||||||
|
const boost::function1<void,void *>& initfunc);
|
||||||
|
~shared_memory();
|
||||||
|
|
||||||
|
void* get() const { return m_ptr; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void init(std::size_t len, int flags,
|
||||||
|
const boost::function1<void, void*>* initfunc);
|
||||||
|
|
||||||
|
void *m_ptr; // Pointer to shared memory block
|
||||||
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
void* m_hmap;
|
||||||
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
|
std::size_t m_len;
|
||||||
|
int m_hmap;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2001
|
// Copyright (C) 2001-2003
|
||||||
// William E. Kempf
|
// William E. Kempf
|
||||||
//
|
//
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
@@ -12,15 +12,11 @@
|
|||||||
#ifndef BOOST_THREAD_WEK070601_HPP
|
#ifndef BOOST_THREAD_WEK070601_HPP
|
||||||
#define BOOST_THREAD_WEK070601_HPP
|
#define BOOST_THREAD_WEK070601_HPP
|
||||||
|
|
||||||
#include <boost/config.hpp>
|
#include <boost/thread/detail/config.hpp>
|
||||||
#ifndef BOOST_HAS_THREADS
|
|
||||||
# error Thread support is unavailable!
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <boost/utility.hpp>
|
|
||||||
#include <boost/function.hpp>
|
#include <boost/function.hpp>
|
||||||
#include <boost/thread/mutex.hpp>
|
#include <boost/thread/mutex.hpp>
|
||||||
#include <boost/thread/detail/config.hpp>
|
#include <iostream>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
@@ -35,56 +31,163 @@ namespace boost {
|
|||||||
|
|
||||||
struct xtime;
|
struct xtime;
|
||||||
|
|
||||||
class BOOST_THREAD_DECL thread : private noncopyable
|
class BOOST_THREAD_DECL thread_cancel
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
thread_cancel();
|
||||||
|
~thread_cancel();
|
||||||
|
};
|
||||||
|
|
||||||
|
class BOOST_THREAD_DECL cancellation_guard
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cancellation_guard();
|
||||||
|
~cancellation_guard();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void* m_handle;
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
|
||||||
|
struct sched_param
|
||||||
|
{
|
||||||
|
int priority;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum { sched_fifo, sched_round_robin, sched_other };
|
||||||
|
enum { scope_process, scope_system };
|
||||||
|
|
||||||
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
|
|
||||||
|
using ::sched_param;
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
sched_fifo = SCHED_FIFO,
|
||||||
|
sched_round_robin = SCHED_RR,
|
||||||
|
sched_other = SCHED_OTHER
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
scope_process = PTHREAD_SCOPE_PROCESS,
|
||||||
|
scope_system = PTHREAD_SCOPE_SYSTEM
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class BOOST_THREAD_DECL thread
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
class BOOST_THREAD_DECL attributes
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
attributes();
|
||||||
|
~attributes();
|
||||||
|
|
||||||
|
attributes& set_stack_size(size_t size);
|
||||||
|
size_t get_stack_size() const;
|
||||||
|
|
||||||
|
attributes& set_stack_address(void* addr);
|
||||||
|
void* get_stack_address() const;
|
||||||
|
|
||||||
|
attributes& inherit_scheduling(bool inherit);
|
||||||
|
bool inherit_scheduling() const;
|
||||||
|
attributes& set_schedule(int policy, const sched_param& param);
|
||||||
|
void get_schedule(int& policy, sched_param& param);
|
||||||
|
attributes& scope(int scope);
|
||||||
|
int scope() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class thread;
|
||||||
|
|
||||||
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
size_t m_stacksize;
|
||||||
|
bool m_schedinherit;
|
||||||
|
sched_param m_schedparam;
|
||||||
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
|
pthread_attr_t m_attr;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
thread();
|
thread();
|
||||||
explicit thread(const function0<void>& threadfunc);
|
explicit thread(const function0<void>& threadfunc,
|
||||||
|
const attributes& attr=attributes());
|
||||||
|
thread(const thread& other);
|
||||||
~thread();
|
~thread();
|
||||||
|
|
||||||
|
thread& operator=(const thread& other);
|
||||||
|
|
||||||
bool operator==(const thread& other) const;
|
bool operator==(const thread& other) const;
|
||||||
bool operator!=(const thread& other) const;
|
bool operator!=(const thread& other) const;
|
||||||
|
bool operator<(const thread& other) const;
|
||||||
|
|
||||||
void join();
|
void join();
|
||||||
|
bool timed_join(const xtime& xt);
|
||||||
|
void cancel();
|
||||||
|
bool cancelled() const;
|
||||||
|
|
||||||
|
void set_scheduling_parameter(int policy, const sched_param& param);
|
||||||
|
void get_scheduling_parameter(int& policy, sched_param& param) const;
|
||||||
|
|
||||||
|
static int max_priority(int policy);
|
||||||
|
static int min_priority(int policy);
|
||||||
|
|
||||||
|
static void test_cancel();
|
||||||
static void sleep(const xtime& xt);
|
static void sleep(const xtime& xt);
|
||||||
static void yield();
|
static void yield();
|
||||||
|
|
||||||
private:
|
static const int stack_min;
|
||||||
|
|
||||||
#if defined(BOOST_HAS_WINTHREADS)
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
void* m_thread;
|
typedef unsigned int id_type;
|
||||||
unsigned int m_id;
|
#else
|
||||||
#elif defined(BOOST_HAS_PTHREADS)
|
typedef const void* id_type;
|
||||||
private:
|
|
||||||
pthread_t m_thread;
|
|
||||||
#elif defined(BOOST_HAS_MPTASKS)
|
|
||||||
MPQueueID m_pJoinQueueID;
|
|
||||||
MPTaskID m_pTaskID;
|
|
||||||
#endif
|
#endif
|
||||||
bool m_joinable;
|
|
||||||
|
id_type id() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void* m_handle;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename charT, typename Traits>
|
||||||
|
std::basic_ostream<charT, Traits>& operator<<(
|
||||||
|
std::basic_ostream<charT, Traits>& os, const thread& thrd)
|
||||||
|
{
|
||||||
|
if (!os.good()) return os;
|
||||||
|
|
||||||
|
typename std::basic_ostream<charT, Traits>::sentry opfx(os);
|
||||||
|
|
||||||
|
if (opfx)
|
||||||
|
os << thrd.id();
|
||||||
|
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
class BOOST_THREAD_DECL thread_group : private noncopyable
|
class BOOST_THREAD_DECL thread_group : private noncopyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
thread_group();
|
thread_group();
|
||||||
~thread_group();
|
~thread_group();
|
||||||
|
|
||||||
thread* create_thread(const function0<void>& threadfunc);
|
thread create_thread(const function0<void>& threadfunc);
|
||||||
void add_thread(thread* thrd);
|
void add_thread(thread thrd);
|
||||||
void remove_thread(thread* thrd);
|
void remove_thread(thread thrd);
|
||||||
|
// thread* thread_group::find(thread& thrd);
|
||||||
void join_all();
|
void join_all();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::list<thread*> m_threads;
|
std::list<thread> m_threads;
|
||||||
mutex m_mutex;
|
mutex m_mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace boost
|
} // namespace boost
|
||||||
|
|
||||||
|
#endif // BOOST_THREAD_WEK070601_HPP
|
||||||
|
|
||||||
// Change Log:
|
// Change Log:
|
||||||
// 8 Feb 01 WEKEMPF Initial version.
|
// 8 Feb 01 WEKEMPF Initial version.
|
||||||
// 1 Jun 01 WEKEMPF Added boost::thread initial implementation.
|
// 1 Jun 01 WEKEMPF Added boost::thread initial implementation.
|
||||||
// 3 Jul 01 WEKEMPF Redesigned boost::thread to be noncopyable.
|
// 3 Jul 01 WEKEMPF Redesigned boost::thread to be noncopyable.
|
||||||
|
|
||||||
#endif // BOOST_THREAD_WEK070601_HPP
|
|
||||||
|
|||||||
44
include/boost/thread/thread_pool.hpp
Normal file
44
include/boost/thread/thread_pool.hpp
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
// Copyright (C) 2002-2003
|
||||||
|
// David Moore, William E. Kempf
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
|
// and its documentation for any purpose is hereby granted without fee,
|
||||||
|
// provided that the above copyright notice appear in all copies and
|
||||||
|
// that both that copyright notice and this permission notice appear
|
||||||
|
// in supporting documentation. William E. Kempf makes no representations
|
||||||
|
// about the suitability of this software for any purpose.
|
||||||
|
// It is provided "as is" without express or implied warranty.
|
||||||
|
|
||||||
|
// Derived loosely from work queue manager in "Programming POSIX Threads"
|
||||||
|
// by David Butenhof.
|
||||||
|
|
||||||
|
#ifndef BOOST_THREAD_POOL_JDM031802_HPP
|
||||||
|
#define BOOST_THREAD_POOL_JDM031802_HPP
|
||||||
|
|
||||||
|
#include <boost/thread/detail/config.hpp>
|
||||||
|
|
||||||
|
#include <boost/function.hpp>
|
||||||
|
#include <boost/limits.hpp>
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
class BOOST_THREAD_DECL thread_pool
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
thread_pool(int max_threads=std::numeric_limits<int>::max(),
|
||||||
|
int min_threads=0, int timeout_secs=5, int timeout_nsecs=0);
|
||||||
|
~thread_pool();
|
||||||
|
|
||||||
|
void add(const boost::function0<void> &job);
|
||||||
|
void join();
|
||||||
|
void cancel();
|
||||||
|
void detach();
|
||||||
|
|
||||||
|
private:
|
||||||
|
class impl;
|
||||||
|
impl* m_pimpl;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2001
|
// Copyright (C) 2001-2003
|
||||||
// William E. Kempf
|
// William E. Kempf
|
||||||
//
|
//
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
@@ -12,13 +12,11 @@
|
|||||||
#ifndef BOOST_TSS_WEK070601_HPP
|
#ifndef BOOST_TSS_WEK070601_HPP
|
||||||
#define BOOST_TSS_WEK070601_HPP
|
#define BOOST_TSS_WEK070601_HPP
|
||||||
|
|
||||||
#include <boost/config.hpp>
|
#include <boost/thread/detail/config.hpp>
|
||||||
#ifndef BOOST_HAS_THREADS
|
|
||||||
# error Thread support is unavailable!
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <boost/utility.hpp>
|
#include <boost/utility.hpp>
|
||||||
#include <boost/thread/detail/config.hpp>
|
#include <boost/function.hpp>
|
||||||
|
#include <boost/thread/exceptions.hpp>
|
||||||
|
|
||||||
#if defined(BOOST_HAS_PTHREADS)
|
#if defined(BOOST_HAS_PTHREADS)
|
||||||
# include <pthread.h>
|
# include <pthread.h>
|
||||||
@@ -28,55 +26,96 @@
|
|||||||
|
|
||||||
namespace boost {
|
namespace boost {
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
class BOOST_THREAD_DECL tss : private noncopyable
|
|
||||||
|
class BOOST_THREAD_DECL tss : private noncopyable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
tss(boost::function1<void, void*>* pcleanup) {
|
||||||
|
if (pcleanup == 0) throw boost::thread_resource_error();
|
||||||
|
try
|
||||||
{
|
{
|
||||||
public:
|
init(pcleanup);
|
||||||
tss(void (*cleanup)(void*)=0);
|
}
|
||||||
~tss();
|
catch (...)
|
||||||
|
{
|
||||||
void* get() const;
|
delete pcleanup;
|
||||||
bool set(void* value);
|
throw boost::thread_resource_error();
|
||||||
|
}
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void* get() const;
|
||||||
|
void set(void* value);
|
||||||
|
void cleanup(void* p);
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned int m_slot; //This is a "pseudo-slot", not a native slot
|
||||||
|
|
||||||
|
void init(boost::function1<void, void*>* pcleanup);
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(BOOST_HAS_MPTASKS)
|
||||||
|
void thread_cleanup();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct tss_adapter
|
||||||
|
{
|
||||||
|
template <typename F>
|
||||||
|
tss_adapter(const F& cleanup) : m_cleanup(cleanup) { }
|
||||||
|
void operator()(void* p) { m_cleanup(static_cast<T*>(p)); }
|
||||||
|
boost::function1<void, T*> m_cleanup;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class thread_specific_ptr : private noncopyable
|
class thread_specific_ptr : private noncopyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
thread_specific_ptr() : m_tss(&thread_specific_ptr<T>::cleanup) { }
|
thread_specific_ptr()
|
||||||
|
: m_tss(new boost::function1<void, void*>(
|
||||||
|
boost::detail::tss_adapter<T>(
|
||||||
|
&thread_specific_ptr<T>::cleanup)))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
thread_specific_ptr(void (*clean)(T*))
|
||||||
|
: m_tss(new boost::function1<void, void*>(
|
||||||
|
boost::detail::tss_adapter<T>(clean)))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
~thread_specific_ptr() { reset(); }
|
||||||
|
|
||||||
T* get() const { return static_cast<T*>(m_tss.get()); }
|
T* get() const { return static_cast<T*>(m_tss.get()); }
|
||||||
T* operator->() const { return get(); }
|
T* operator->() const { return get(); }
|
||||||
T& operator*() const { return *get(); }
|
T& operator*() const { return *get(); }
|
||||||
T* release() { T* temp = get(); m_tss.set(0); return temp; }
|
T* release() { T* temp = get(); if (temp) m_tss.set(0); return temp; }
|
||||||
void reset(T* p=0) { T* cur = get(); if (cur == p) return; delete cur; m_tss.set(p); }
|
void reset(T* p=0)
|
||||||
|
{
|
||||||
|
T* cur = get();
|
||||||
|
if (cur == p) return;
|
||||||
|
m_tss.set(p);
|
||||||
|
if (cur) m_tss.cleanup(cur);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void cleanup(void* p) { delete static_cast<T*>(p); }
|
static void cleanup(T* p) { delete p; }
|
||||||
|
detail::tss m_tss;
|
||||||
mutable detail::tss m_tss;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace boost
|
} // namespace boost
|
||||||
|
|
||||||
|
#endif //BOOST_TSS_WEK070601_HPP
|
||||||
|
|
||||||
// Change Log:
|
// Change Log:
|
||||||
// 6 Jun 01 WEKEMPF Initial version.
|
// 6 Jun 01
|
||||||
|
// WEKEMPF Initial version.
|
||||||
#endif // BOOST_TSS_WEK070601_HPP
|
// 30 May 02 WEKEMPF
|
||||||
|
// Added interface to set specific cleanup handlers.
|
||||||
|
// Removed TLS slot limits from most implementations.
|
||||||
|
// 22 Mar 04 GlassfordM for WEKEMPF
|
||||||
|
// Fixed: thread_specific_ptr::reset() doesn't check error returned
|
||||||
|
// by tss::set(); tss::set() now throws if it fails.
|
||||||
|
// Fixed: calling thread_specific_ptr::reset() or
|
||||||
|
// thread_specific_ptr::release() causes double-delete: once on
|
||||||
|
// reset()/release() and once on ~thread_specific_ptr().
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2001
|
// Copyright (C) 2001-2003
|
||||||
// William E. Kempf
|
// William E. Kempf
|
||||||
//
|
//
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
@@ -12,22 +12,22 @@
|
|||||||
#ifndef BOOST_XTIME_WEK070601_HPP
|
#ifndef BOOST_XTIME_WEK070601_HPP
|
||||||
#define BOOST_XTIME_WEK070601_HPP
|
#define BOOST_XTIME_WEK070601_HPP
|
||||||
|
|
||||||
#include <boost/config.hpp>
|
|
||||||
#include <boost/cstdint.hpp>
|
|
||||||
#include <boost/thread/detail/config.hpp>
|
#include <boost/thread/detail/config.hpp>
|
||||||
|
|
||||||
|
#include <boost/cstdint.hpp>
|
||||||
|
|
||||||
namespace boost {
|
namespace boost {
|
||||||
|
|
||||||
enum
|
enum xtime_clock_types
|
||||||
{
|
{
|
||||||
TIME_UTC=1,
|
TIME_UTC=1
|
||||||
TIME_TAI,
|
// TIME_TAI,
|
||||||
TIME_MONOTONIC,
|
// TIME_MONOTONIC,
|
||||||
TIME_PROCESS,
|
// TIME_PROCESS,
|
||||||
TIME_THREAD,
|
// TIME_THREAD,
|
||||||
TIME_LOCAL,
|
// TIME_LOCAL,
|
||||||
TIME_SYNC,
|
// TIME_SYNC,
|
||||||
TIME_RESOLUTION
|
// TIME_RESOLUTION
|
||||||
};
|
};
|
||||||
|
|
||||||
struct xtime
|
struct xtime
|
||||||
|
|||||||
49
src/barrier.cpp
Normal file
49
src/barrier.cpp
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
// Copyright (C) 2002-2003
|
||||||
|
// David Moore, William E. Kempf
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
|
// and its documentation for any purpose is hereby granted without fee,
|
||||||
|
// provided that the above copyright notice appear in all copies and
|
||||||
|
// that both that copyright notice and this permission notice appear
|
||||||
|
// in supporting documentation. William E. Kempf makes no representations
|
||||||
|
// about the suitability of this software for any purpose.
|
||||||
|
// It is provided "as is" without express or implied warranty.
|
||||||
|
|
||||||
|
#include <boost/thread/detail/config.hpp>
|
||||||
|
|
||||||
|
#include <boost/thread/barrier.hpp>
|
||||||
|
#include <boost/thread/thread.hpp>
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
barrier::barrier(unsigned int count)
|
||||||
|
: m_threshold(count), m_count(count), m_generation(0)
|
||||||
|
{
|
||||||
|
if (count == 0)
|
||||||
|
throw std::invalid_argument("count cannot be zero.");
|
||||||
|
}
|
||||||
|
|
||||||
|
barrier::~barrier()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool barrier::wait()
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(m_mutex);
|
||||||
|
unsigned int gen = m_generation;
|
||||||
|
|
||||||
|
if (--m_count == 0)
|
||||||
|
{
|
||||||
|
m_generation++;
|
||||||
|
m_count = m_threshold;
|
||||||
|
m_cond.notify_all();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::cancellation_guard guard;
|
||||||
|
while (gen == m_generation)
|
||||||
|
m_cond.wait(lock);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2001
|
// Copyright (C) 2001-2003
|
||||||
// William E. Kempf
|
// William E. Kempf
|
||||||
//
|
//
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
@@ -9,6 +9,8 @@
|
|||||||
// about the suitability of this software for any purpose.
|
// about the suitability of this software for any purpose.
|
||||||
// It is provided "as is" without express or implied warranty.
|
// It is provided "as is" without express or implied warranty.
|
||||||
|
|
||||||
|
#include <boost/thread/detail/config.hpp>
|
||||||
|
|
||||||
#include <boost/thread/condition.hpp>
|
#include <boost/thread/condition.hpp>
|
||||||
#include <boost/thread/xtime.hpp>
|
#include <boost/thread/xtime.hpp>
|
||||||
#include <boost/thread/thread.hpp>
|
#include <boost/thread/thread.hpp>
|
||||||
@@ -25,9 +27,9 @@
|
|||||||
#elif defined(BOOST_HAS_PTHREADS)
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
# include <errno.h>
|
# include <errno.h>
|
||||||
#elif defined(BOOST_HAS_MPTASKS)
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
# include <MacErrors.h>
|
# include <MacErrors.h>
|
||||||
# include "mac/init.hpp"
|
# include "mac/init.hpp"
|
||||||
# include "mac/safe.hpp"
|
# include "mac/safe.hpp"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace boost {
|
namespace boost {
|
||||||
@@ -39,8 +41,8 @@ condition_impl::condition_impl()
|
|||||||
: m_gone(0), m_blocked(0), m_waiting(0)
|
: m_gone(0), m_blocked(0), m_waiting(0)
|
||||||
{
|
{
|
||||||
m_gate = reinterpret_cast<void*>(CreateSemaphore(0, 1, 1, 0));
|
m_gate = reinterpret_cast<void*>(CreateSemaphore(0, 1, 1, 0));
|
||||||
m_queue = reinterpret_cast<void*>(CreateSemaphore(0, 0,
|
m_queue = reinterpret_cast<void*>(
|
||||||
std::numeric_limits<long>::max(), 0));
|
CreateSemaphore(0, 0, (std::numeric_limits<long>::max)(), 0));
|
||||||
m_mutex = reinterpret_cast<void*>(CreateMutex(0, 0, 0));
|
m_mutex = reinterpret_cast<void*>(CreateMutex(0, 0, 0));
|
||||||
|
|
||||||
if (!m_gate || !m_queue || !m_mutex)
|
if (!m_gate || !m_queue || !m_mutex)
|
||||||
@@ -168,15 +170,15 @@ void condition_impl::notify_all()
|
|||||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||||
assert(res);
|
assert(res);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||||
|
assert(res);
|
||||||
|
|
||||||
|
if (signals)
|
||||||
|
{
|
||||||
|
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_queue), signals, 0);
|
||||||
assert(res);
|
assert(res);
|
||||||
|
|
||||||
if (signals)
|
|
||||||
{
|
|
||||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_queue), signals, 0);
|
|
||||||
assert(res);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,7 +220,7 @@ void condition_impl::do_wait()
|
|||||||
m_gone = 0;
|
m_gone = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (++m_gone == (std::numeric_limits<unsigned>::max() / 2))
|
else if (++m_gone == ((std::numeric_limits<unsigned>::max)() / 2))
|
||||||
{
|
{
|
||||||
// timeout occured, normalize the m_gone count
|
// timeout occured, normalize the m_gone count
|
||||||
// this may occur if many calls to wait with a timeout are made and
|
// this may occur if many calls to wait with a timeout are made and
|
||||||
@@ -302,7 +304,7 @@ bool condition_impl::do_timed_wait(const xtime& xt)
|
|||||||
m_gone = 0;
|
m_gone = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (++m_gone == (std::numeric_limits<unsigned>::max() / 2))
|
else if (++m_gone == ((std::numeric_limits<unsigned>::max)() / 2))
|
||||||
{
|
{
|
||||||
// timeout occured, normalize the m_gone count
|
// timeout occured, normalize the m_gone count
|
||||||
// this may occur if many calls to wait with a timeout are made and
|
// this may occur if many calls to wait with a timeout are made and
|
||||||
@@ -427,7 +429,8 @@ void condition_impl::notify_one()
|
|||||||
unsigned signals = 0;
|
unsigned signals = 0;
|
||||||
|
|
||||||
OSStatus lStatus = noErr;
|
OSStatus lStatus = noErr;
|
||||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||||
|
m_mutex_mutex);
|
||||||
assert(lStatus == noErr);
|
assert(lStatus == noErr);
|
||||||
|
|
||||||
if (m_waiting != 0) // the m_gate is already closed
|
if (m_waiting != 0) // the m_gate is already closed
|
||||||
@@ -479,7 +482,8 @@ void condition_impl::notify_all()
|
|||||||
unsigned signals = 0;
|
unsigned signals = 0;
|
||||||
|
|
||||||
OSStatus lStatus = noErr;
|
OSStatus lStatus = noErr;
|
||||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||||
|
m_mutex_mutex);
|
||||||
assert(lStatus == noErr);
|
assert(lStatus == noErr);
|
||||||
|
|
||||||
if (m_waiting != 0) // the m_gate is already closed
|
if (m_waiting != 0) // the m_gate is already closed
|
||||||
@@ -545,7 +549,8 @@ void condition_impl::do_wait()
|
|||||||
unsigned was_waiting=0;
|
unsigned was_waiting=0;
|
||||||
unsigned was_gone=0;
|
unsigned was_gone=0;
|
||||||
|
|
||||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||||
|
m_mutex_mutex);
|
||||||
assert(lStatus == noErr);
|
assert(lStatus == noErr);
|
||||||
was_waiting = m_waiting;
|
was_waiting = m_waiting;
|
||||||
was_gone = m_gone;
|
was_gone = m_gone;
|
||||||
@@ -563,7 +568,7 @@ void condition_impl::do_wait()
|
|||||||
m_gone = 0;
|
m_gone = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (++m_gone == (std::numeric_limits<unsigned>::max() / 2))
|
else if (++m_gone == ((std::numeric_limits<unsigned>::max)() / 2))
|
||||||
{
|
{
|
||||||
// timeout occured, normalize the m_gone count
|
// timeout occured, normalize the m_gone count
|
||||||
// this may occur if many calls to wait with a timeout are made and
|
// this may occur if many calls to wait with a timeout are made and
|
||||||
@@ -605,7 +610,8 @@ bool condition_impl::do_timed_wait(const xtime& xt)
|
|||||||
unsigned was_waiting=0;
|
unsigned was_waiting=0;
|
||||||
unsigned was_gone=0;
|
unsigned was_gone=0;
|
||||||
|
|
||||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||||
|
m_mutex_mutex);
|
||||||
assert(lStatus == noErr);
|
assert(lStatus == noErr);
|
||||||
was_waiting = m_waiting;
|
was_waiting = m_waiting;
|
||||||
was_gone = m_gone;
|
was_gone = m_gone;
|
||||||
@@ -630,7 +636,7 @@ bool condition_impl::do_timed_wait(const xtime& xt)
|
|||||||
m_gone = 0;
|
m_gone = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (++m_gone == (std::numeric_limits<unsigned>::max() / 2))
|
else if (++m_gone == ((std::numeric_limits<unsigned>::max)() / 2))
|
||||||
{
|
{
|
||||||
// timeout occured, normalize the m_gone count
|
// timeout occured, normalize the m_gone count
|
||||||
// this may occur if many calls to wait with a timeout are made and
|
// this may occur if many calls to wait with a timeout are made and
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2001
|
// Copyright (C) 2001-2003
|
||||||
// William E. Kempf
|
// William E. Kempf
|
||||||
//
|
//
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
@@ -9,17 +9,174 @@
|
|||||||
// about the suitability of this software for any purpose.
|
// about the suitability of this software for any purpose.
|
||||||
// It is provided "as is" without express or implied warranty.
|
// It is provided "as is" without express or implied warranty.
|
||||||
|
|
||||||
|
#include <boost/thread/detail/config.hpp>
|
||||||
|
|
||||||
#include <boost/thread/exceptions.hpp>
|
#include <boost/thread/exceptions.hpp>
|
||||||
|
#include <cstring>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
# ifdef BOOST_NO_STDC_NAMESPACE
|
||||||
|
namespace std { using ::strerror; }
|
||||||
|
# endif
|
||||||
|
|
||||||
|
// BOOST_POSIX or BOOST_WINDOWS specify which API to use.
|
||||||
|
# if !defined( BOOST_WINDOWS ) && !defined( BOOST_POSIX )
|
||||||
|
# if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(__CYGWIN__)
|
||||||
|
# define BOOST_WINDOWS
|
||||||
|
# else
|
||||||
|
# define BOOST_POSIX
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# if defined( BOOST_WINDOWS )
|
||||||
|
# include "windows.h"
|
||||||
|
# else
|
||||||
|
# include <errno.h> // for POSIX error codes
|
||||||
|
# endif
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
std::string system_message(int sys_err_code)
|
||||||
|
{
|
||||||
|
std::string str;
|
||||||
|
# ifdef BOOST_WINDOWS
|
||||||
|
LPVOID lpMsgBuf;
|
||||||
|
::FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||||
|
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||||
|
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||||
|
NULL,
|
||||||
|
sys_err_code,
|
||||||
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
|
||||||
|
(LPSTR)&lpMsgBuf,
|
||||||
|
0,
|
||||||
|
NULL);
|
||||||
|
str += static_cast<LPCSTR>(lpMsgBuf);
|
||||||
|
::LocalFree(lpMsgBuf); // free the buffer
|
||||||
|
while (str.size() && (str[str.size()-1] == '\n' ||
|
||||||
|
str[str.size()-1] == '\r'))
|
||||||
|
{
|
||||||
|
str.erase(str.size()-1);
|
||||||
|
}
|
||||||
|
# else
|
||||||
|
str += std::strerror(errno);
|
||||||
|
# endif
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // unnamed namespace
|
||||||
|
|
||||||
namespace boost {
|
namespace boost {
|
||||||
|
|
||||||
lock_error::lock_error() : std::logic_error("thread lock error")
|
thread_exception::thread_exception()
|
||||||
|
: m_sys_err(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
thread_resource_error::thread_resource_error() : std::runtime_error("thread resource error")
|
thread_exception::thread_exception(int sys_err_code)
|
||||||
|
: m_sys_err(sys_err_code)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
thread_exception::~thread_exception() throw()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* thread_exception::message() const
|
||||||
|
{
|
||||||
|
if (m_sys_err != 0)
|
||||||
|
return system_message(m_sys_err).c_str();
|
||||||
|
return what();
|
||||||
|
}
|
||||||
|
|
||||||
|
lock_error::lock_error()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
lock_error::lock_error(int sys_err_code)
|
||||||
|
: thread_exception(sys_err_code)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
lock_error::~lock_error() throw()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* lock_error::what() const throw()
|
||||||
|
{
|
||||||
|
return "boost::lock_error";
|
||||||
|
}
|
||||||
|
|
||||||
|
thread_resource_error::thread_resource_error()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
thread_resource_error::thread_resource_error(int sys_err_code)
|
||||||
|
: thread_exception(sys_err_code)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
thread_resource_error::~thread_resource_error() throw()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* thread_resource_error::what() const throw()
|
||||||
|
{
|
||||||
|
return "boost::thread_resource_error";
|
||||||
|
}
|
||||||
|
|
||||||
|
unsupported_thread_option::unsupported_thread_option()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
unsupported_thread_option::unsupported_thread_option(int sys_err_code)
|
||||||
|
: thread_exception(sys_err_code)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
unsupported_thread_option::~unsupported_thread_option() throw()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* unsupported_thread_option::what() const throw()
|
||||||
|
{
|
||||||
|
return "boost::unsupported_thread_option";
|
||||||
|
}
|
||||||
|
|
||||||
|
invalid_thread_argument::invalid_thread_argument()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
invalid_thread_argument::invalid_thread_argument(int sys_err_code)
|
||||||
|
: thread_exception(sys_err_code)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
invalid_thread_argument::~invalid_thread_argument() throw()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* invalid_thread_argument::what() const throw()
|
||||||
|
{
|
||||||
|
return "boost::invalid_thread_argument";
|
||||||
|
}
|
||||||
|
|
||||||
|
thread_permission_error::thread_permission_error()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
thread_permission_error::thread_permission_error(int sys_err_code)
|
||||||
|
: thread_exception(sys_err_code)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
thread_permission_error::~thread_permission_error() throw()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* thread_permission_error::what() const throw()
|
||||||
|
{
|
||||||
|
return "boost::thread_permission_error";
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace boost
|
} // namespace boost
|
||||||
|
|||||||
151
src/mutex.cpp
151
src/mutex.cpp
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2001
|
// Copyright (C) 2001-2003
|
||||||
// William E. Kempf
|
// William E. Kempf
|
||||||
//
|
//
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
@@ -9,6 +9,8 @@
|
|||||||
// about the suitability of this software for any purpose.
|
// about the suitability of this software for any purpose.
|
||||||
// It is provided "as is" without express or implied warranty.
|
// It is provided "as is" without express or implied warranty.
|
||||||
|
|
||||||
|
#include <boost/thread/detail/config.hpp>
|
||||||
|
|
||||||
#include <boost/thread/mutex.hpp>
|
#include <boost/thread/mutex.hpp>
|
||||||
#include <boost/thread/xtime.hpp>
|
#include <boost/thread/xtime.hpp>
|
||||||
#include <boost/thread/thread.hpp>
|
#include <boost/thread/thread.hpp>
|
||||||
@@ -16,17 +18,18 @@
|
|||||||
#include <boost/limits.hpp>
|
#include <boost/limits.hpp>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <new>
|
|
||||||
#include "timeconv.inl"
|
#include "timeconv.inl"
|
||||||
|
|
||||||
#if defined(BOOST_HAS_WINTHREADS)
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
# include <new>
|
||||||
|
# include <boost/thread/once.hpp>
|
||||||
# include <windows.h>
|
# include <windows.h>
|
||||||
# include <time.h>
|
# include <time.h>
|
||||||
|
# include "mutex.inl"
|
||||||
#elif defined(BOOST_HAS_PTHREADS)
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
# include <errno.h>
|
# include <errno.h>
|
||||||
#elif defined(BOOST_HAS_MPTASKS)
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
# include <MacErrors.h>
|
# include <MacErrors.h>
|
||||||
|
|
||||||
# include "mac/init.hpp"
|
# include "mac/init.hpp"
|
||||||
# include "mac/safe.hpp"
|
# include "mac/safe.hpp"
|
||||||
#endif
|
#endif
|
||||||
@@ -34,28 +37,41 @@
|
|||||||
namespace boost {
|
namespace boost {
|
||||||
|
|
||||||
#if defined(BOOST_HAS_WINTHREADS)
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
mutex::mutex()
|
|
||||||
|
mutex::mutex(const char* name)
|
||||||
|
: boost::detail::named_object(name)
|
||||||
|
, m_mutex(0)
|
||||||
|
, m_critical_section(false)
|
||||||
{
|
{
|
||||||
m_mutex = reinterpret_cast<void*>(new(std::nothrow) CRITICAL_SECTION);
|
m_critical_section = !name;
|
||||||
if (!m_mutex)
|
if (m_critical_section)
|
||||||
throw thread_resource_error();
|
m_mutex = new_critical_section();
|
||||||
InitializeCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(m_mutex));
|
else
|
||||||
|
m_mutex = new_mutex(effective_name()); //:add special name that creates a mutex instead of a critical section, but doesn't name the mutex?
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex::~mutex()
|
mutex::~mutex()
|
||||||
{
|
{
|
||||||
DeleteCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(m_mutex));
|
if (m_critical_section)
|
||||||
delete reinterpret_cast<LPCRITICAL_SECTION>(m_mutex);
|
delete_critical_section(m_mutex);
|
||||||
|
else
|
||||||
|
delete_mutex(m_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mutex::do_lock()
|
void mutex::do_lock()
|
||||||
{
|
{
|
||||||
EnterCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(m_mutex));
|
if (m_critical_section)
|
||||||
|
wait_critical_section_infinite(m_mutex);
|
||||||
|
else
|
||||||
|
wait_mutex(m_mutex, INFINITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mutex::do_unlock()
|
void mutex::do_unlock()
|
||||||
{
|
{
|
||||||
LeaveCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(m_mutex));
|
if (m_critical_section)
|
||||||
|
release_critical_section(m_mutex);
|
||||||
|
else
|
||||||
|
release_mutex(m_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mutex::do_lock(cv_state&)
|
void mutex::do_lock(cv_state&)
|
||||||
@@ -68,40 +84,48 @@ void mutex::do_unlock(cv_state&)
|
|||||||
do_unlock();
|
do_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
try_mutex::try_mutex()
|
try_mutex::try_mutex(const char* name)
|
||||||
|
: boost::detail::named_object(name)
|
||||||
|
, m_mutex(0)
|
||||||
|
, m_critical_section(false)
|
||||||
{
|
{
|
||||||
m_mutex = reinterpret_cast<void*>(CreateMutex(0, 0, 0));
|
m_critical_section = !name && has_TryEnterCriticalSection();
|
||||||
if (!m_mutex)
|
if (m_critical_section)
|
||||||
throw thread_resource_error();
|
m_mutex = new_critical_section();
|
||||||
|
else
|
||||||
|
m_mutex = new_mutex(effective_name());
|
||||||
}
|
}
|
||||||
|
|
||||||
try_mutex::~try_mutex()
|
try_mutex::~try_mutex()
|
||||||
{
|
{
|
||||||
int res = 0;
|
if (m_critical_section)
|
||||||
res = CloseHandle(reinterpret_cast<HANDLE>(m_mutex));
|
delete_critical_section(m_mutex);
|
||||||
assert(res);
|
else
|
||||||
|
delete_mutex(m_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void try_mutex::do_lock()
|
void try_mutex::do_lock()
|
||||||
{
|
{
|
||||||
int res = 0;
|
if (m_critical_section)
|
||||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), INFINITE);
|
wait_critical_section_infinite(m_mutex);
|
||||||
assert(res == WAIT_OBJECT_0);
|
else
|
||||||
|
wait_mutex(m_mutex, INFINITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool try_mutex::do_trylock()
|
bool try_mutex::do_trylock()
|
||||||
{
|
{
|
||||||
unsigned int res = 0;
|
if (m_critical_section)
|
||||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), 0);
|
return wait_critical_section_try(m_mutex);
|
||||||
assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
|
else
|
||||||
return res == WAIT_OBJECT_0;
|
return wait_mutex(m_mutex, 0) == WAIT_OBJECT_0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void try_mutex::do_unlock()
|
void try_mutex::do_unlock()
|
||||||
{
|
{
|
||||||
int res = 0;
|
if (m_critical_section)
|
||||||
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
release_critical_section(m_mutex);
|
||||||
assert(res);
|
else
|
||||||
|
release_mutex(m_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void try_mutex::do_lock(cv_state&)
|
void try_mutex::do_lock(cv_state&)
|
||||||
@@ -114,51 +138,42 @@ void try_mutex::do_unlock(cv_state&)
|
|||||||
do_unlock();
|
do_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
timed_mutex::timed_mutex()
|
timed_mutex::timed_mutex(const char* name)
|
||||||
|
: boost::detail::named_object(name)
|
||||||
|
, m_mutex(0)
|
||||||
{
|
{
|
||||||
m_mutex = reinterpret_cast<void*>(CreateMutex(0, 0, 0));
|
m_mutex = new_mutex(effective_name());
|
||||||
if (!m_mutex)
|
|
||||||
throw thread_resource_error();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
timed_mutex::~timed_mutex()
|
timed_mutex::~timed_mutex()
|
||||||
{
|
{
|
||||||
int res = 0;
|
delete_mutex(m_mutex);
|
||||||
res = CloseHandle(reinterpret_cast<HANDLE>(m_mutex));
|
|
||||||
assert(res);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void timed_mutex::do_lock()
|
void timed_mutex::do_lock()
|
||||||
{
|
{
|
||||||
int res = 0;
|
wait_mutex(m_mutex, INFINITE);
|
||||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), INFINITE);
|
|
||||||
assert(res == WAIT_OBJECT_0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool timed_mutex::do_trylock()
|
bool timed_mutex::do_trylock()
|
||||||
{
|
{
|
||||||
unsigned int res = 0;
|
return wait_mutex(m_mutex, 0) == WAIT_OBJECT_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)
|
bool timed_mutex::do_timedlock(const xtime& xt)
|
||||||
{
|
{
|
||||||
unsigned int res = 0;
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
int milliseconds;
|
int milliseconds;
|
||||||
to_duration(xt, milliseconds);
|
to_duration(xt, milliseconds);
|
||||||
|
|
||||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), milliseconds);
|
int res = wait_mutex(m_mutex, milliseconds);
|
||||||
assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
|
|
||||||
|
|
||||||
if (res == WAIT_TIMEOUT)
|
if (res == WAIT_TIMEOUT)
|
||||||
{
|
{
|
||||||
xtime cur;
|
boost::xtime cur;
|
||||||
xtime_get(&cur, TIME_UTC);
|
boost::xtime_get(&cur, boost::TIME_UTC);
|
||||||
if (xtime_cmp(xt, cur) > 0)
|
if (boost::xtime_cmp(xt, cur) > 0)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,9 +183,7 @@ bool timed_mutex::do_timedlock(const xtime& xt)
|
|||||||
|
|
||||||
void timed_mutex::do_unlock()
|
void timed_mutex::do_unlock()
|
||||||
{
|
{
|
||||||
int res = 0;
|
release_mutex(m_mutex);
|
||||||
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
|
||||||
assert(res);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void timed_mutex::do_lock(cv_state&)
|
void timed_mutex::do_lock(cv_state&)
|
||||||
@@ -182,9 +195,13 @@ void timed_mutex::do_unlock(cv_state&)
|
|||||||
{
|
{
|
||||||
do_unlock();
|
do_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(BOOST_HAS_PTHREADS)
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
mutex::mutex()
|
|
||||||
|
mutex::mutex(const char* name)
|
||||||
{
|
{
|
||||||
|
//:Use name parameter
|
||||||
|
|
||||||
int res = 0;
|
int res = 0;
|
||||||
res = pthread_mutex_init(&m_mutex, 0);
|
res = pthread_mutex_init(&m_mutex, 0);
|
||||||
if (res != 0)
|
if (res != 0)
|
||||||
@@ -223,8 +240,10 @@ void mutex::do_unlock(cv_state& state)
|
|||||||
state.pmutex = &m_mutex;
|
state.pmutex = &m_mutex;
|
||||||
}
|
}
|
||||||
|
|
||||||
try_mutex::try_mutex()
|
try_mutex::try_mutex(const char* name)
|
||||||
{
|
{
|
||||||
|
//:Use name parameter
|
||||||
|
|
||||||
int res = 0;
|
int res = 0;
|
||||||
res = pthread_mutex_init(&m_mutex, 0);
|
res = pthread_mutex_init(&m_mutex, 0);
|
||||||
if (res != 0)
|
if (res != 0)
|
||||||
@@ -272,9 +291,11 @@ void try_mutex::do_unlock(cv_state& state)
|
|||||||
state.pmutex = &m_mutex;
|
state.pmutex = &m_mutex;
|
||||||
}
|
}
|
||||||
|
|
||||||
timed_mutex::timed_mutex()
|
timed_mutex::timed_mutex(const char* name)
|
||||||
: m_locked(false)
|
: m_locked(false)
|
||||||
{
|
{
|
||||||
|
//:Use name parameter
|
||||||
|
|
||||||
int res = 0;
|
int res = 0;
|
||||||
res = pthread_mutex_init(&m_mutex, 0);
|
res = pthread_mutex_init(&m_mutex, 0);
|
||||||
if (res != 0)
|
if (res != 0)
|
||||||
@@ -412,12 +433,14 @@ void timed_mutex::do_unlock(cv_state& state)
|
|||||||
|
|
||||||
state.pmutex = &m_mutex;
|
state.pmutex = &m_mutex;
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(BOOST_HAS_MPTASKS)
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
|
|
||||||
using threads::mac::detail::safe_enter_critical_region;
|
using threads::mac::detail::safe_enter_critical_region;
|
||||||
|
|
||||||
mutex::mutex()
|
mutex::mutex(const char* name)
|
||||||
{
|
{
|
||||||
|
//:Use name parameter
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex::~mutex()
|
mutex::~mutex()
|
||||||
@@ -427,7 +450,8 @@ mutex::~mutex()
|
|||||||
void mutex::do_lock()
|
void mutex::do_lock()
|
||||||
{
|
{
|
||||||
OSStatus lStatus = noErr;
|
OSStatus lStatus = noErr;
|
||||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||||
|
m_mutex_mutex);
|
||||||
assert(lStatus == noErr);
|
assert(lStatus == noErr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -448,8 +472,9 @@ void mutex::do_unlock(cv_state& /*state*/)
|
|||||||
do_unlock();
|
do_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
try_mutex::try_mutex()
|
try_mutex::try_mutex(const char* name)
|
||||||
{
|
{
|
||||||
|
//:Use name parameter
|
||||||
}
|
}
|
||||||
|
|
||||||
try_mutex::~try_mutex()
|
try_mutex::~try_mutex()
|
||||||
@@ -459,7 +484,8 @@ try_mutex::~try_mutex()
|
|||||||
void try_mutex::do_lock()
|
void try_mutex::do_lock()
|
||||||
{
|
{
|
||||||
OSStatus lStatus = noErr;
|
OSStatus lStatus = noErr;
|
||||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||||
|
m_mutex_mutex);
|
||||||
assert(lStatus == noErr);
|
assert(lStatus == noErr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -488,8 +514,9 @@ void try_mutex::do_unlock(cv_state& /*state*/)
|
|||||||
do_unlock();
|
do_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
timed_mutex::timed_mutex()
|
timed_mutex::timed_mutex(const char* name)
|
||||||
{
|
{
|
||||||
|
//:Use name parameter
|
||||||
}
|
}
|
||||||
|
|
||||||
timed_mutex::~timed_mutex()
|
timed_mutex::~timed_mutex()
|
||||||
@@ -499,7 +526,8 @@ timed_mutex::~timed_mutex()
|
|||||||
void timed_mutex::do_lock()
|
void timed_mutex::do_lock()
|
||||||
{
|
{
|
||||||
OSStatus lStatus = noErr;
|
OSStatus lStatus = noErr;
|
||||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||||
|
m_mutex_mutex);
|
||||||
assert(lStatus == noErr);
|
assert(lStatus == noErr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -540,6 +568,7 @@ void timed_mutex::do_unlock(cv_state& /*state*/)
|
|||||||
{
|
{
|
||||||
do_unlock();
|
do_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} // namespace boost
|
} // namespace boost
|
||||||
|
|||||||
124
src/mutex.inl
Normal file
124
src/mutex.inl
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
// Copyright (C) 2001-2003
|
||||||
|
// William E. Kempf
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
|
// and its documentation for any purpose is hereby granted without fee,
|
||||||
|
// provided that the above copyright notice appear in all copies and
|
||||||
|
// that both that copyright notice and this permission notice appear
|
||||||
|
// in supporting documentation. William E. Kempf makes no representations
|
||||||
|
// about the suitability of this software for any purpose.
|
||||||
|
// It is provided "as is" without express or implied warranty.
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
//:PREVENT THIS FROM BEING DUPLICATED
|
||||||
|
typedef BOOL (WINAPI* TryEnterCriticalSection_type)(LPCRITICAL_SECTION lpCriticalSection);
|
||||||
|
TryEnterCriticalSection_type g_TryEnterCriticalSection = 0;
|
||||||
|
boost::once_flag once_init_TryEnterCriticalSection = BOOST_ONCE_INIT;
|
||||||
|
|
||||||
|
void init_TryEnterCriticalSection()
|
||||||
|
{
|
||||||
|
//TryEnterCriticalSection is only available on WinNT 4.0 or later;
|
||||||
|
//it is not available on Win9x.
|
||||||
|
|
||||||
|
OSVERSIONINFO version_info = {sizeof(OSVERSIONINFO)};
|
||||||
|
::GetVersionEx(&version_info);
|
||||||
|
if (version_info.dwPlatformId == VER_PLATFORM_WIN32_NT &&
|
||||||
|
version_info.dwMajorVersion >= 4)
|
||||||
|
{
|
||||||
|
if (HMODULE kernel_module = GetModuleHandle(TEXT("KERNEL32.DLL")))
|
||||||
|
g_TryEnterCriticalSection = reinterpret_cast<TryEnterCriticalSection_type>(GetProcAddress(kernel_module, "TryEnterCriticalSection"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool has_TryEnterCriticalSection()
|
||||||
|
{
|
||||||
|
boost::call_once(init_TryEnterCriticalSection, once_init_TryEnterCriticalSection);
|
||||||
|
return g_TryEnterCriticalSection != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline HANDLE mutex_cast(void* p)
|
||||||
|
{
|
||||||
|
return reinterpret_cast<HANDLE>(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline LPCRITICAL_SECTION critical_section_cast(void* p)
|
||||||
|
{
|
||||||
|
return reinterpret_cast<LPCRITICAL_SECTION>(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void* new_critical_section()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
LPCRITICAL_SECTION critical_section = new CRITICAL_SECTION;
|
||||||
|
if (critical_section == 0) throw boost::thread_resource_error();
|
||||||
|
InitializeCriticalSection(critical_section);
|
||||||
|
return critical_section;
|
||||||
|
}
|
||||||
|
catch(...)
|
||||||
|
{
|
||||||
|
throw boost::thread_resource_error();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void* new_mutex(const char* name)
|
||||||
|
{
|
||||||
|
#if defined(BOOST_NO_ANSI_APIS)
|
||||||
|
USES_CONVERSION;
|
||||||
|
HANDLE mutex = CreateMutexW(0, 0, A2CW(name));
|
||||||
|
#else
|
||||||
|
HANDLE mutex = CreateMutexA(0, 0, name);
|
||||||
|
#endif
|
||||||
|
if (mutex == 0 || mutex == INVALID_HANDLE_VALUE) //:xxx (check for both values?)
|
||||||
|
throw boost::thread_resource_error();
|
||||||
|
return reinterpret_cast<void*>(mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void delete_critical_section(void* mutex)
|
||||||
|
{
|
||||||
|
DeleteCriticalSection(critical_section_cast(mutex));
|
||||||
|
delete critical_section_cast(mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void delete_mutex(void* mutex)
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = CloseHandle(mutex_cast(mutex));
|
||||||
|
assert(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void wait_critical_section_infinite(void* mutex)
|
||||||
|
{
|
||||||
|
EnterCriticalSection(critical_section_cast(mutex)); //:xxx Can throw an exception under low memory conditions
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool wait_critical_section_try(void* mutex)
|
||||||
|
{
|
||||||
|
BOOL res = g_TryEnterCriticalSection(critical_section_cast(mutex));
|
||||||
|
return res != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int wait_mutex(void* mutex, int time)
|
||||||
|
{
|
||||||
|
unsigned int res = 0;
|
||||||
|
res = WaitForSingleObject(mutex_cast(mutex), time);
|
||||||
|
//:xxx assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void release_critical_section(void* mutex)
|
||||||
|
{
|
||||||
|
LeaveCriticalSection(critical_section_cast(mutex));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void release_mutex(void* mutex)
|
||||||
|
{
|
||||||
|
BOOL res = FALSE;
|
||||||
|
res = ReleaseMutex(mutex_cast(mutex));
|
||||||
|
assert(res);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
135
src/named.cpp
Normal file
135
src/named.cpp
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
// Copyright (C) 2001-2003
|
||||||
|
// William E. Kempf
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
|
// and its documentation for any purpose is hereby granted without fee,
|
||||||
|
// provided that the above copyright notice appear in all copies and
|
||||||
|
// that both that copyright notice and this permission notice appear
|
||||||
|
// in supporting documentation. William E. Kempf makes no representations
|
||||||
|
// about the suitability of this software for any purpose.
|
||||||
|
// It is provided "as is" without express or implied warranty.
|
||||||
|
|
||||||
|
#include <boost/thread/detail/config.hpp>
|
||||||
|
|
||||||
|
#include <boost/thread/detail/named.hpp>
|
||||||
|
#include <string.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
char* concat(char* result, const char* buf)
|
||||||
|
{
|
||||||
|
if (result == 0)
|
||||||
|
return strdup(buf);
|
||||||
|
|
||||||
|
int len = strlen(result) + strlen(buf) + 1;
|
||||||
|
result = (char*)realloc(result, len);
|
||||||
|
strcat(result, buf);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* get_root()
|
||||||
|
{
|
||||||
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
return "";
|
||||||
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
|
return "/";
|
||||||
|
#else
|
||||||
|
return "";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
char* encode(const char* str)
|
||||||
|
{
|
||||||
|
const char* digits="0123456789abcdef";
|
||||||
|
char* result=0;
|
||||||
|
static char buf[100];
|
||||||
|
char* ebuf = buf + 100;
|
||||||
|
char* p = buf;
|
||||||
|
*p = 0;
|
||||||
|
strcat(p, get_root());
|
||||||
|
p = p + strlen(p);
|
||||||
|
while (*str)
|
||||||
|
{
|
||||||
|
if (((*str >= '0') && (*str <= '9')) ||
|
||||||
|
((*str >= 'a') && (*str <= 'z')) ||
|
||||||
|
((*str >= 'A') && (*str <= 'Z')) ||
|
||||||
|
(*str == '/') || (*str == '.') || (*str == '_'))
|
||||||
|
{
|
||||||
|
*p = *str;
|
||||||
|
}
|
||||||
|
else if (*str == ' ')
|
||||||
|
{
|
||||||
|
*p = '+';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (p + 3 >= ebuf)
|
||||||
|
{
|
||||||
|
*p = 0;
|
||||||
|
result = concat(result, buf);
|
||||||
|
p = buf;
|
||||||
|
}
|
||||||
|
*p = '%';
|
||||||
|
char* e = p + 2;
|
||||||
|
int v = *str;
|
||||||
|
while (e > p)
|
||||||
|
{
|
||||||
|
*e-- = digits[v % 16];
|
||||||
|
v /= 16;
|
||||||
|
}
|
||||||
|
p += 2;
|
||||||
|
}
|
||||||
|
if (++p == ebuf)
|
||||||
|
{
|
||||||
|
*p = 0;
|
||||||
|
result = concat(result, buf);
|
||||||
|
p = buf;
|
||||||
|
}
|
||||||
|
++str;
|
||||||
|
}
|
||||||
|
*p = 0;
|
||||||
|
result = concat(result, buf);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
named_object::named_object(const char* name)
|
||||||
|
: m_name(0), m_ename(0)
|
||||||
|
{
|
||||||
|
if (name)
|
||||||
|
{
|
||||||
|
m_name = strdup(name);
|
||||||
|
if (*m_name == '%')
|
||||||
|
m_ename = m_name + 1;
|
||||||
|
else
|
||||||
|
m_ename = encode(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
named_object::~named_object()
|
||||||
|
{
|
||||||
|
if (m_name)
|
||||||
|
{
|
||||||
|
if (*m_name != '%')
|
||||||
|
free(m_ename);
|
||||||
|
free(m_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* named_object::name() const
|
||||||
|
{
|
||||||
|
return m_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* named_object::effective_name() const
|
||||||
|
{
|
||||||
|
return m_ename;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
} // namespace boost
|
||||||
163
src/once.cpp
163
src/once.cpp
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2001
|
// Copyright (C) 2001-2003
|
||||||
// William E. Kempf
|
// William E. Kempf
|
||||||
//
|
//
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
@@ -9,6 +9,8 @@
|
|||||||
// about the suitability of this software for any purpose.
|
// about the suitability of this software for any purpose.
|
||||||
// It is provided "as is" without express or implied warranty.
|
// It is provided "as is" without express or implied warranty.
|
||||||
|
|
||||||
|
#include <boost/thread/detail/config.hpp>
|
||||||
|
|
||||||
#include <boost/thread/once.hpp>
|
#include <boost/thread/once.hpp>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
@@ -17,14 +19,16 @@
|
|||||||
# include <windows.h>
|
# include <windows.h>
|
||||||
# if defined(BOOST_NO_STRINGSTREAM)
|
# if defined(BOOST_NO_STRINGSTREAM)
|
||||||
# include <strstream>
|
# include <strstream>
|
||||||
class unfreezer
|
|
||||||
{
|
class unfreezer
|
||||||
public:
|
{
|
||||||
unfreezer(std::ostrstream& s) : m_stream(s) {}
|
public:
|
||||||
~unfreezer() { m_stream.freeze(false); }
|
unfreezer(std::ostrstream& s) : m_stream(s) {}
|
||||||
private:
|
~unfreezer() { m_stream.freeze(false); }
|
||||||
std::ostrstream& m_stream;
|
private:
|
||||||
};
|
std::ostrstream& m_stream;
|
||||||
|
};
|
||||||
|
|
||||||
# else
|
# else
|
||||||
# include <sstream>
|
# include <sstream>
|
||||||
# endif
|
# endif
|
||||||
@@ -33,7 +37,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef BOOST_NO_STDC_NAMESPACE
|
#ifdef BOOST_NO_STDC_NAMESPACE
|
||||||
namespace std { using ::sprintf; }
|
namespace std { using ::sprintf; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(BOOST_HAS_PTHREADS)
|
#if defined(BOOST_HAS_PTHREADS)
|
||||||
@@ -46,64 +50,70 @@ typedef void (*once_callback)();
|
|||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
static void key_init()
|
static void key_init()
|
||||||
{
|
{
|
||||||
pthread_key_create(&key, 0);
|
pthread_key_create(&key, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_once()
|
static void do_once()
|
||||||
{
|
{
|
||||||
once_callback* cb = reinterpret_cast<once_callback*>(pthread_getspecific(key));
|
once_callback* cb = reinterpret_cast<once_callback*>(
|
||||||
(**cb)();
|
pthread_getspecific(key));
|
||||||
}
|
(**cb)();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
#elif defined(BOOST_HAS_MPTASKS)
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
namespace {
|
namespace {
|
||||||
void *remote_call_proxy(void *pData)
|
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)
|
||||||
{
|
{
|
||||||
std::pair<void (*)(), boost::once_flag *> &rData(*reinterpret_cast<std::pair<void (*)(), boost::once_flag *> *>(pData));
|
rData.first();
|
||||||
|
*rData.second = true;
|
||||||
if(*rData.second == false)
|
|
||||||
{
|
|
||||||
rData.first();
|
|
||||||
*rData.second = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return(NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return(NULL);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#elif defined(BOOST_HAS_WINTHREADS)
|
#elif defined(BOOST_HAS_WINTHREADS)
|
||||||
namespace {
|
namespace {
|
||||||
// The signature for InterlockedCompareExchange has changed with the
|
// The signature for InterlockedCompareExchange has changed with the
|
||||||
// addition of Win64 support. I can't determine any (consistent and
|
// addition of Win64 support. I can't determine any (consistent and
|
||||||
// portable) way of using conditional compilation to detect this, so
|
// portable) way of using conditional compilation to detect this, so
|
||||||
// we use these type wrappers. Unfortunately, the various vendors
|
// we use these type wrappers. Unfortunately, the various vendors
|
||||||
// use different calling conventions and other signature anamolies,
|
// use different calling conventions and other signature anamolies,
|
||||||
// and thus have unique types as well. This is known to work on VC6,
|
// and thus have unique types as well. This is known to work on VC6,
|
||||||
// VC7, Borland 5.5.2 and gcc 3.2. Are there other signatures for
|
// VC7, Borland 5.5.2 and gcc 3.2. Are there other signatures for
|
||||||
// other platforms?
|
// other platforms?
|
||||||
inline LONG ice_wrapper(LONG (__stdcall *ice)(LONG*, LONG, LONG), volatile LONG* dest, LONG exch, LONG cmp)
|
inline LONG ice_wrapper(LONG (__stdcall *ice)(LONG*, LONG, LONG),
|
||||||
{
|
volatile LONG* dest, LONG exch, LONG cmp)
|
||||||
return (*ice)(const_cast<LONG*>(dest), exch, cmp);
|
{
|
||||||
}
|
return (*ice)(const_cast<LONG*>(dest), exch, cmp);
|
||||||
|
}
|
||||||
|
|
||||||
inline LONG ice_wrapper(LONG (__stdcall *ice)(volatile LONG*, LONG, LONG), volatile LONG* dest, LONG exch, LONG cmp)
|
inline LONG ice_wrapper(LONG (__stdcall *ice)(volatile LONG*, LONG, LONG),
|
||||||
{
|
volatile LONG* dest, LONG exch, LONG cmp)
|
||||||
return (*ice)(dest, exch, cmp);
|
{
|
||||||
}
|
return (*ice)(dest, exch, cmp);
|
||||||
|
}
|
||||||
|
|
||||||
inline LONG ice_wrapper(LPVOID (__stdcall *ice)(LPVOID*, LPVOID, LPVOID), volatile LONG* dest, LONG exch, LONG cmp)
|
inline LONG ice_wrapper(LPVOID (__stdcall *ice)(LPVOID*, LPVOID, LPVOID),
|
||||||
{
|
volatile LONG* dest, LONG exch, LONG cmp)
|
||||||
return (LONG)(*ice)((LPVOID*)dest, (LPVOID)exch, (LPVOID)cmp);
|
{
|
||||||
}
|
return (LONG)(*ice)((LPVOID*)dest, (LPVOID)exch, (LPVOID)cmp);
|
||||||
|
}
|
||||||
|
|
||||||
// The friendly form of InterlockedCompareExchange that defers
|
// The friendly form of InterlockedCompareExchange that defers
|
||||||
// according to the above function type wrappers.
|
// according to the above function type wrappers.
|
||||||
inline LONG compare_exchange(volatile LPLONG dest, LONG exch, LONG cmp)
|
inline LONG compare_exchange(volatile LPLONG dest, LONG exch, LONG cmp)
|
||||||
{
|
{
|
||||||
return ice_wrapper(&InterlockedCompareExchange, dest, exch, cmp);
|
return ice_wrapper(&InterlockedCompareExchange, dest, exch, cmp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -116,13 +126,34 @@ void call_once(void (*func)(), once_flag& flag)
|
|||||||
{
|
{
|
||||||
#if defined(BOOST_NO_STRINGSTREAM)
|
#if defined(BOOST_NO_STRINGSTREAM)
|
||||||
std::ostrstream strm;
|
std::ostrstream strm;
|
||||||
strm << "2AC1A572DB6944B0A65C38C4140AF2F4" << std::hex << GetCurrentProcessId() << &flag << std::ends;
|
strm << "2AC1A572DB6944B0A65C38C4140AF2F4"
|
||||||
|
<< std::hex
|
||||||
|
<< GetCurrentProcessId()
|
||||||
|
<< &flag
|
||||||
|
<< std::ends;
|
||||||
unfreezer unfreeze(strm);
|
unfreezer unfreeze(strm);
|
||||||
HANDLE mutex = CreateMutex(NULL, FALSE, strm.str());
|
# if defined (BOOST_NO_ANSI_APIS)
|
||||||
|
USES_CONVERSION;
|
||||||
|
HANDLE mutex = CreateMutexW(NULL, FALSE, A2CW(strm.str()));
|
||||||
|
# else
|
||||||
|
HANDLE mutex = CreateMutexA(NULL, FALSE, strm.str());
|
||||||
|
# endif
|
||||||
#else
|
#else
|
||||||
|
# if defined (BOOST_NO_ANSI_APIS)
|
||||||
|
std::wostringstream strm;
|
||||||
|
strm << L"2AC1A572DB6944B0A65C38C4140AF2F4"
|
||||||
|
<< std::hex
|
||||||
|
<< GetCurrentProcessId()
|
||||||
|
<< &flag;
|
||||||
|
HANDLE mutex = CreateMutexW(NULL, FALSE, strm.str().c_str());
|
||||||
|
# else
|
||||||
std::ostringstream strm;
|
std::ostringstream strm;
|
||||||
strm << "2AC1A572DB6944B0A65C38C4140AF2F4" << std::hex << GetCurrentProcessId() << &flag;
|
strm << "2AC1A572DB6944B0A65C38C4140AF2F4"
|
||||||
|
<< std::hex
|
||||||
|
<< GetCurrentProcessId()
|
||||||
|
<< &flag;
|
||||||
HANDLE mutex = CreateMutexA(NULL, FALSE, strm.str().c_str());
|
HANDLE mutex = CreateMutexA(NULL, FALSE, strm.str().c_str());
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
assert(mutex != NULL);
|
assert(mutex != NULL);
|
||||||
|
|
||||||
@@ -132,7 +163,18 @@ void call_once(void (*func)(), once_flag& flag)
|
|||||||
|
|
||||||
if (compare_exchange(&flag, 1, 1) == 0)
|
if (compare_exchange(&flag, 1, 1) == 0)
|
||||||
{
|
{
|
||||||
func();
|
try
|
||||||
|
{
|
||||||
|
func();
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
res = ReleaseMutex(mutex);
|
||||||
|
assert(res);
|
||||||
|
res = CloseHandle(mutex);
|
||||||
|
assert(res);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
InterlockedExchange(&flag, 1);
|
InterlockedExchange(&flag, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,7 +190,8 @@ void call_once(void (*func)(), once_flag& flag)
|
|||||||
#elif defined(BOOST_HAS_MPTASKS)
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
if(flag == false)
|
if(flag == false)
|
||||||
{
|
{
|
||||||
// all we do here is make a remote call to blue, as blue is not reentrant.
|
// all we do here is make a remote call to blue, as blue is not
|
||||||
|
// reentrant.
|
||||||
std::pair<void (*)(), once_flag *> sData(func, &flag);
|
std::pair<void (*)(), once_flag *> sData(func, &flag);
|
||||||
MPRemoteCall(remote_call_proxy, &sData, kMPOwningProcessRemoteContext);
|
MPRemoteCall(remote_call_proxy, &sData, kMPOwningProcessRemoteContext);
|
||||||
assert(flag == true);
|
assert(flag == true);
|
||||||
|
|||||||
1146
src/read_write_mutex.cpp
Normal file
1146
src/read_write_mutex.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2001
|
// Copyright (C) 2001-2003
|
||||||
// William E. Kempf
|
// William E. Kempf
|
||||||
//
|
//
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
@@ -9,6 +9,8 @@
|
|||||||
// about the suitability of this software for any purpose.
|
// about the suitability of this software for any purpose.
|
||||||
// It is provided "as is" without express or implied warranty.
|
// It is provided "as is" without express or implied warranty.
|
||||||
|
|
||||||
|
#include <boost/thread/detail/config.hpp>
|
||||||
|
|
||||||
#include <boost/thread/recursive_mutex.hpp>
|
#include <boost/thread/recursive_mutex.hpp>
|
||||||
#include <boost/thread/xtime.hpp>
|
#include <boost/thread/xtime.hpp>
|
||||||
#include <boost/thread/thread.hpp>
|
#include <boost/thread/thread.hpp>
|
||||||
@@ -18,50 +20,77 @@
|
|||||||
#include "timeconv.inl"
|
#include "timeconv.inl"
|
||||||
|
|
||||||
#if defined(BOOST_HAS_WINTHREADS)
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
# include <new>
|
||||||
|
# include <boost/thread/once.hpp>
|
||||||
# include <windows.h>
|
# include <windows.h>
|
||||||
# include <time.h>
|
# include <time.h>
|
||||||
|
# include "mutex.inl"
|
||||||
#elif defined(BOOST_HAS_PTHREADS)
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
# include <errno.h>
|
# include <errno.h>
|
||||||
#elif defined(BOOST_HAS_MPTASKS)
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
# include <MacErrors.h>
|
# include <MacErrors.h>
|
||||||
# include "safe.hpp"
|
# include "safe.hpp"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace boost {
|
namespace boost {
|
||||||
|
|
||||||
#if defined(BOOST_HAS_WINTHREADS)
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
recursive_mutex::recursive_mutex()
|
|
||||||
: m_count(0)
|
recursive_mutex::recursive_mutex(const char* name)
|
||||||
|
: boost::detail::named_object(name)
|
||||||
|
, m_mutex(0)
|
||||||
|
, m_count(0)
|
||||||
|
, m_critical_section(false)
|
||||||
{
|
{
|
||||||
m_mutex = reinterpret_cast<void*>(new(std::nothrow) CRITICAL_SECTION);
|
m_critical_section = !name;
|
||||||
if (!m_mutex)
|
if (m_critical_section)
|
||||||
throw thread_resource_error();
|
m_mutex = new_critical_section();
|
||||||
InitializeCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(m_mutex));
|
else
|
||||||
|
m_mutex = new_mutex(effective_name()); //:add special name that creates a mutex instead of a critical section, but doesn't name the mutex?
|
||||||
}
|
}
|
||||||
|
|
||||||
recursive_mutex::~recursive_mutex()
|
recursive_mutex::~recursive_mutex()
|
||||||
{
|
{
|
||||||
DeleteCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(m_mutex));
|
if (m_critical_section)
|
||||||
delete reinterpret_cast<LPCRITICAL_SECTION>(m_mutex);
|
delete_critical_section(m_mutex);
|
||||||
|
else
|
||||||
|
delete_mutex(m_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void recursive_mutex::do_lock()
|
void recursive_mutex::do_lock()
|
||||||
{
|
{
|
||||||
EnterCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(m_mutex));
|
if (m_critical_section)
|
||||||
|
wait_critical_section_infinite(m_mutex);
|
||||||
|
else
|
||||||
|
wait_mutex(m_mutex, INFINITE);
|
||||||
|
|
||||||
if (++m_count > 1)
|
if (++m_count > 1)
|
||||||
LeaveCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(m_mutex));
|
{
|
||||||
|
if (m_critical_section)
|
||||||
|
release_critical_section(m_mutex);
|
||||||
|
else
|
||||||
|
release_mutex(m_mutex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void recursive_mutex::do_unlock()
|
void recursive_mutex::do_unlock()
|
||||||
{
|
{
|
||||||
if (--m_count == 0)
|
if (--m_count == 0)
|
||||||
LeaveCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(m_mutex));
|
{
|
||||||
|
if (m_critical_section)
|
||||||
|
release_critical_section(m_mutex);
|
||||||
|
else
|
||||||
|
release_mutex(m_mutex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void recursive_mutex::do_lock(cv_state& state)
|
void recursive_mutex::do_lock(cv_state& state)
|
||||||
{
|
{
|
||||||
EnterCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(m_mutex));
|
if (m_critical_section)
|
||||||
|
wait_critical_section_infinite(m_mutex);
|
||||||
|
else
|
||||||
|
wait_mutex(m_mutex, INFINITE);
|
||||||
|
|
||||||
m_count = state;
|
m_count = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,49 +98,66 @@ void recursive_mutex::do_unlock(cv_state& state)
|
|||||||
{
|
{
|
||||||
state = m_count;
|
state = m_count;
|
||||||
m_count = 0;
|
m_count = 0;
|
||||||
LeaveCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(m_mutex));
|
|
||||||
|
if (m_critical_section)
|
||||||
|
release_critical_section(m_mutex);
|
||||||
|
else
|
||||||
|
release_mutex(m_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
recursive_try_mutex::recursive_try_mutex()
|
recursive_try_mutex::recursive_try_mutex(const char* name)
|
||||||
: m_count(0)
|
: boost::detail::named_object(name)
|
||||||
|
, m_mutex(0)
|
||||||
|
, m_count(0)
|
||||||
|
, m_critical_section(false)
|
||||||
{
|
{
|
||||||
m_mutex = reinterpret_cast<void*>(CreateMutex(0, 0, 0));
|
m_critical_section = !name && has_TryEnterCriticalSection();
|
||||||
if (!m_mutex)
|
if (m_critical_section)
|
||||||
throw thread_resource_error();
|
m_mutex = new_critical_section();
|
||||||
|
else
|
||||||
|
m_mutex = new_mutex(effective_name());
|
||||||
}
|
}
|
||||||
|
|
||||||
recursive_try_mutex::~recursive_try_mutex()
|
recursive_try_mutex::~recursive_try_mutex()
|
||||||
{
|
{
|
||||||
int res = 0;
|
if (m_critical_section)
|
||||||
res = CloseHandle(reinterpret_cast<HANDLE>(m_mutex));
|
delete_critical_section(m_mutex);
|
||||||
assert(res);
|
else
|
||||||
|
delete_mutex(m_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void recursive_try_mutex::do_lock()
|
void recursive_try_mutex::do_lock()
|
||||||
{
|
{
|
||||||
int res = 0;
|
if (m_critical_section)
|
||||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), INFINITE);
|
wait_critical_section_infinite(m_mutex);
|
||||||
assert(res == WAIT_OBJECT_0);
|
else
|
||||||
|
wait_mutex(m_mutex, INFINITE);
|
||||||
|
|
||||||
if (++m_count > 1)
|
if (++m_count > 1)
|
||||||
{
|
{
|
||||||
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
if (m_critical_section)
|
||||||
assert(res);
|
release_critical_section(m_mutex);
|
||||||
|
else
|
||||||
|
release_mutex(m_mutex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool recursive_try_mutex::do_trylock()
|
bool recursive_try_mutex::do_trylock()
|
||||||
{
|
{
|
||||||
unsigned int res = 0;
|
bool res = false;
|
||||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), 0);
|
if (m_critical_section)
|
||||||
assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
|
res = wait_critical_section_try(m_mutex);
|
||||||
|
else
|
||||||
|
res = wait_mutex(m_mutex, 0) == WAIT_OBJECT_0;
|
||||||
|
|
||||||
if (res == WAIT_OBJECT_0)
|
if (res)
|
||||||
{
|
{
|
||||||
if (++m_count > 1)
|
if (++m_count > 1)
|
||||||
{
|
{
|
||||||
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
if (m_critical_section)
|
||||||
assert(res);
|
release_critical_section(m_mutex);
|
||||||
|
else
|
||||||
|
release_mutex(m_mutex);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -122,17 +168,19 @@ void recursive_try_mutex::do_unlock()
|
|||||||
{
|
{
|
||||||
if (--m_count == 0)
|
if (--m_count == 0)
|
||||||
{
|
{
|
||||||
int res = 0;
|
if (m_critical_section)
|
||||||
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
release_critical_section(m_mutex);
|
||||||
assert(res);
|
else
|
||||||
|
release_mutex(m_mutex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void recursive_try_mutex::do_lock(cv_state& state)
|
void recursive_try_mutex::do_lock(cv_state& state)
|
||||||
{
|
{
|
||||||
int res = 0;
|
if (m_critical_section)
|
||||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), INFINITE);
|
wait_critical_section_infinite(m_mutex);
|
||||||
assert(res == WAIT_OBJECT_0);
|
else
|
||||||
|
wait_mutex(m_mutex, INFINITE);
|
||||||
|
|
||||||
m_count = state;
|
m_count = state;
|
||||||
}
|
}
|
||||||
@@ -142,52 +190,41 @@ void recursive_try_mutex::do_unlock(cv_state& state)
|
|||||||
state = m_count;
|
state = m_count;
|
||||||
m_count = 0;
|
m_count = 0;
|
||||||
|
|
||||||
int res = 0;
|
if (m_critical_section)
|
||||||
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
release_critical_section(m_mutex);
|
||||||
assert(res);
|
else
|
||||||
|
release_mutex(m_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
recursive_timed_mutex::recursive_timed_mutex()
|
recursive_timed_mutex::recursive_timed_mutex(const char* name)
|
||||||
: m_count(0)
|
: boost::detail::named_object(name)
|
||||||
|
, m_mutex(0)
|
||||||
|
, m_count(0)
|
||||||
{
|
{
|
||||||
m_mutex = reinterpret_cast<void*>(CreateMutex(0, 0, 0));
|
m_mutex = new_mutex(effective_name());
|
||||||
if (!m_mutex)
|
|
||||||
throw thread_resource_error();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
recursive_timed_mutex::~recursive_timed_mutex()
|
recursive_timed_mutex::~recursive_timed_mutex()
|
||||||
{
|
{
|
||||||
int res = 0;
|
delete_mutex(m_mutex);
|
||||||
res = CloseHandle(reinterpret_cast<HANDLE>(m_mutex));
|
|
||||||
assert(res);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void recursive_timed_mutex::do_lock()
|
void recursive_timed_mutex::do_lock()
|
||||||
{
|
{
|
||||||
int res = 0;
|
wait_mutex(m_mutex, INFINITE);
|
||||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), INFINITE);
|
|
||||||
assert(res == WAIT_OBJECT_0);
|
|
||||||
|
|
||||||
if (++m_count > 1)
|
if (++m_count > 1)
|
||||||
{
|
release_mutex(m_mutex);
|
||||||
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
|
||||||
assert(res);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool recursive_timed_mutex::do_trylock()
|
bool recursive_timed_mutex::do_trylock()
|
||||||
{
|
{
|
||||||
unsigned int res = 0;
|
bool res = wait_mutex(m_mutex, 0) == WAIT_OBJECT_0;
|
||||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), 0);
|
|
||||||
assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
|
|
||||||
|
|
||||||
if (res == WAIT_OBJECT_0)
|
if (res)
|
||||||
{
|
{
|
||||||
if (++m_count > 1)
|
if (++m_count > 1)
|
||||||
{
|
release_mutex(m_mutex);
|
||||||
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
|
||||||
assert(res);
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -200,9 +237,7 @@ bool recursive_timed_mutex::do_timedlock(const xtime& xt)
|
|||||||
int milliseconds;
|
int milliseconds;
|
||||||
to_duration(xt, milliseconds);
|
to_duration(xt, milliseconds);
|
||||||
|
|
||||||
unsigned int res = 0;
|
unsigned int res = wait_mutex(m_mutex, milliseconds);
|
||||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), milliseconds);
|
|
||||||
assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
|
|
||||||
|
|
||||||
if (res == WAIT_TIMEOUT)
|
if (res == WAIT_TIMEOUT)
|
||||||
{
|
{
|
||||||
@@ -215,10 +250,7 @@ bool recursive_timed_mutex::do_timedlock(const xtime& xt)
|
|||||||
if (res == WAIT_OBJECT_0)
|
if (res == WAIT_OBJECT_0)
|
||||||
{
|
{
|
||||||
if (++m_count > 1)
|
if (++m_count > 1)
|
||||||
{
|
release_mutex(m_mutex);
|
||||||
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
|
||||||
assert(res);
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,18 +261,12 @@ bool recursive_timed_mutex::do_timedlock(const xtime& xt)
|
|||||||
void recursive_timed_mutex::do_unlock()
|
void recursive_timed_mutex::do_unlock()
|
||||||
{
|
{
|
||||||
if (--m_count == 0)
|
if (--m_count == 0)
|
||||||
{
|
release_mutex(m_mutex);
|
||||||
int res = 0;
|
|
||||||
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
|
||||||
assert(res);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void recursive_timed_mutex::do_lock(cv_state& state)
|
void recursive_timed_mutex::do_lock(cv_state& state)
|
||||||
{
|
{
|
||||||
int res = 0;
|
wait_mutex(m_mutex, INFINITE);
|
||||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), INFINITE);
|
|
||||||
assert(res == WAIT_OBJECT_0);
|
|
||||||
|
|
||||||
m_count = state;
|
m_count = state;
|
||||||
}
|
}
|
||||||
@@ -250,20 +276,21 @@ void recursive_timed_mutex::do_unlock(cv_state& state)
|
|||||||
state = m_count;
|
state = m_count;
|
||||||
m_count = 0;
|
m_count = 0;
|
||||||
|
|
||||||
int res = 0;
|
release_mutex(m_mutex);
|
||||||
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
|
||||||
assert(res);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(BOOST_HAS_PTHREADS)
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
recursive_mutex::recursive_mutex()
|
|
||||||
|
recursive_mutex::recursive_mutex(const char* name)
|
||||||
: m_count(0)
|
: m_count(0)
|
||||||
# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
|
# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
|
||||||
, m_valid_id(false)
|
, m_valid_id(false)
|
||||||
# endif
|
# endif
|
||||||
{
|
{
|
||||||
|
//:Use name parameter
|
||||||
|
|
||||||
pthread_mutexattr_t attr;
|
pthread_mutexattr_t attr;
|
||||||
int res = 0;
|
int res = pthread_mutexattr_init(&attr);
|
||||||
res = pthread_mutexattr_init(&attr);
|
|
||||||
assert(res == 0);
|
assert(res == 0);
|
||||||
|
|
||||||
# if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
|
# if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
|
||||||
@@ -272,6 +299,10 @@ recursive_mutex::recursive_mutex()
|
|||||||
# endif
|
# endif
|
||||||
|
|
||||||
res = pthread_mutex_init(&m_mutex, &attr);
|
res = pthread_mutex_init(&m_mutex, &attr);
|
||||||
|
{
|
||||||
|
int res = pthread_mutexattr_destroy(&attr);
|
||||||
|
assert(res == 0);
|
||||||
|
}
|
||||||
if (res != 0)
|
if (res != 0)
|
||||||
throw thread_resource_error();
|
throw thread_resource_error();
|
||||||
|
|
||||||
@@ -407,15 +438,16 @@ void recursive_mutex::do_unlock(cv_state& state)
|
|||||||
state.count = m_count;
|
state.count = m_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
recursive_try_mutex::recursive_try_mutex()
|
recursive_try_mutex::recursive_try_mutex(const char* name)
|
||||||
: m_count(0)
|
: m_count(0)
|
||||||
# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
|
# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
|
||||||
, m_valid_id(false)
|
, m_valid_id(false)
|
||||||
# endif
|
# endif
|
||||||
{
|
{
|
||||||
|
//:Use name parameter
|
||||||
|
|
||||||
pthread_mutexattr_t attr;
|
pthread_mutexattr_t attr;
|
||||||
int res = 0;
|
int res = pthread_mutexattr_init(&attr);
|
||||||
res = pthread_mutexattr_init(&attr);
|
|
||||||
assert(res == 0);
|
assert(res == 0);
|
||||||
|
|
||||||
# if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
|
# if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
|
||||||
@@ -424,6 +456,10 @@ recursive_try_mutex::recursive_try_mutex()
|
|||||||
# endif
|
# endif
|
||||||
|
|
||||||
res = pthread_mutex_init(&m_mutex, &attr);
|
res = pthread_mutex_init(&m_mutex, &attr);
|
||||||
|
{
|
||||||
|
int res = pthread_mutexattr_destroy(&attr);
|
||||||
|
assert(res == 0);
|
||||||
|
}
|
||||||
if (res != 0)
|
if (res != 0)
|
||||||
throw thread_resource_error();
|
throw thread_resource_error();
|
||||||
|
|
||||||
@@ -603,9 +639,11 @@ void recursive_try_mutex::do_unlock(cv_state& state)
|
|||||||
state.count = m_count;
|
state.count = m_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
recursive_timed_mutex::recursive_timed_mutex()
|
recursive_timed_mutex::recursive_timed_mutex(const char* name)
|
||||||
: m_valid_id(false), m_count(0)
|
: m_valid_id(false), m_count(0)
|
||||||
{
|
{
|
||||||
|
//:Use name parameter
|
||||||
|
|
||||||
int res = 0;
|
int res = 0;
|
||||||
res = pthread_mutex_init(&m_mutex, 0);
|
res = pthread_mutex_init(&m_mutex, 0);
|
||||||
if (res != 0)
|
if (res != 0)
|
||||||
@@ -781,14 +819,16 @@ void recursive_timed_mutex::do_unlock(cv_state& state)
|
|||||||
state.pmutex = &m_mutex;
|
state.pmutex = &m_mutex;
|
||||||
state.count = m_count;
|
state.count = m_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(BOOST_HAS_MPTASKS)
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
|
|
||||||
using threads::mac::detail::safe_enter_critical_region;
|
using threads::mac::detail::safe_enter_critical_region;
|
||||||
|
|
||||||
|
|
||||||
recursive_mutex::recursive_mutex()
|
recursive_mutex::recursive_mutex(const char* name)
|
||||||
: m_count(0)
|
: m_count(0)
|
||||||
{
|
{
|
||||||
|
//:Use name parameter
|
||||||
}
|
}
|
||||||
|
|
||||||
recursive_mutex::~recursive_mutex()
|
recursive_mutex::~recursive_mutex()
|
||||||
@@ -798,7 +838,8 @@ recursive_mutex::~recursive_mutex()
|
|||||||
void recursive_mutex::do_lock()
|
void recursive_mutex::do_lock()
|
||||||
{
|
{
|
||||||
OSStatus lStatus = noErr;
|
OSStatus lStatus = noErr;
|
||||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||||
|
m_mutex_mutex);
|
||||||
assert(lStatus == noErr);
|
assert(lStatus == noErr);
|
||||||
|
|
||||||
if (++m_count > 1)
|
if (++m_count > 1)
|
||||||
@@ -821,7 +862,8 @@ void recursive_mutex::do_unlock()
|
|||||||
void recursive_mutex::do_lock(cv_state& state)
|
void recursive_mutex::do_lock(cv_state& state)
|
||||||
{
|
{
|
||||||
OSStatus lStatus = noErr;
|
OSStatus lStatus = noErr;
|
||||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||||
|
m_mutex_mutex);
|
||||||
assert(lStatus == noErr);
|
assert(lStatus == noErr);
|
||||||
|
|
||||||
m_count = state;
|
m_count = state;
|
||||||
@@ -837,9 +879,10 @@ void recursive_mutex::do_unlock(cv_state& state)
|
|||||||
assert(lStatus == noErr);
|
assert(lStatus == noErr);
|
||||||
}
|
}
|
||||||
|
|
||||||
recursive_try_mutex::recursive_try_mutex()
|
recursive_try_mutex::recursive_try_mutex(const char* name)
|
||||||
: m_count(0)
|
: m_count(0)
|
||||||
{
|
{
|
||||||
|
//:Use name parameter
|
||||||
}
|
}
|
||||||
|
|
||||||
recursive_try_mutex::~recursive_try_mutex()
|
recursive_try_mutex::~recursive_try_mutex()
|
||||||
@@ -849,7 +892,8 @@ recursive_try_mutex::~recursive_try_mutex()
|
|||||||
void recursive_try_mutex::do_lock()
|
void recursive_try_mutex::do_lock()
|
||||||
{
|
{
|
||||||
OSStatus lStatus = noErr;
|
OSStatus lStatus = noErr;
|
||||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||||
|
m_mutex_mutex);
|
||||||
assert(lStatus == noErr);
|
assert(lStatus == noErr);
|
||||||
|
|
||||||
if (++m_count > 1)
|
if (++m_count > 1)
|
||||||
@@ -890,7 +934,8 @@ void recursive_try_mutex::do_unlock()
|
|||||||
void recursive_try_mutex::do_lock(cv_state& state)
|
void recursive_try_mutex::do_lock(cv_state& state)
|
||||||
{
|
{
|
||||||
OSStatus lStatus = noErr;
|
OSStatus lStatus = noErr;
|
||||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||||
|
m_mutex_mutex);
|
||||||
assert(lStatus == noErr);
|
assert(lStatus == noErr);
|
||||||
|
|
||||||
m_count = state;
|
m_count = state;
|
||||||
@@ -906,9 +951,10 @@ void recursive_try_mutex::do_unlock(cv_state& state)
|
|||||||
assert(lStatus == noErr);
|
assert(lStatus == noErr);
|
||||||
}
|
}
|
||||||
|
|
||||||
recursive_timed_mutex::recursive_timed_mutex()
|
recursive_timed_mutex::recursive_timed_mutex(const char* name)
|
||||||
: m_count(0)
|
: m_count(0)
|
||||||
{
|
{
|
||||||
|
//:Use name parameter
|
||||||
}
|
}
|
||||||
|
|
||||||
recursive_timed_mutex::~recursive_timed_mutex()
|
recursive_timed_mutex::~recursive_timed_mutex()
|
||||||
@@ -918,7 +964,8 @@ recursive_timed_mutex::~recursive_timed_mutex()
|
|||||||
void recursive_timed_mutex::do_lock()
|
void recursive_timed_mutex::do_lock()
|
||||||
{
|
{
|
||||||
OSStatus lStatus = noErr;
|
OSStatus lStatus = noErr;
|
||||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||||
|
m_mutex_mutex);
|
||||||
assert(lStatus == noErr);
|
assert(lStatus == noErr);
|
||||||
|
|
||||||
if (++m_count > 1)
|
if (++m_count > 1)
|
||||||
@@ -981,7 +1028,8 @@ void recursive_timed_mutex::do_unlock()
|
|||||||
void recursive_timed_mutex::do_lock(cv_state& state)
|
void recursive_timed_mutex::do_lock(cv_state& state)
|
||||||
{
|
{
|
||||||
OSStatus lStatus = noErr;
|
OSStatus lStatus = noErr;
|
||||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever, m_mutex_mutex);
|
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||||
|
m_mutex_mutex);
|
||||||
assert(lStatus == noErr);
|
assert(lStatus == noErr);
|
||||||
|
|
||||||
m_count = state;
|
m_count = state;
|
||||||
@@ -996,6 +1044,7 @@ void recursive_timed_mutex::do_unlock(cv_state& state)
|
|||||||
lStatus = MPExitCriticalRegion(m_mutex);
|
lStatus = MPExitCriticalRegion(m_mutex);
|
||||||
assert(lStatus == noErr);
|
assert(lStatus == noErr);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} // namespace boost
|
} // namespace boost
|
||||||
|
|||||||
191
src/shared_memory.cpp
Normal file
191
src/shared_memory.cpp
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
// Copyright (C) 2002
|
||||||
|
// William E. Kempf, David Moore
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
|
// and its documentation for any purpose is hereby granted without fee,
|
||||||
|
// provided that the above copyright notice appear in all copies and
|
||||||
|
// that both that copyright notice and this permission notice appear
|
||||||
|
// in supporting documentation. William E. Kempf makes no representations
|
||||||
|
// about the suitability of this software for any purpose.
|
||||||
|
// It is provided "as is" without express or implied warranty.
|
||||||
|
|
||||||
|
#include <boost/thread/detail/config.hpp>
|
||||||
|
|
||||||
|
#include <boost/thread/shared_memory.hpp>
|
||||||
|
#include <boost/thread/once.hpp>
|
||||||
|
#include <boost/thread/mutex.hpp>
|
||||||
|
|
||||||
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
#include <windows.h>
|
||||||
|
#include <winbase.h>
|
||||||
|
|
||||||
|
// Next line should really be BOOST_HAS_POSIX_xxx
|
||||||
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
|
|
||||||
|
//#include <sys/shm.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <semaphore.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
shared_memory::shared_memory(const char *name, size_t len, int flags)
|
||||||
|
: boost::detail::named_object(name)
|
||||||
|
{
|
||||||
|
init(len, flags, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
shared_memory::shared_memory(const char *name, size_t len, int flags,
|
||||||
|
const boost::function1<void, void *>& initfunc)
|
||||||
|
: boost::detail::named_object(name)
|
||||||
|
{
|
||||||
|
init(len, flags & create, &initfunc);
|
||||||
|
}
|
||||||
|
|
||||||
|
shared_memory::~shared_memory()
|
||||||
|
{
|
||||||
|
if (m_ptr)
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
res = UnmapViewOfFile(m_ptr);
|
||||||
|
assert(res);
|
||||||
|
res = CloseHandle(reinterpret_cast<HANDLE>(m_hmap));
|
||||||
|
assert(res);
|
||||||
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
|
res = munmap(reinterpret_cast<char*>(m_ptr), m_len);
|
||||||
|
assert(res == 0);
|
||||||
|
res = close(m_hmap);
|
||||||
|
assert(res == 0);
|
||||||
|
res = shm_unlink(effective_name());
|
||||||
|
assert(res == 0);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void shared_memory::init(size_t len, int flags,
|
||||||
|
const boost::function1<void,void *>* initfunc)
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
bool should_init = false;
|
||||||
|
|
||||||
|
std::string ename = effective_name();
|
||||||
|
std::string mxname = ename + "mx94543CBD1523443dB128451E51B5103E";
|
||||||
|
|
||||||
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
HANDLE mutex = CreateMutexA(0, FALSE, mxname.c_str());
|
||||||
|
if (mutex == INVALID_HANDLE_VALUE)
|
||||||
|
throw thread_resource_error();
|
||||||
|
res = WaitForSingleObject(mutex, INFINITE);
|
||||||
|
assert(res == WAIT_OBJECT_0);
|
||||||
|
|
||||||
|
if (flags & create)
|
||||||
|
{
|
||||||
|
DWORD protect = (flags & write) ? PAGE_READWRITE : PAGE_READONLY;
|
||||||
|
m_hmap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, protect,
|
||||||
|
0, len, ename.c_str());
|
||||||
|
if (m_hmap == INVALID_HANDLE_VALUE ||
|
||||||
|
((flags & exclusive) && GetLastError() == ERROR_ALREADY_EXISTS))
|
||||||
|
{
|
||||||
|
res = ReleaseMutex(mutex);
|
||||||
|
assert(res);
|
||||||
|
res = CloseHandle(mutex);
|
||||||
|
assert(res);
|
||||||
|
if (m_hmap != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
res = CloseHandle(m_hmap);
|
||||||
|
assert(res);
|
||||||
|
}
|
||||||
|
throw thread_resource_error();
|
||||||
|
}
|
||||||
|
should_init = GetLastError() != ERROR_ALREADY_EXISTS;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DWORD protect = (flags & write) ? FILE_MAP_WRITE : FILE_MAP_READ;
|
||||||
|
m_hmap = OpenFileMapping(protect, FALSE, ename.c_str());
|
||||||
|
if (m_hmap == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
res = ReleaseMutex(mutex);
|
||||||
|
assert(res);
|
||||||
|
res = CloseHandle(mutex);
|
||||||
|
assert(res);
|
||||||
|
throw thread_resource_error();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_ptr = MapViewOfFile(m_hmap, FILE_MAP_WRITE, 0, 0, 0);
|
||||||
|
assert(m_ptr);
|
||||||
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
|
m_len = len;
|
||||||
|
|
||||||
|
sem_t* sem = sem_open(mxname.c_str(), O_CREAT);
|
||||||
|
if (sem == SEM_FAILED)
|
||||||
|
throw thread_resource_error();
|
||||||
|
res = sem_wait(sem);
|
||||||
|
assert(res == 0);
|
||||||
|
|
||||||
|
int oflag = (flags & write) ? O_RDWR : O_RDONLY;
|
||||||
|
int cflag = (flags & create) ? O_CREAT|O_TRUNC|O_EXCL : 0;
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
m_hmap = shm_open(m_name.c_str(), oflag|cflag, 0);
|
||||||
|
if (m_hmap == -1)
|
||||||
|
{
|
||||||
|
if (errno != EEXIST || (flags & exclusive))
|
||||||
|
{
|
||||||
|
res = sem_post(sem);
|
||||||
|
assert(res == 0);
|
||||||
|
res = sem_close(sem);
|
||||||
|
assert(res == 0);
|
||||||
|
res = sem_unlink(mxname.c_str());
|
||||||
|
assert(res);
|
||||||
|
throw thread_resource_error();
|
||||||
|
}
|
||||||
|
m_hmap = shm_open(m_name.c_str(), oflag, 0);
|
||||||
|
if (m_hmap == -1)
|
||||||
|
{
|
||||||
|
if (errno == ENOENT)
|
||||||
|
continue;
|
||||||
|
res = sem_post(sem);
|
||||||
|
assert(res == 0);
|
||||||
|
res = sem_close(sem);
|
||||||
|
assert(res);
|
||||||
|
res = sem_unlink(mxname.c_str());
|
||||||
|
assert(res);
|
||||||
|
throw thread_resource_error();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
should_init = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ftruncate(m_hmap, len);
|
||||||
|
int prot = (flags & write) ? PROT_READ|PROT_WRITE : PROT_READ;
|
||||||
|
m_ptr = mmap(0, m_len, prot, MAP_SHARED, m_hmap, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (should_init && initfunc)
|
||||||
|
(*initfunc)(m_ptr);
|
||||||
|
|
||||||
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
res = ReleaseMutex(mutex);
|
||||||
|
assert(res);
|
||||||
|
res = CloseHandle(mutex);
|
||||||
|
assert(res);
|
||||||
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
|
res = sem_post(sem);
|
||||||
|
assert(res == 0);
|
||||||
|
res = sem_close(sem);
|
||||||
|
assert(res == 0);
|
||||||
|
res = sem_unlink(mxname.c_str());
|
||||||
|
assert(res == 0);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
903
src/thread.cpp
903
src/thread.cpp
File diff suppressed because it is too large
Load Diff
321
src/thread_pool.cpp
Normal file
321
src/thread_pool.cpp
Normal file
@@ -0,0 +1,321 @@
|
|||||||
|
// Copyright (C) 2002-2003
|
||||||
|
// David Moore, William E. Kempf
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
|
// and its documentation for any purpose is hereby granted without fee,
|
||||||
|
// provided that the above copyright notice appear in all copies and
|
||||||
|
// that both that copyright notice and this permission notice appear
|
||||||
|
// in supporting documentation. William E. Kempf makes no representations
|
||||||
|
// about the suitability of this software for any purpose.
|
||||||
|
// It is provided "as is" without express or implied warranty.
|
||||||
|
|
||||||
|
// Derived loosely from work queue manager in "Programming POSIX Threads"
|
||||||
|
// by David Butenhof.
|
||||||
|
|
||||||
|
#include <boost/thread/detail/config.hpp>
|
||||||
|
|
||||||
|
#include <boost/thread/thread_pool.hpp>
|
||||||
|
#include <boost/thread/thread.hpp>
|
||||||
|
#include <boost/thread/condition.hpp>
|
||||||
|
#include <boost/thread/mutex.hpp>
|
||||||
|
#include <boost/thread/xtime.hpp>
|
||||||
|
#include <boost/bind.hpp>
|
||||||
|
#include <list>
|
||||||
|
#include <queue>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
class thread_pool::impl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
impl(int max_threads, int min_threads, int timeout_secs,
|
||||||
|
int timeout_nsecs);
|
||||||
|
~impl();
|
||||||
|
|
||||||
|
void add(const boost::function0<void> &job);
|
||||||
|
void join();
|
||||||
|
void cancel();
|
||||||
|
void detach();
|
||||||
|
void worker_harness();
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
RUNNING,
|
||||||
|
CANCELLING,
|
||||||
|
JOINING,
|
||||||
|
JOINED,
|
||||||
|
DETACHED
|
||||||
|
} thread_pool_state;
|
||||||
|
|
||||||
|
typedef std::queue<boost::function0<void> > job_q;
|
||||||
|
|
||||||
|
condition m_more_work;
|
||||||
|
condition m_done;
|
||||||
|
mutex m_prot;
|
||||||
|
job_q m_jobs;
|
||||||
|
thread_group m_workers;
|
||||||
|
thread_pool_state m_state;
|
||||||
|
int m_max_threads; // Max threads allowed
|
||||||
|
int m_min_threads;
|
||||||
|
int m_thread_count; // Current number of threads
|
||||||
|
int m_idle_count; // Number of idle threads
|
||||||
|
int m_timeout_secs; // How long to keep idle threads
|
||||||
|
int m_timeout_nsecs;
|
||||||
|
};
|
||||||
|
|
||||||
|
thread_pool::impl::impl(int max_threads, int min_threads, int timeout_secs,
|
||||||
|
int timeout_nsecs)
|
||||||
|
: m_state(RUNNING), m_max_threads(max_threads), m_min_threads(min_threads),
|
||||||
|
m_thread_count(0), m_idle_count(0), m_timeout_secs(timeout_secs),
|
||||||
|
m_timeout_nsecs(timeout_nsecs)
|
||||||
|
{
|
||||||
|
// Immediately launch some worker threads.
|
||||||
|
//
|
||||||
|
// Not an exception safe implementation, yet.
|
||||||
|
while (min_threads-- > 0)
|
||||||
|
{
|
||||||
|
m_workers.create_thread(
|
||||||
|
bind(&thread_pool::impl::worker_harness, this));
|
||||||
|
m_thread_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
thread_pool::impl::~impl()
|
||||||
|
{
|
||||||
|
// Join in the destructor, unless they have already
|
||||||
|
// joined or detached.
|
||||||
|
mutex::scoped_lock lock(m_prot);
|
||||||
|
if (m_state == RUNNING)
|
||||||
|
{
|
||||||
|
lock.unlock();
|
||||||
|
join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void thread_pool::impl::add(const boost::function0<void> &job)
|
||||||
|
{
|
||||||
|
mutex::scoped_lock lock(m_prot);
|
||||||
|
|
||||||
|
// Note - can never reach this point if m_state == CANCELLED
|
||||||
|
// because the m_prot is held during the entire cancel operation.
|
||||||
|
|
||||||
|
assert(m_state == RUNNING);
|
||||||
|
|
||||||
|
m_jobs.push(job);
|
||||||
|
if (m_idle_count > 0)
|
||||||
|
m_more_work.notify_one();
|
||||||
|
else if (m_thread_count < m_max_threads)
|
||||||
|
{
|
||||||
|
// No idle threads, and we're below our limit. Spawn a new
|
||||||
|
// worker.
|
||||||
|
|
||||||
|
// What we really need is thread::detach(), or "create suspended"
|
||||||
|
m_workers.create_thread(
|
||||||
|
bind(&thread_pool::impl::worker_harness, this));
|
||||||
|
m_thread_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void thread_pool::impl::join()
|
||||||
|
{
|
||||||
|
mutex::scoped_lock lock(m_prot);
|
||||||
|
|
||||||
|
assert(m_state == RUNNING);
|
||||||
|
|
||||||
|
if (m_thread_count > 0)
|
||||||
|
{
|
||||||
|
m_state = JOINING;
|
||||||
|
|
||||||
|
// if any threads are idling, wake them.
|
||||||
|
if (m_idle_count > 0)
|
||||||
|
m_more_work.notify_all();
|
||||||
|
|
||||||
|
// Track the shutdown progress of the threads.
|
||||||
|
while (m_thread_count > 0)
|
||||||
|
m_done.wait(lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_workers.join_all();
|
||||||
|
m_state = JOINED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a "weak" form of cancel which empties out the job queue and takes
|
||||||
|
// the thread count down to zero.
|
||||||
|
//
|
||||||
|
// Upon receiving more work, the thread count would grow back up to
|
||||||
|
// min_threads.
|
||||||
|
//
|
||||||
|
// Cancel will be much stronger once full thread cancellation is in place!
|
||||||
|
|
||||||
|
void thread_pool::impl::cancel()
|
||||||
|
{
|
||||||
|
mutex::scoped_lock lock(m_prot);
|
||||||
|
|
||||||
|
assert(m_state == RUNNING);
|
||||||
|
|
||||||
|
if (m_thread_count > 0)
|
||||||
|
{
|
||||||
|
m_state = CANCELLING;
|
||||||
|
|
||||||
|
// Cancelling kills any unexecuted jobs.
|
||||||
|
while (!m_jobs.empty())
|
||||||
|
m_jobs.pop();
|
||||||
|
|
||||||
|
/* If we had cancel, this would be something like....
|
||||||
|
m_workers.cancel_all();
|
||||||
|
while(m_cancel_count > 0)
|
||||||
|
m_all_cancelled.wait(lock);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
m_state = RUNNING; // Go back to accepting work.
|
||||||
|
}
|
||||||
|
|
||||||
|
void thread_pool::impl::detach()
|
||||||
|
{
|
||||||
|
mutex::scoped_lock lock(m_prot);
|
||||||
|
if (m_state == RUNNING)
|
||||||
|
{
|
||||||
|
m_min_threads = 0;
|
||||||
|
m_state = DETACHED;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// detach during/after a join has no effect - the join will
|
||||||
|
// complete.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void thread_pool::impl::worker_harness()
|
||||||
|
{
|
||||||
|
boost::thread me;
|
||||||
|
|
||||||
|
xtime timeout;
|
||||||
|
int timedout;
|
||||||
|
|
||||||
|
mutex::scoped_lock lock(m_prot);
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
timedout = 0;
|
||||||
|
|
||||||
|
xtime_get(&timeout, boost::TIME_UTC);
|
||||||
|
timeout.sec += m_timeout_secs;
|
||||||
|
timeout.nsec += m_timeout_nsecs;
|
||||||
|
|
||||||
|
while (m_jobs.empty() && (m_state == RUNNING))
|
||||||
|
{
|
||||||
|
m_idle_count++;
|
||||||
|
bool status = m_more_work.timed_wait(lock, timeout);
|
||||||
|
m_idle_count--;
|
||||||
|
if (!status)
|
||||||
|
{
|
||||||
|
timedout = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_jobs.empty() && m_state != CANCELLING)
|
||||||
|
{
|
||||||
|
boost::function0<void> jobfunc = m_jobs.front();
|
||||||
|
m_jobs.pop();
|
||||||
|
lock.unlock();
|
||||||
|
jobfunc();
|
||||||
|
lock.lock();
|
||||||
|
}
|
||||||
|
else if (m_jobs.empty() && m_state == JOINING)
|
||||||
|
{
|
||||||
|
m_thread_count--;
|
||||||
|
|
||||||
|
// If we are the last worker exiting, let everyone know about it!
|
||||||
|
if (m_thread_count == 0)
|
||||||
|
m_done.notify_all();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (m_jobs.empty() && m_state == DETACHED)
|
||||||
|
{
|
||||||
|
m_thread_count--;
|
||||||
|
|
||||||
|
// If we are the last worker exiting, let everyone know about it!
|
||||||
|
if (m_thread_count == 0)
|
||||||
|
{
|
||||||
|
lock.unlock();
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If there's no more work, and we wait for as long as
|
||||||
|
* we're allowed, then terminate this server thread.
|
||||||
|
*/
|
||||||
|
if (m_jobs.empty() && timedout)
|
||||||
|
{
|
||||||
|
if (m_thread_count > m_min_threads)
|
||||||
|
{
|
||||||
|
m_thread_count--;
|
||||||
|
|
||||||
|
if (m_state == DETACHED &&
|
||||||
|
m_thread_count == 0)
|
||||||
|
{
|
||||||
|
lock.unlock();
|
||||||
|
delete this;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We aren't in a JOINING or CANCELLING state, so trim
|
||||||
|
// down our resource usage and clean ourselves up.
|
||||||
|
// thread* thrd = m_workers.find(me);
|
||||||
|
m_workers.remove_thread(me);
|
||||||
|
// delete thrd;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
thread_pool::thread_pool(int max_threads, int min_threads, int timeout_secs,
|
||||||
|
int timeout_nsecs)
|
||||||
|
: m_pimpl(new impl(max_threads, min_threads, timeout_secs, timeout_nsecs))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
thread_pool::~thread_pool()
|
||||||
|
{
|
||||||
|
if (m_pimpl != NULL)
|
||||||
|
delete m_pimpl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void thread_pool::add(const boost::function0<void> &job)
|
||||||
|
{
|
||||||
|
assert(m_pimpl);
|
||||||
|
m_pimpl->add(job);
|
||||||
|
}
|
||||||
|
|
||||||
|
void thread_pool::join()
|
||||||
|
{
|
||||||
|
assert(m_pimpl);
|
||||||
|
m_pimpl->join();
|
||||||
|
}
|
||||||
|
|
||||||
|
void thread_pool::cancel()
|
||||||
|
{
|
||||||
|
assert(m_pimpl);
|
||||||
|
m_pimpl->cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
void thread_pool::detach()
|
||||||
|
{
|
||||||
|
assert(m_pimpl);
|
||||||
|
|
||||||
|
// Tell our implementation it is running detached.
|
||||||
|
m_pimpl->detach();
|
||||||
|
m_pimpl = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
@@ -1,165 +1,185 @@
|
|||||||
// threadmon.cpp : Defines the entry point for the DLL application.
|
// Copyright (C) 2001-2003
|
||||||
|
// William E. Kempf
|
||||||
//
|
//
|
||||||
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
|
// and its documentation for any purpose is hereby granted without fee,
|
||||||
|
// provided that the above copyright notice appear in all copies and
|
||||||
|
// that both that copyright notice and this permission notice appear
|
||||||
|
// in supporting documentation. William E. Kempf makes no representations
|
||||||
|
// about the suitability of this software for any purpose.
|
||||||
|
// It is provided "as is" without express or implied warranty.
|
||||||
|
|
||||||
#include <boost/config.hpp>
|
#include <boost/thread/detail/config.hpp>
|
||||||
|
|
||||||
#if defined(BOOST_HAS_WINTHREADS)
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
extern "C" void tss_cleanup_implemented(void);
|
||||||
#if defined(BOOST_THREAD_BUILD_DLL)
|
|
||||||
|
void require_tss_cleanup_implemented(void)
|
||||||
#include <boost/thread/detail/threadmon.hpp>
|
|
||||||
|
|
||||||
#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:
|
tss_cleanup_implemented();
|
||||||
InitializeCriticalSection(&cs);
|
}
|
||||||
|
|
||||||
|
#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 <boost/thread/detail/threadmon.hpp>
|
||||||
|
|
||||||
|
typedef void (__cdecl * handler)(void);
|
||||||
|
typedef std::list<handler> exit_handlers;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
const DWORD invalid_key = TLS_OUT_OF_INDEXES;
|
||||||
|
static DWORD key = invalid_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
BOOST_THREAD_DECL int at_thread_exit(void (__cdecl * func)(void))
|
||||||
|
{
|
||||||
|
//Get the exit handlers for the current thread,
|
||||||
|
//creating and registering one if it doesn't exist.
|
||||||
|
|
||||||
|
if (key == invalid_key)
|
||||||
key = TlsAlloc();
|
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
|
if (key == invalid_key)
|
||||||
// and then destroy it.
|
return -1;
|
||||||
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
|
exit_handlers* handlers =
|
||||||
// there'd only be the main thread left, but to insure we
|
static_cast<exit_handlers*>(TlsGetValue(key));
|
||||||
// don't get memory leaks we won't make that assumption
|
|
||||||
// here.
|
|
||||||
EnterCriticalSection(&cs);
|
|
||||||
for (registered_handlers::iterator it = registry.begin();
|
|
||||||
it != registry.end(); ++it)
|
|
||||||
{
|
|
||||||
delete (*it);
|
|
||||||
}
|
|
||||||
LeaveCriticalSection(&cs);
|
|
||||||
DeleteCriticalSection(&cs);
|
|
||||||
TlsFree(key);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" BOOST_THREAD_DECL int on_thread_exit(void (__cdecl * func)(void))
|
if (!handlers)
|
||||||
{
|
|
||||||
// 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;
|
try
|
||||||
// Handle broken implementations of operator new that don't throw.
|
{
|
||||||
if (!handlers)
|
handlers = new exit_handlers;
|
||||||
|
|
||||||
|
//Handle broken implementations
|
||||||
|
//of operator new that don't throw
|
||||||
|
if (!handlers)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
catch (...)
|
|
||||||
{
|
//Attempt to set a TLS value for the new handlers.
|
||||||
return -1;
|
if (!TlsSetValue(key, handlers))
|
||||||
|
{
|
||||||
|
delete handlers;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attempt to set a TLS value for the new handlers.
|
//Attempt to add the handler to the list of exit handlers.
|
||||||
if (!TlsSetValue(key, handlers))
|
|
||||||
{
|
|
||||||
delete handlers;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attempt to register this new handler so that memory can be properly
|
|
||||||
// cleaned up.
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
EnterCriticalSection(&cs);
|
handlers->push_front(func);
|
||||||
registry.insert(handlers);
|
|
||||||
LeaveCriticalSection(&cs);
|
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
LeaveCriticalSection(&cs);
|
|
||||||
delete handlers;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" BOOST_THREAD_DECL void on_process_enter(void)
|
||||||
|
{
|
||||||
|
if (key == invalid_key)
|
||||||
|
key = TlsAlloc();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" BOOST_THREAD_DECL void on_thread_exit(void)
|
||||||
|
{
|
||||||
|
if (key == invalid_key)
|
||||||
|
return;
|
||||||
|
|
||||||
|
exit_handlers* handlers =
|
||||||
|
static_cast<exit_handlers*>(TlsGetValue(key));
|
||||||
|
|
||||||
|
if (handlers)
|
||||||
|
{
|
||||||
|
for (exit_handlers::iterator it = handlers->begin();
|
||||||
|
it != handlers->end();
|
||||||
|
++it)
|
||||||
|
{
|
||||||
|
//Call each exit handler
|
||||||
|
(*it)();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Destroy the exit handlers
|
||||||
|
delete handlers;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attempt to add the handler to the list of exit handlers. If it's been
|
extern "C" BOOST_THREAD_DECL void on_process_exit(void)
|
||||||
// previously added just report success and exit.
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
handlers->push_front(func);
|
if (key != invalid_key)
|
||||||
}
|
{
|
||||||
catch (...)
|
TlsFree(key);
|
||||||
{
|
key = invalid_key;
|
||||||
return -1;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
#if defined(BOOST_THREAD_BUILD_DLL)
|
||||||
}
|
extern "C" void tss_cleanup_implemented(void)
|
||||||
|
{
|
||||||
|
//Don't need to do anything; this function's
|
||||||
|
//sole purpose is to cause a link error in cases
|
||||||
|
//where tss cleanup is not implemented by Boost.Threads
|
||||||
|
//as a reminder that user code is responsible for calling
|
||||||
|
//on_process_enter(), on_thread_exit(), and
|
||||||
|
//on_process_exit() at the appropriate times
|
||||||
|
//and implementing an empty tss_cleanup_implemented()
|
||||||
|
//function to eliminate the link error.
|
||||||
|
}
|
||||||
|
|
||||||
#endif // BOOST_THREAD_BUILD_DLL
|
#if defined(__BORLANDC__)
|
||||||
|
#define DllMain DllEntryPoint
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
BOOL WINAPI DllMain(HANDLE /*module*/, DWORD reason, LPVOID)
|
||||||
|
{
|
||||||
|
switch (reason)
|
||||||
|
{
|
||||||
|
case DLL_PROCESS_ATTACH:
|
||||||
|
{
|
||||||
|
on_process_enter();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DLL_THREAD_ATTACH:
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DLL_THREAD_DETACH:
|
||||||
|
{
|
||||||
|
on_thread_exit();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DLL_PROCESS_DETACH:
|
||||||
|
{
|
||||||
|
on_thread_exit();
|
||||||
|
on_process_exit();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
#endif // BOOST_THREAD_BUILD_DLL
|
||||||
#endif // BOOST_HAS_WINTHREADS
|
#endif // BOOST_HAS_WINTHREADS
|
||||||
|
|
||||||
|
// Change Log:
|
||||||
|
// 20 Mar 04 GLASSFORM for WEKEMPF
|
||||||
|
// Removed uneccessary critical section:
|
||||||
|
// Windows already serializes calls to DllMain.
|
||||||
|
// Removed registered_handlers.
|
||||||
179
src/timeconv.inl
179
src/timeconv.inl
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2001
|
// Copyright (C) 2001-2003
|
||||||
// William E. Kempf
|
// William E. Kempf
|
||||||
//
|
//
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
@@ -10,118 +10,119 @@
|
|||||||
// It is provided "as is" without express or implied warranty.
|
// It is provided "as is" without express or implied warranty.
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
const int MILLISECONDS_PER_SECOND = 1000;
|
const int MILLISECONDS_PER_SECOND = 1000;
|
||||||
const int NANOSECONDS_PER_SECOND = 1000000000;
|
const int NANOSECONDS_PER_SECOND = 1000000000;
|
||||||
const int NANOSECONDS_PER_MILLISECOND = 1000000;
|
const int NANOSECONDS_PER_MILLISECOND = 1000000;
|
||||||
|
|
||||||
const int MICROSECONDS_PER_SECOND = 1000000;
|
const int MICROSECONDS_PER_SECOND = 1000000;
|
||||||
const int NANOSECONDS_PER_MICROSECOND = 1000;
|
const int NANOSECONDS_PER_MICROSECOND = 1000;
|
||||||
|
|
||||||
inline void to_time(int milliseconds, boost::xtime& xt)
|
inline void to_time(int milliseconds, boost::xtime& xt)
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
res = boost::xtime_get(&xt, boost::TIME_UTC);
|
||||||
|
assert(res == boost::TIME_UTC);
|
||||||
|
|
||||||
|
xt.sec += (milliseconds / MILLISECONDS_PER_SECOND);
|
||||||
|
xt.nsec += ((milliseconds % MILLISECONDS_PER_SECOND) *
|
||||||
|
NANOSECONDS_PER_MILLISECOND);
|
||||||
|
|
||||||
|
if (xt.nsec > static_cast<const int>(NANOSECONDS_PER_SECOND))
|
||||||
{
|
{
|
||||||
int res = 0;
|
++xt.sec;
|
||||||
res = boost::xtime_get(&xt, boost::TIME_UTC);
|
xt.nsec -= NANOSECONDS_PER_SECOND;
|
||||||
assert(res == boost::TIME_UTC);
|
|
||||||
|
|
||||||
xt.sec += (milliseconds / MILLISECONDS_PER_SECOND);
|
|
||||||
xt.nsec += ((milliseconds % MILLISECONDS_PER_SECOND) * NANOSECONDS_PER_MILLISECOND);
|
|
||||||
|
|
||||||
if (xt.nsec > static_cast<const int>(NANOSECONDS_PER_SECOND))
|
|
||||||
{
|
|
||||||
++xt.sec;
|
|
||||||
xt.nsec -= NANOSECONDS_PER_SECOND;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(BOOST_HAS_PTHREADS)
|
#if defined(BOOST_HAS_PTHREADS)
|
||||||
inline void to_timespec(const boost::xtime& xt, timespec& ts)
|
inline void to_timespec(const boost::xtime& xt, timespec& ts)
|
||||||
|
{
|
||||||
|
ts.tv_sec = static_cast<int>(xt.sec);
|
||||||
|
ts.tv_nsec = static_cast<int>(xt.nsec);
|
||||||
|
if(ts.tv_nsec > static_cast<const int>(NANOSECONDS_PER_SECOND))
|
||||||
{
|
{
|
||||||
ts.tv_sec = static_cast<int>(xt.sec);
|
ts.tv_sec += ts.tv_nsec / NANOSECONDS_PER_SECOND;
|
||||||
ts.tv_nsec = static_cast<int>(xt.nsec);
|
ts.tv_nsec %= NANOSECONDS_PER_SECOND;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void to_time(int milliseconds, timespec& ts)
|
||||||
|
{
|
||||||
|
boost::xtime xt;
|
||||||
|
to_time(milliseconds, xt);
|
||||||
|
to_timespec(xt, ts);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void to_timespec_duration(const boost::xtime& xt, timespec& ts)
|
||||||
|
{
|
||||||
|
boost::xtime cur;
|
||||||
|
int res = 0;
|
||||||
|
res = boost::xtime_get(&cur, boost::TIME_UTC);
|
||||||
|
assert(res == boost::TIME_UTC);
|
||||||
|
|
||||||
|
if (boost::xtime_cmp(xt, cur) <= 0)
|
||||||
|
{
|
||||||
|
ts.tv_sec = 0;
|
||||||
|
ts.tv_nsec = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ts.tv_sec = xt.sec - cur.sec;
|
||||||
|
ts.tv_nsec = xt.nsec - cur.nsec;
|
||||||
|
|
||||||
|
if( ts.tv_nsec < 0 )
|
||||||
|
{
|
||||||
|
ts.tv_sec -= 1;
|
||||||
|
ts.tv_nsec += NANOSECONDS_PER_SECOND;
|
||||||
|
}
|
||||||
if(ts.tv_nsec > static_cast<const int>(NANOSECONDS_PER_SECOND))
|
if(ts.tv_nsec > static_cast<const int>(NANOSECONDS_PER_SECOND))
|
||||||
{
|
{
|
||||||
ts.tv_sec += ts.tv_nsec / NANOSECONDS_PER_SECOND;
|
ts.tv_sec += ts.tv_nsec / NANOSECONDS_PER_SECOND;
|
||||||
ts.tv_nsec %= NANOSECONDS_PER_SECOND;
|
ts.tv_nsec %= NANOSECONDS_PER_SECOND;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
inline void to_time(int milliseconds, timespec& ts)
|
|
||||||
{
|
|
||||||
boost::xtime xt;
|
|
||||||
to_time(milliseconds, xt);
|
|
||||||
to_timespec(xt, ts);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void to_timespec_duration(const boost::xtime& xt, timespec& ts)
|
|
||||||
{
|
|
||||||
boost::xtime cur;
|
|
||||||
int res = 0;
|
|
||||||
res = boost::xtime_get(&cur, boost::TIME_UTC);
|
|
||||||
assert(res == boost::TIME_UTC);
|
|
||||||
|
|
||||||
if (boost::xtime_cmp(xt, cur) <= 0)
|
|
||||||
{
|
|
||||||
ts.tv_sec = 0;
|
|
||||||
ts.tv_nsec = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ts.tv_sec = xt.sec - cur.sec;
|
|
||||||
ts.tv_nsec = xt.nsec - cur.nsec;
|
|
||||||
|
|
||||||
if( ts.tv_nsec < 0 )
|
|
||||||
{
|
|
||||||
ts.tv_sec -= 1;
|
|
||||||
ts.tv_nsec += NANOSECONDS_PER_SECOND;
|
|
||||||
}
|
|
||||||
if(ts.tv_nsec > static_cast<const int>(NANOSECONDS_PER_SECOND))
|
|
||||||
{
|
|
||||||
ts.tv_sec += ts.tv_nsec / NANOSECONDS_PER_SECOND;
|
|
||||||
ts.tv_nsec %= NANOSECONDS_PER_SECOND;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
inline void to_duration(boost::xtime xt, int& milliseconds)
|
inline void to_duration(boost::xtime xt, int& milliseconds)
|
||||||
{
|
{
|
||||||
boost::xtime cur;
|
boost::xtime cur;
|
||||||
int res = 0;
|
int res = 0;
|
||||||
res = boost::xtime_get(&cur, boost::TIME_UTC);
|
res = boost::xtime_get(&cur, boost::TIME_UTC);
|
||||||
assert(res == boost::TIME_UTC);
|
assert(res == boost::TIME_UTC);
|
||||||
|
|
||||||
if (boost::xtime_cmp(xt, cur) <= 0)
|
if (boost::xtime_cmp(xt, cur) <= 0)
|
||||||
milliseconds = 0;
|
milliseconds = 0;
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
if (cur.nsec > xt.nsec)
|
||||||
{
|
{
|
||||||
if (cur.nsec > xt.nsec)
|
xt.nsec += NANOSECONDS_PER_SECOND;
|
||||||
{
|
--xt.sec;
|
||||||
xt.nsec += NANOSECONDS_PER_SECOND;
|
}
|
||||||
--xt.sec;
|
milliseconds = (int)((xt.sec - cur.sec) * MILLISECONDS_PER_SECOND) +
|
||||||
}
|
(((xt.nsec - cur.nsec) + (NANOSECONDS_PER_MILLISECOND/2)) /
|
||||||
milliseconds = ((xt.sec - cur.sec) * MILLISECONDS_PER_SECOND) +
|
|
||||||
(((xt.nsec - cur.nsec) + (NANOSECONDS_PER_MILLISECOND/2)) /
|
|
||||||
NANOSECONDS_PER_MILLISECOND);
|
NANOSECONDS_PER_MILLISECOND);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inline void to_microduration(const boost::xtime& xt, int& microseconds)
|
inline void to_microduration(const boost::xtime& xt, int& microseconds)
|
||||||
|
{
|
||||||
|
boost::xtime cur;
|
||||||
|
int res = 0;
|
||||||
|
res = boost::xtime_get(&cur, boost::TIME_UTC);
|
||||||
|
assert(res == boost::TIME_UTC);
|
||||||
|
|
||||||
|
if (boost::xtime_get(&cur, boost::TIME_UTC) <= 0)
|
||||||
|
microseconds = 0;
|
||||||
|
else
|
||||||
{
|
{
|
||||||
boost::xtime cur;
|
microseconds = (int)((xt.sec - cur.sec) * MICROSECONDS_PER_SECOND) +
|
||||||
int res = 0;
|
(((xt.nsec - cur.nsec) + (NANOSECONDS_PER_MICROSECOND/2)) /
|
||||||
res = boost::xtime_get(&cur, boost::TIME_UTC);
|
|
||||||
assert(res == boost::TIME_UTC);
|
|
||||||
|
|
||||||
if (boost::xtime_get(&cur, boost::TIME_UTC) <= 0)
|
|
||||||
microseconds = 0;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
microseconds = ((xt.sec - cur.sec) * MICROSECONDS_PER_SECOND) +
|
|
||||||
(((xt.nsec - cur.nsec) + (NANOSECONDS_PER_MICROSECOND/2)) /
|
|
||||||
NANOSECONDS_PER_MICROSECOND);
|
NANOSECONDS_PER_MICROSECOND);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Change Log:
|
// Change Log:
|
||||||
// 1 Jun 01 Initial creation.
|
// 1 Jun 01 Initial creation.
|
||||||
|
|||||||
371
src/tss.cpp
371
src/tss.cpp
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2001
|
// Copyright (C) 2001-2003
|
||||||
// William E. Kempf
|
// William E. Kempf
|
||||||
//
|
//
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
@@ -9,239 +9,206 @@
|
|||||||
// about the suitability of this software for any purpose.
|
// about the suitability of this software for any purpose.
|
||||||
// It is provided "as is" without express or implied warranty.
|
// It is provided "as is" without express or implied warranty.
|
||||||
|
|
||||||
|
#include <boost/thread/detail/config.hpp>
|
||||||
|
|
||||||
#include <boost/thread/tss.hpp>
|
#include <boost/thread/tss.hpp>
|
||||||
|
#ifndef BOOST_THREAD_NO_TSS_CLEANUP
|
||||||
|
|
||||||
#include <boost/thread/once.hpp>
|
#include <boost/thread/once.hpp>
|
||||||
|
#include <boost/thread/mutex.hpp>
|
||||||
#include <boost/thread/exceptions.hpp>
|
#include <boost/thread/exceptions.hpp>
|
||||||
|
#include <vector>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
#if defined(BOOST_HAS_WINTHREADS)
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
# include <windows.h>
|
# include <windows.h>
|
||||||
|
# include <boost/thread/detail/threadmon.hpp>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
typedef std::vector<void*> tss_slots;
|
||||||
|
|
||||||
|
struct tss_data_t
|
||||||
|
{
|
||||||
|
boost::mutex mutex;
|
||||||
|
std::vector<boost::function1<void, void*>*> cleanup_handlers;
|
||||||
#if defined(BOOST_HAS_WINTHREADS)
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
#include <boost/thread/detail/threadmon.hpp>
|
DWORD native_key;
|
||||||
#include <map>
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
namespace {
|
pthread_key_t native_key;
|
||||||
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)
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
#include <map>
|
TaskStorageIndex native_key;
|
||||||
namespace {
|
#endif
|
||||||
typedef std::pair<void(*)(void*), void*> cleanup_info;
|
};
|
||||||
typedef std::map<int, cleanup_info> cleanup_handlers;
|
|
||||||
|
|
||||||
TaskStorageIndex key;
|
tss_data_t* tss_data = 0;
|
||||||
boost::once_flag once = BOOST_ONCE_INIT;
|
boost::once_flag tss_data_once = BOOST_ONCE_INIT;
|
||||||
|
|
||||||
void init_cleanup_key()
|
extern "C" void cleanup_slots(void* p)
|
||||||
|
{
|
||||||
|
tss_slots* slots = static_cast<tss_slots*>(p);
|
||||||
|
for (tss_slots::size_type i = 0; i < slots->size(); ++i)
|
||||||
{
|
{
|
||||||
OSStatus lStatus = MPAllocateTaskStorageIndex(&key);
|
boost::mutex::scoped_lock lock(tss_data->mutex);
|
||||||
assert(lStatus == noErr);
|
(*tss_data->cleanup_handlers[i])((*slots)[i]);
|
||||||
}
|
(*slots)[i] = 0;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void init_tss_data()
|
||||||
|
{
|
||||||
|
std::auto_ptr<tss_data_t> temp(new tss_data_t);
|
||||||
|
|
||||||
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
temp->native_key = TlsAlloc();
|
||||||
|
if (temp->native_key == 0xFFFFFFFF)
|
||||||
|
return;
|
||||||
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
|
int res = pthread_key_create(&temp->native_key, &cleanup_slots);
|
||||||
|
if (res != 0)
|
||||||
|
return;
|
||||||
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
|
OSStatus status = MPAllocateTaskStorageIndex(&temp->native_key);
|
||||||
|
if (status != noErr)
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Intentional memory "leak"
|
||||||
|
// This is the only way to ensure the mutex in the global data
|
||||||
|
// structure is available when cleanup handlers are run, since the
|
||||||
|
// execution order of cleanup handlers is unspecified on any platform
|
||||||
|
// with regards to C++ destructor ordering rules.
|
||||||
|
tss_data = temp.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
tss_slots* get_slots(bool alloc);
|
||||||
|
|
||||||
|
void __cdecl tss_thread_exit()
|
||||||
|
{
|
||||||
|
tss_slots* slots = get_slots(false);
|
||||||
|
if (slots)
|
||||||
|
cleanup_slots(slots);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
tss_slots* get_slots(bool alloc)
|
||||||
|
{
|
||||||
|
tss_slots* slots = 0;
|
||||||
|
|
||||||
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
slots = static_cast<tss_slots*>(
|
||||||
|
TlsGetValue(tss_data->native_key));
|
||||||
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
|
slots = static_cast<tss_slots*>(
|
||||||
|
pthread_getspecific(tss_data->native_key));
|
||||||
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
|
slots = static_cast<tss_slots*>(
|
||||||
|
MPGetTaskStorageValue(tss_data->native_key));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (slots == 0 && alloc)
|
||||||
|
{
|
||||||
|
std::auto_ptr<tss_slots> temp(new tss_slots);
|
||||||
|
|
||||||
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
if (at_thread_exit(&tss_thread_exit) == -1)
|
||||||
|
return 0;
|
||||||
|
if (!TlsSetValue(tss_data->native_key, temp.get()))
|
||||||
|
return 0;
|
||||||
|
#elif defined(BOOST_HAS_PTHREADS)
|
||||||
|
if (pthread_setspecific(tss_data->native_key, temp.get()) != 0)
|
||||||
|
return 0;
|
||||||
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
|
if (MPSetTaskStorageValue(tss_data->native_key, temp.get()) != noErr)
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
slots = temp.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
return slots;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
namespace boost {
|
namespace boost {
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
void tss::init(boost::function1<void, void*>* pcleanup)
|
||||||
|
|
||||||
void thread_cleanup()
|
|
||||||
{
|
{
|
||||||
cleanup_handlers* handlers = reinterpret_cast<cleanup_handlers*>(MPGetTaskStorageValue(key));
|
boost::call_once(&init_tss_data, tss_data_once);
|
||||||
if(handlers != NULL)
|
if (tss_data == 0)
|
||||||
|
throw thread_resource_error();
|
||||||
|
boost::mutex::scoped_lock lock(tss_data->mutex);
|
||||||
|
try
|
||||||
{
|
{
|
||||||
for (cleanup_handlers::iterator it = handlers->begin(); it != handlers->end(); ++it)
|
tss_data->cleanup_handlers.push_back(pcleanup);
|
||||||
|
m_slot = tss_data->cleanup_handlers.size() - 1;
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
throw thread_resource_error();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void* tss::get() const
|
||||||
|
{
|
||||||
|
tss_slots* slots = get_slots(false);
|
||||||
|
|
||||||
|
if (!slots)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (m_slot >= slots->size())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return (*slots)[m_slot];
|
||||||
|
}
|
||||||
|
|
||||||
|
void tss::set(void* value)
|
||||||
|
{
|
||||||
|
tss_slots* slots = get_slots(true);
|
||||||
|
|
||||||
|
if (!slots)
|
||||||
|
throw boost::thread_resource_error();
|
||||||
|
|
||||||
|
if (m_slot >= slots->size())
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
cleanup_info info = it->second;
|
slots->resize(m_slot + 1);
|
||||||
if (info.second)
|
}
|
||||||
info.first(info.second);
|
catch (...)
|
||||||
|
{
|
||||||
|
throw boost::thread_resource_error();
|
||||||
}
|
}
|
||||||
delete handlers;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
(*slots)[m_slot] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tss::cleanup(void* value)
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
} // namespace boost
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace boost { namespace detail {
|
|
||||||
|
|
||||||
#if defined(BOOST_HAS_WINTHREADS)
|
|
||||||
tss::tss(void (*cleanup)(void*))
|
|
||||||
{
|
{
|
||||||
m_key = TlsAlloc();
|
boost::mutex::scoped_lock lock(tss_data->mutex);
|
||||||
if (m_key == 0xFFFFFFFF)
|
(*tss_data->cleanup_handlers[m_slot])(value);
|
||||||
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 detail
|
||||||
} // namespace boost
|
} // namespace boost
|
||||||
|
|
||||||
|
#endif //BOOST_THREAD_NO_TSS_CLEANUP
|
||||||
|
|
||||||
// Change Log:
|
// Change Log:
|
||||||
// 6 Jun 01 WEKEMPF Initial version.
|
// 6 Jun 01
|
||||||
|
// WEKEMPF Initial version.
|
||||||
|
// 30 May 02 WEKEMPF
|
||||||
|
// Added interface to set specific cleanup handlers.
|
||||||
|
// Removed TLS slot limits from most implementations.
|
||||||
|
// 22 Mar 04 GlassfordM for WEKEMPF
|
||||||
|
// Fixed: thread_specific_ptr::reset() doesn't check error returned
|
||||||
|
// by tss::set(); tss::set() now throws if it fails.
|
||||||
|
// Fixed: calling thread_specific_ptr::reset() or
|
||||||
|
// thread_specific_ptr::release() causes double-delete: once on
|
||||||
|
// reset()/release() and once on ~thread_specific_ptr().
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2001
|
// Copyright (C) 2001-2003
|
||||||
// William E. Kempf
|
// William E. Kempf
|
||||||
//
|
//
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
// Permission to use, copy, modify, distribute and sell this software
|
||||||
@@ -9,6 +9,8 @@
|
|||||||
// about the suitability of this software for any purpose.
|
// about the suitability of this software for any purpose.
|
||||||
// It is provided "as is" without express or implied warranty.
|
// It is provided "as is" without express or implied warranty.
|
||||||
|
|
||||||
|
#include <boost/thread/detail/config.hpp>
|
||||||
|
|
||||||
#include <boost/thread/xtime.hpp>
|
#include <boost/thread/xtime.hpp>
|
||||||
|
|
||||||
#if defined(BOOST_HAS_FTIME)
|
#if defined(BOOST_HAS_FTIME)
|
||||||
@@ -33,29 +35,30 @@ struct startup_time_info
|
|||||||
{
|
{
|
||||||
startup_time_info()
|
startup_time_info()
|
||||||
{
|
{
|
||||||
// 1970 Jan 1 at 00:00:00
|
// 1970 Jan 1 at 00:00:00
|
||||||
static const DateTimeRec k_sUNIXBase = {1970, 1, 1, 0, 0, 0, 0};
|
static const DateTimeRec k_sUNIXBase = {1970, 1, 1, 0, 0, 0, 0};
|
||||||
static unsigned long s_ulUNIXBaseSeconds = 0UL;
|
static unsigned long s_ulUNIXBaseSeconds = 0UL;
|
||||||
|
|
||||||
if(s_ulUNIXBaseSeconds == 0UL)
|
if(s_ulUNIXBaseSeconds == 0UL)
|
||||||
{
|
{
|
||||||
// calculate the number of seconds between the Mac OS base and the UNIX base
|
// calculate the number of seconds between the Mac OS base and the
|
||||||
// the first time we enter this constructor.
|
// UNIX base the first time we enter this constructor.
|
||||||
DateToSeconds(&k_sUNIXBase, &s_ulUNIXBaseSeconds);
|
DateToSeconds(&k_sUNIXBase, &s_ulUNIXBaseSeconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long ulSeconds;
|
unsigned long ulSeconds;
|
||||||
|
|
||||||
// get the time in UpTime units twice, with the time in seconds in the middle.
|
// get the time in UpTime units twice, with the time in seconds in the
|
||||||
|
// middle.
|
||||||
uint64_t ullFirstUpTime = force_cast<uint64_t>(UpTime());
|
uint64_t ullFirstUpTime = force_cast<uint64_t>(UpTime());
|
||||||
GetDateTime(&ulSeconds);
|
GetDateTime(&ulSeconds);
|
||||||
uint64_t ullSecondUpTime = force_cast<uint64_t>(UpTime());
|
uint64_t ullSecondUpTime = force_cast<uint64_t>(UpTime());
|
||||||
|
|
||||||
// calculate the midpoint of the two UpTimes, and save that.
|
// calculate the midpoint of the two UpTimes, and save that.
|
||||||
uint64_t ullAverageUpTime = (ullFirstUpTime + ullSecondUpTime) / 2ULL;
|
uint64_t ullAverageUpTime = (ullFirstUpTime + ullSecondUpTime) / 2ULL;
|
||||||
m_sStartupAbsoluteTime = force_cast<AbsoluteTime>(ullAverageUpTime);
|
m_sStartupAbsoluteTime = force_cast<AbsoluteTime>(ullAverageUpTime);
|
||||||
|
|
||||||
// save the number of seconds, recentered at the UNIX base.
|
// save the number of seconds, recentered at the UNIX base.
|
||||||
m_ulStartupSeconds = ulSeconds - s_ulUNIXBaseSeconds;
|
m_ulStartupSeconds = ulSeconds - s_ulUNIXBaseSeconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,11 +79,22 @@ int xtime_get(struct xtime* xtp, int clock_type)
|
|||||||
{
|
{
|
||||||
#if defined(BOOST_HAS_FTIME)
|
#if defined(BOOST_HAS_FTIME)
|
||||||
FILETIME ft;
|
FILETIME ft;
|
||||||
|
# if defined(BOOST_NO_GETSYSTEMTIMEASFILETIME)
|
||||||
|
{
|
||||||
|
SYSTEMTIME st;
|
||||||
|
GetSystemTime(&st);
|
||||||
|
SystemTimeToFileTime(&st,&ft);
|
||||||
|
}
|
||||||
|
# else
|
||||||
GetSystemTimeAsFileTime(&ft);
|
GetSystemTimeAsFileTime(&ft);
|
||||||
const boost::uint64_t TIMESPEC_TO_FILETIME_OFFSET = ((boost::uint64_t)27111902UL << 32) + (boost::uint64_t)3577643008UL;
|
# endif
|
||||||
xtp->sec = (int)((*(__int64*)&ft - TIMESPEC_TO_FILETIME_OFFSET) / 10000000);
|
const boost::uint64_t TIMESPEC_TO_FILETIME_OFFSET =
|
||||||
|
((boost::uint64_t)27111902UL << 32) +
|
||||||
|
(boost::uint64_t)3577643008UL;
|
||||||
|
xtp->sec = (int)((*(__int64*)&ft - TIMESPEC_TO_FILETIME_OFFSET) /
|
||||||
|
10000000);
|
||||||
xtp->nsec = (int)((*(__int64*)&ft - TIMESPEC_TO_FILETIME_OFFSET -
|
xtp->nsec = (int)((*(__int64*)&ft - TIMESPEC_TO_FILETIME_OFFSET -
|
||||||
((__int64)xtp->sec * (__int64)10000000)) * 100);
|
((__int64)xtp->sec * (__int64)10000000)) * 100);
|
||||||
return clock_type;
|
return clock_type;
|
||||||
#elif defined(BOOST_HAS_GETTIMEOFDAY)
|
#elif defined(BOOST_HAS_GETTIMEOFDAY)
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
@@ -96,12 +110,16 @@ int xtime_get(struct xtime* xtp, int clock_type)
|
|||||||
return clock_type;
|
return clock_type;
|
||||||
#elif defined(BOOST_HAS_MPTASKS)
|
#elif defined(BOOST_HAS_MPTASKS)
|
||||||
using detail::thread::force_cast;
|
using detail::thread::force_cast;
|
||||||
// the Mac OS does not have an MP-safe way of getting the date/time, so we use a
|
// the Mac OS does not have an MP-safe way of getting the date/time,
|
||||||
// delta from the startup time. We _could_ defer this and use something that is
|
// so we use a delta from the startup time. We _could_ defer this
|
||||||
// interrupt-safe, but this would be _SLOW_, and we need speed here.
|
// 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);
|
const uint64_t k_ullNanosecondsPerSecond(1000ULL * 1000ULL * 1000ULL);
|
||||||
AbsoluteTime sUpTime(UpTime());
|
AbsoluteTime sUpTime(UpTime());
|
||||||
uint64_t ullNanoseconds(force_cast<uint64_t>(AbsoluteDeltaToNanoseconds(sUpTime, detail::g_sStartupTimeInfo.m_sStartupAbsoluteTime)));
|
uint64_t ullNanoseconds(
|
||||||
|
force_cast<uint64_t>(
|
||||||
|
AbsoluteDeltaToNanoseconds(sUpTime,
|
||||||
|
detail::g_sStartupTimeInfo.m_sStartupAbsoluteTime)));
|
||||||
uint64_t ullSeconds = (ullNanoseconds / k_ullNanosecondsPerSecond);
|
uint64_t ullSeconds = (ullNanoseconds / k_ullNanosecondsPerSecond);
|
||||||
ullNanoseconds -= (ullSeconds * k_ullNanosecondsPerSecond);
|
ullNanoseconds -= (ullSeconds * k_ullNanosecondsPerSecond);
|
||||||
xtp->sec = detail::g_sStartupTimeInfo.m_ulStartupSeconds + ullSeconds;
|
xtp->sec = detail::g_sStartupTimeInfo.m_ulStartupSeconds + ullSeconds;
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user