mirror of
https://github.com/boostorg/thread.git
synced 2026-02-03 09:42:16 +00:00
Compare commits
280 Commits
boost-1.34
...
svn-branch
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
28d5417cc9 | ||
|
|
0997fad8ec | ||
|
|
73715bd096 | ||
|
|
372ba84c40 | ||
|
|
6b562eab48 | ||
|
|
2f53e5d440 | ||
|
|
8fd0dd0cc0 | ||
|
|
8eea5811ba | ||
|
|
a154c2adab | ||
|
|
10bf4ed576 | ||
|
|
60d12dd395 | ||
|
|
b4e9be3c52 | ||
|
|
dcebae6d4a | ||
|
|
8749696538 | ||
|
|
0d776bcd26 | ||
|
|
2d6ed47cf2 | ||
|
|
9beea23f63 | ||
|
|
ea06434425 | ||
|
|
6508eff95e | ||
|
|
69930684a9 | ||
|
|
b1931a3eda | ||
|
|
63b44d4e32 | ||
|
|
f7cb8d8141 | ||
|
|
48c857e02c | ||
|
|
2978d43a5d | ||
|
|
a264766584 | ||
|
|
442dc58e0f | ||
|
|
25460c652c | ||
|
|
31a98f0a1e | ||
|
|
36c44b6f45 | ||
|
|
27426b18d1 | ||
|
|
3ea9ce1c8c | ||
|
|
f03a9bfcf3 | ||
|
|
4dfc636c84 | ||
|
|
5fe4312c6c | ||
|
|
63e675a6bb | ||
|
|
e92aeac7d7 | ||
|
|
f1f7eac1f2 | ||
|
|
eff0c84553 | ||
|
|
58c8ce61c7 | ||
|
|
6ac5e6953a | ||
|
|
5d9ad59af2 | ||
|
|
3c48a05437 | ||
|
|
4462124ff2 | ||
|
|
373f557ef7 | ||
|
|
495e561398 | ||
|
|
d24a579033 | ||
|
|
77130424b4 | ||
|
|
eb30688937 | ||
|
|
880bac0633 | ||
|
|
60fdcddcb5 | ||
|
|
851d6a987f | ||
|
|
9bebd7b35f | ||
|
|
309acb9597 | ||
|
|
a56887167e | ||
|
|
e984dff4e4 | ||
|
|
685e4d446b | ||
|
|
8af680f307 | ||
|
|
6c60cce60d | ||
|
|
5882a675bb | ||
|
|
a5e95845b3 | ||
|
|
5b83d81e40 | ||
|
|
c8e5ad564d | ||
|
|
5edfa273ff | ||
|
|
4db57bcb10 | ||
|
|
3f13340903 | ||
|
|
6abb53c9d3 | ||
|
|
fdd20a519e | ||
|
|
67cc49f333 | ||
|
|
31a34cd0b5 | ||
|
|
ef8c08ba99 | ||
|
|
2991ca6c6f | ||
|
|
52bace18b2 | ||
|
|
767d14ae4f | ||
|
|
1a5c911e36 | ||
|
|
6e42a04e43 | ||
|
|
28be2cfeef | ||
|
|
8be168fd87 | ||
|
|
eee95fef57 | ||
|
|
9ea179b052 | ||
|
|
6868280409 | ||
|
|
e00b764454 | ||
|
|
999613c686 | ||
|
|
c2661d7eb5 | ||
|
|
4d21dd1f47 | ||
|
|
a0a0e57527 | ||
|
|
d8af0d0b4e | ||
|
|
113288e3b0 | ||
|
|
afecfd7c2d | ||
|
|
94d89aac5f | ||
|
|
8831b13efc | ||
|
|
01f99da03a | ||
|
|
080654e3ef | ||
|
|
2ac2eb2a61 | ||
|
|
61b940b705 | ||
|
|
4a4f87e017 | ||
|
|
6d5e7f63a7 | ||
|
|
f77285f375 | ||
|
|
dc5d03a6dc | ||
|
|
ea0961b7f6 | ||
|
|
33d9f9774c | ||
|
|
86097fa038 | ||
|
|
70d9dbc45a | ||
|
|
3926fd3a20 | ||
|
|
7861cf1146 | ||
|
|
0516b86a6e | ||
|
|
ec735d3e9b | ||
|
|
1c5c070983 | ||
|
|
a5c02b73dc | ||
|
|
918b920670 | ||
|
|
de67d2e27e | ||
|
|
bc89df04cb | ||
|
|
c26a4cf082 | ||
|
|
6e1a866b13 | ||
|
|
f91986ad0d | ||
|
|
795cc23f3e | ||
|
|
a3695bd4a0 | ||
|
|
08dc521daf | ||
|
|
8b916d21b1 | ||
|
|
c40f47a78a | ||
|
|
e9fb470b06 | ||
|
|
343d049772 | ||
|
|
86f9480da4 | ||
|
|
8696b610ca | ||
|
|
6f13227eda | ||
|
|
525d190f91 | ||
|
|
58d5110e61 | ||
|
|
1e0154335b | ||
|
|
76e53c7bc5 | ||
|
|
413c29a5e4 | ||
|
|
30bb6143c1 | ||
|
|
cfb08be1a8 | ||
|
|
b5bbb7fb1c | ||
|
|
a76c33f8cc | ||
|
|
991ac727c6 | ||
|
|
810306b8f3 | ||
|
|
6c22bdb3bd | ||
|
|
569a78649f | ||
|
|
6a0d3e98bc | ||
|
|
7caec1ec33 | ||
|
|
7fd3fb48b1 | ||
|
|
3809321037 | ||
|
|
eef695bdf0 | ||
|
|
ab01ab1e4d | ||
|
|
a32a3b37db | ||
|
|
c8d8a108a7 | ||
|
|
7afd9efcc5 | ||
|
|
56ded87ad2 | ||
|
|
82e503339b | ||
|
|
713d0c7ace | ||
|
|
25ad6e3f8f | ||
|
|
df0197b617 | ||
|
|
a89c4f01ad | ||
|
|
ae67099633 | ||
|
|
57542d3a5c | ||
|
|
9a1da14116 | ||
|
|
ed050d753d | ||
|
|
8bec363710 | ||
|
|
7c68e190a9 | ||
|
|
7ebf5ea3d1 | ||
|
|
11e0435a4b | ||
|
|
d15ee57cd1 | ||
|
|
56d660b7fd | ||
|
|
792958e693 | ||
|
|
914e67dc04 | ||
|
|
b50a7ccb61 | ||
|
|
f827709d42 | ||
|
|
36abb42175 | ||
|
|
40f3b1b4c8 | ||
|
|
4f35e25688 | ||
|
|
270e88edd7 | ||
|
|
5ded171247 | ||
|
|
88f6076f3c | ||
|
|
b4d12e08dd | ||
|
|
332dd988e4 | ||
|
|
bce8db41d7 | ||
|
|
f6fd70245d | ||
|
|
4ff0a055d6 | ||
|
|
c9140267a5 | ||
|
|
72fcee4e5e | ||
|
|
9c8e512edd | ||
|
|
3c191af34a | ||
|
|
5e0b2d7370 | ||
|
|
5994abd453 | ||
|
|
67a2d119c0 | ||
|
|
114215088a | ||
|
|
a78e2b793e | ||
|
|
519ed3834e | ||
|
|
22647135fa | ||
|
|
58c741e9ca | ||
|
|
ef9083089e | ||
|
|
5de1582a0a | ||
|
|
39c864e31f | ||
|
|
320cb63df4 | ||
|
|
c246222ded | ||
|
|
b7edb2873c | ||
|
|
89f2032c0d | ||
|
|
d2f8230093 | ||
|
|
9f6b5d169a | ||
|
|
e56708d4aa | ||
|
|
304156c20e | ||
|
|
31e1566e1d | ||
|
|
3908637056 | ||
|
|
abee301f3d | ||
|
|
9b1d3f8f3c | ||
|
|
3513eaf701 | ||
|
|
08a840afe4 | ||
|
|
370f5d461c | ||
|
|
8efc8458e1 | ||
|
|
6485717c52 | ||
|
|
1d5bbd11a8 | ||
|
|
bc403742b5 | ||
|
|
c7f963f57e | ||
|
|
afb6684bde | ||
|
|
ee3d772235 | ||
|
|
1af08f7085 | ||
|
|
ccf23fa273 | ||
|
|
f701defc5f | ||
|
|
c606f05bf8 | ||
|
|
a646153615 | ||
|
|
60380afe15 | ||
|
|
d4b0a977c9 | ||
|
|
f86156ad10 | ||
|
|
1836ee854f | ||
|
|
c37cdeec9f | ||
|
|
b0b2b17908 | ||
|
|
bf46b2ee96 | ||
|
|
2918732481 | ||
|
|
bfaeda36c7 | ||
|
|
5a4d5ddb9d | ||
|
|
55afcf678d | ||
|
|
16c7cf9b5e | ||
|
|
432bd29c1c | ||
|
|
a87914ef23 | ||
|
|
041530a953 | ||
|
|
9d4c55161a | ||
|
|
a706d1df00 | ||
|
|
b15b2e666f | ||
|
|
5d4678364e | ||
|
|
ffe0e489d9 | ||
|
|
1c0f470032 | ||
|
|
9590526430 | ||
|
|
1c6dfda83c | ||
|
|
a8be12940e | ||
|
|
4b5046366b | ||
|
|
a0fff90c26 | ||
|
|
4c165ab173 | ||
|
|
a8daedac5e | ||
|
|
5fa26fb3ac | ||
|
|
ea3e297175 | ||
|
|
92b8789532 | ||
|
|
8f61694057 | ||
|
|
67f7de5305 | ||
|
|
6faecefb73 | ||
|
|
a11bd6ebd9 | ||
|
|
9889bf50a2 | ||
|
|
d75fb2deda | ||
|
|
6355a5b28d | ||
|
|
595bbee41e | ||
|
|
cb3f3a1f64 | ||
|
|
0e44838905 | ||
|
|
64cd268fc7 | ||
|
|
f048dd81f2 | ||
|
|
5746f2214c | ||
|
|
099af669d4 | ||
|
|
79cac706a7 | ||
|
|
df229074ac | ||
|
|
191c27e856 | ||
|
|
e5ee01b43c | ||
|
|
c46b040f6f | ||
|
|
72e4794f5b | ||
|
|
c30b65a0ea | ||
|
|
1cb08ff60c | ||
|
|
d3d7fd9317 | ||
|
|
acf0f97663 | ||
|
|
34bd87cea7 | ||
|
|
228f11262e | ||
|
|
9683e0f1cc | ||
|
|
674ae6d571 | ||
|
|
690d44e2e6 |
227
build/Jamfile.v2
227
build/Jamfile.v2
@@ -1,39 +1,208 @@
|
||||
# (C) Copyright Vladimir Prus, David Abrahams, Michael Stevens, Hartmut Kaiser,
|
||||
# William E Kempf 2002-2006
|
||||
# Use, modification and distribution are subject to the
|
||||
# Boost Software License, Version 1.0. (See accompanying file
|
||||
# LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
# $Id$
|
||||
# Copyright 2006-2007 Roland Schwarz.
|
||||
# Copyright 2007 Anthony Williams
|
||||
# Distributed under the Boost Software License, Version 1.0. (See
|
||||
# accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#########################################################################
|
||||
# The boost threading library can be built on top of different API's
|
||||
# Currently this is the win32 API and the pthreads API.
|
||||
# Pthread is native on unix variants.
|
||||
# To get pthread on windows you need the pthread win32 library
|
||||
# http://sourceware.org/pthreads-win32 which is available under LGPL.
|
||||
#
|
||||
# You need to provide the include path and lib path in the variables
|
||||
# PTW32_INCLUDE and PTW32_LIB respectively. You can specify these
|
||||
# paths in site-config.jam, user-config.jam or in the environment.
|
||||
# A new feature is provided to request a specific API:
|
||||
# <threadapi>win32 and <threadapi)pthread.
|
||||
#
|
||||
# The naming of the resulting libraries is mostly the same for the
|
||||
# variant native to the build platform, i.e.
|
||||
# boost_thread and the boost specific tagging.
|
||||
# For the library variant that is not native on the build platform
|
||||
# an additional tag is applied:
|
||||
# boost_thread_pthread for the pthread variant on windows, and
|
||||
# boost_thread_win32 for the win32 variant (likely when built on cygwin).
|
||||
#
|
||||
# To request the pthread variant on windows, from boost root you would
|
||||
# say e.g:
|
||||
# bjam msvc-8.0 --with-thread install threadapi=pthread
|
||||
#########################################################################
|
||||
|
||||
import os ;
|
||||
|
||||
import feature ;
|
||||
import indirect ;
|
||||
import path ;
|
||||
|
||||
project boost/thread
|
||||
: source-location ../src
|
||||
: requirements <link>shared:<define>BOOST_THREAD_BUILD_DLL=1 <threading>multi
|
||||
: source-location ../src
|
||||
: requirements <threading>multi
|
||||
<link>static:<define>BOOST_THREAD_BUILD_LIB=1
|
||||
<link>shared:<define>BOOST_THREAD_BUILD_DLL=1
|
||||
-<tag>@$(BOOST_JAMROOT_MODULE)%$(BOOST_JAMROOT_MODULE).tag
|
||||
<tag>@$(__name__).tag
|
||||
: default-build <threading>multi
|
||||
;
|
||||
|
||||
CPP_SOURCES =
|
||||
barrier
|
||||
condition
|
||||
exceptions
|
||||
mutex
|
||||
once
|
||||
recursive_mutex
|
||||
# read_write_mutex
|
||||
thread
|
||||
tss_hooks
|
||||
tss_dll
|
||||
tss_pe
|
||||
tss
|
||||
xtime
|
||||
local rule default_threadapi ( )
|
||||
{
|
||||
local api = pthread ;
|
||||
if [ os.name ] = "NT" { api = win32 ; }
|
||||
return $(api) ;
|
||||
}
|
||||
|
||||
feature.feature threadapi : pthread win32 : propagated ;
|
||||
feature.set-default threadapi : [ default_threadapi ] ;
|
||||
|
||||
rule tag ( name : type ? : property-set )
|
||||
{
|
||||
local result = $(name) ;
|
||||
|
||||
if $(type) in STATIC_LIB SHARED_LIB IMPORT_LIB
|
||||
{
|
||||
local api = [ $(property-set).get <threadapi> ] ;
|
||||
|
||||
# non native api gets additional tag
|
||||
if $(api) != [ default_threadapi ] {
|
||||
result = $(result)_$(api) ;
|
||||
}
|
||||
}
|
||||
|
||||
# forward to the boost tagging rule
|
||||
return [ indirect.call $(BOOST_JAMROOT_MODULE)%$(BOOST_JAMROOT_MODULE).tag
|
||||
$(result) : $(type) : $(property-set) ] ;
|
||||
}
|
||||
|
||||
rule win32_pthread_paths ( properties * )
|
||||
{
|
||||
local result ;
|
||||
local PTW32_INCLUDE ;
|
||||
local PTW32_LIB ;
|
||||
PTW32_INCLUDE = [ modules.peek : PTW32_INCLUDE ] ;
|
||||
PTW32_LIB = [ modules.peek : PTW32_LIB ] ;
|
||||
PTW32_INCLUDE ?= [ modules.peek user-config : PTW32_INCLUDE ] ;
|
||||
PTW32_LIB ?= [ modules.peek user-config : PTW32_LIB ] ;
|
||||
PTW32_INCLUDE ?= [ modules.peek site-config : PTW32_INCLUDE ] ;
|
||||
PTW32_LIB ?= [ modules.peek site-config : PTW32_LIB ] ;
|
||||
|
||||
if ! ( $(PTW32_INCLUDE) && $(PTW32_LIB) )
|
||||
{
|
||||
if ! $(.notified)
|
||||
{
|
||||
echo "************************************************************" ;
|
||||
echo "Trying to build Boost.Thread with pthread support." ;
|
||||
echo "If you need pthread you should specify the paths." ;
|
||||
echo "You can specify them in site-config.jam, user-config.jam" ;
|
||||
echo "or in the environment." ;
|
||||
echo "For example:" ;
|
||||
echo "PTW32_INCLUDE=C:\\Program Files\\ptw32\\Pre-built2\\include" ;
|
||||
echo "PTW32_LIB=C:\\Program Files\\ptw32\\Pre-built2\\lib" ;
|
||||
echo "************************************************************" ;
|
||||
.notified = true ;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
local include_path = [ path.make $(PTW32_INCLUDE) ] ;
|
||||
local lib_path = [ path.make $(PTW32_LIB) ] ;
|
||||
local libname = pthread ;
|
||||
if <toolset>msvc in $(properties)
|
||||
{
|
||||
libname = $(libname)VC2.lib ;
|
||||
}
|
||||
if <toolset>gcc in $(properties)
|
||||
{
|
||||
libname = lib$(libname)GC2.a ;
|
||||
}
|
||||
lib_path = [ path.glob $(lib_path) : $(libname) ] ;
|
||||
if ! $(lib_path)
|
||||
{
|
||||
if ! $(.notified)
|
||||
{
|
||||
echo "************************************************************" ;
|
||||
echo "Trying to build Boost.Thread with pthread support." ;
|
||||
echo "But the library" $(libname) "could not be found in path" ;
|
||||
echo $(PTW32_LIB) ;
|
||||
echo "************************************************************" ;
|
||||
.notified = true ;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result += <include>$(include_path) ;
|
||||
result += <library>$(lib_path) ;
|
||||
}
|
||||
}
|
||||
return $(result) ;
|
||||
}
|
||||
|
||||
rule usage-requirements ( properties * )
|
||||
{
|
||||
local result ;
|
||||
if <threadapi>pthread in $(properties)
|
||||
{
|
||||
result += <define>BOOST_THREAD_POSIX ;
|
||||
if <target-os>windows in $(properties)
|
||||
{
|
||||
result += [ win32_pthread_paths $(properties) ] ;
|
||||
# TODO: What is for static linking? Is the <library> also needed
|
||||
# in that case?
|
||||
}
|
||||
}
|
||||
return $(result) ;
|
||||
}
|
||||
|
||||
rule requirements ( properties * )
|
||||
{
|
||||
local result ;
|
||||
|
||||
if <threadapi>pthread in $(properties)
|
||||
{
|
||||
result += <define>BOOST_THREAD_POSIX ;
|
||||
if <target-os>windows in $(properties)
|
||||
{
|
||||
local paths = [ win32_pthread_paths $(properties) ] ;
|
||||
if $(paths)
|
||||
{
|
||||
result += $(paths) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = <build>no ;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $(result) ;
|
||||
}
|
||||
|
||||
alias thread_sources
|
||||
: ## win32 sources ##
|
||||
win32/thread.cpp
|
||||
win32/exceptions.cpp
|
||||
win32/tss_dll.cpp
|
||||
win32/tss_pe.cpp
|
||||
: ## requirements ##
|
||||
<threadapi>win32
|
||||
;
|
||||
|
||||
alias thread_sources
|
||||
: ## pthread sources ##
|
||||
pthread/thread.cpp
|
||||
pthread/exceptions.cpp
|
||||
pthread/once.cpp
|
||||
: ## requirements ##
|
||||
<threadapi>pthread
|
||||
;
|
||||
|
||||
explicit thread_sources ;
|
||||
|
||||
lib boost_thread
|
||||
: $(CPP_SOURCES).cpp
|
||||
: <link>shared:<define>BOOST_THREAD_BUILD_DLL=1
|
||||
<link>static:<define>BOOST_THREAD_BUILD_LIB=1
|
||||
: # default build
|
||||
: <link>shared:<define>BOOST_THREAD_BUILD_DLL=1
|
||||
<link>static:<define>BOOST_THREAD_BUILD_LIB=1
|
||||
;
|
||||
: thread_sources
|
||||
: <conditional>@requirements
|
||||
:
|
||||
: <link>shared:<define>BOOST_THREAD_USE_DLL=1
|
||||
<link>static:<define>BOOST_THREAD_USE_LIB=1
|
||||
<conditional>@usage-requirements
|
||||
;
|
||||
|
||||
@@ -1,11 +1,55 @@
|
||||
# Copyright (C) 2001-2003
|
||||
# William E. Kempf
|
||||
# (C) Copyright 2008 Anthony Williams
|
||||
#
|
||||
# Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
import toolset ;
|
||||
toolset.using doxygen ;
|
||||
path-constant boost-images : ../../../doc/src/images ;
|
||||
|
||||
boostbook thread : thread.xml ;
|
||||
xml thread : thread.qbk ;
|
||||
|
||||
boostbook standalone
|
||||
:
|
||||
thread
|
||||
:
|
||||
# HTML options first:
|
||||
# Use graphics not text for navigation:
|
||||
<xsl:param>navig.graphics=1
|
||||
# How far down we chunk nested sections, basically all of them:
|
||||
<xsl:param>chunk.section.depth=3
|
||||
# Don't put the first section on the same page as the TOC:
|
||||
<xsl:param>chunk.first.sections=1
|
||||
# How far down sections get TOC's
|
||||
<xsl:param>toc.section.depth=10
|
||||
# Max depth in each TOC:
|
||||
<xsl:param>toc.max.depth=3
|
||||
# How far down we go with TOC's
|
||||
<xsl:param>generate.section.toc.level=10
|
||||
# Path for links to Boost:
|
||||
<xsl:param>boost.root=../../../..
|
||||
# Path for libraries index:
|
||||
<xsl:param>boost.libraries=../../../../libs/libraries.htm
|
||||
# Use the main Boost stylesheet:
|
||||
<xsl:param>html.stylesheet=../../../../doc/html/boostbook.css
|
||||
|
||||
# PDF Options:
|
||||
# TOC Generation: this is needed for FOP-0.9 and later:
|
||||
#<xsl:param>fop1.extensions=1
|
||||
# Or enable this if you're using XEP:
|
||||
<xsl:param>xep.extensions=1
|
||||
# TOC generation: this is needed for FOP 0.2, but must not be set to zero for FOP-0.9!
|
||||
<xsl:param>fop.extensions=0
|
||||
# No indent on body text:
|
||||
<xsl:param>body.start.indent=0pt
|
||||
# Margin size:
|
||||
<xsl:param>page.margin.inner=0.5in
|
||||
# Margin size:
|
||||
<xsl:param>page.margin.outer=0.5in
|
||||
# Yes, we want graphics for admonishments:
|
||||
<xsl:param>admon.graphics=1
|
||||
# Set this one for PDF generation *only*:
|
||||
# default pnd graphics are awful in PDF form,
|
||||
# better use SVG's instead:
|
||||
<format>pdf:<xsl:param>admon.graphics.extension=".svg"
|
||||
<format>pdf:<xsl:param>admon.graphics.path=$(boost-images)/
|
||||
;
|
||||
|
||||
|
||||
23
doc/acknowledgements.qbk
Normal file
23
doc/acknowledgements.qbk
Normal file
@@ -0,0 +1,23 @@
|
||||
[/
|
||||
(C) Copyright 2007-8 Anthony Williams.
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
]
|
||||
|
||||
[section:acknowledgements Acknowledgments]
|
||||
|
||||
The original implementation of __boost_thread__ was written by William Kempf, with contributions from numerous others. This new
|
||||
version initially grew out of an attempt to rewrite __boost_thread__ to William Kempf's design with fresh code that could be
|
||||
released under the Boost Software License. However, as the C++ Standards committee have been actively discussing standardizing a
|
||||
thread library for C++, this library has evolved to reflect the proposals, whilst retaining as much backwards-compatibility as
|
||||
possible.
|
||||
|
||||
Particular thanks must be given to Roland Schwarz, who contributed a lot of time and code to the original __boost_thread__ library,
|
||||
and who has been actively involved with the rewrite. The scheme for dividing the platform-specific implementations into separate
|
||||
directories was devised by Roland, and his input has contributed greatly to improving the quality of the current implementation.
|
||||
|
||||
Thanks also must go to Peter Dimov, Howard Hinnant, Alexander Terekhov, Chris Thomasson and others for their comments on the
|
||||
implementation details of the code.
|
||||
|
||||
[endsect]
|
||||
72
doc/barrier.qbk
Normal file
72
doc/barrier.qbk
Normal file
@@ -0,0 +1,72 @@
|
||||
[/
|
||||
(C) Copyright 2007-8 Anthony Williams.
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
]
|
||||
|
||||
[section:barriers Barriers]
|
||||
|
||||
A barrier is a simple concept. Also known as a ['rendezvous], it is a synchronization point between multiple threads. The barrier is
|
||||
configured for a particular number of threads (`n`), and as threads reach the barrier they must wait until all `n` threads have
|
||||
arrived. Once the `n`-th thread has reached the barrier, all the waiting threads can proceed, and the barrier is reset.
|
||||
|
||||
[section:barrier Class `barrier`]
|
||||
|
||||
#include <boost/thread/barrier.hpp>
|
||||
|
||||
class barrier
|
||||
{
|
||||
public:
|
||||
barrier(unsigned int count);
|
||||
~barrier();
|
||||
|
||||
bool wait();
|
||||
};
|
||||
|
||||
Instances of __barrier__ are not copyable or movable.
|
||||
|
||||
[heading Constructor]
|
||||
|
||||
barrier(unsigned int count);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Construct a barrier for `count` threads.]]
|
||||
|
||||
[[Throws:] [__thread_resource_error__ if an error occurs.]]
|
||||
|
||||
]
|
||||
|
||||
[heading Destructor]
|
||||
|
||||
~barrier();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Precondition:] [No threads are waiting on `*this`.]]
|
||||
|
||||
[[Effects:] [Destroys `*this`.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[heading Member function `wait`]
|
||||
|
||||
bool wait();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Block until `count` threads have called `wait` on `*this`. When the `count`-th thread calls `wait`, all waiting threads
|
||||
are unblocked, and the barrier is reset. ]]
|
||||
|
||||
[[Returns:] [`true` for exactly one thread from each batch of waiting threads, `false` otherwise.]]
|
||||
|
||||
[[Throws:] [__thread_resource_error__ if an error occurs.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
83
doc/changes.qbk
Normal file
83
doc/changes.qbk
Normal file
@@ -0,0 +1,83 @@
|
||||
[/
|
||||
(C) Copyright 2007-8 Anthony Williams.
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
]
|
||||
|
||||
[section:changes Changes since boost 1.35]
|
||||
|
||||
The 1.36.0 release of Boost includes a few new features in the thread library:
|
||||
|
||||
* New generic __lock_multiple_ref__ and __try_lock_multiple_ref__ functions for locking multiple mutexes at once.
|
||||
|
||||
* Rvalue reference support for move semantics where the compilers supports it.
|
||||
|
||||
* A few bugs fixed and missing functions added (including the serious win32 condition variable bug).
|
||||
|
||||
* `scoped_try_lock` types are now backwards-compatible with Boost 1.34.0 and previous releases.
|
||||
|
||||
* Support for passing function arguments to the thread function by supplying additional arguments to the __thread__ constructor.
|
||||
|
||||
* Backwards-compatibility overloads added for `timed_lock` and `timed_wait` functions to allow use of `xtime` for timeouts.
|
||||
|
||||
[heading Changes since boost 1.34]
|
||||
|
||||
Almost every line of code in __boost_thread__ has been changed since the 1.34 release of boost. However, most of the interface
|
||||
changes have been extensions, so the new code is largely backwards-compatible with the old code. The new features and breaking
|
||||
changes are described below.
|
||||
|
||||
[heading New Features]
|
||||
|
||||
* Instances of __thread__ and of the various lock types are now movable.
|
||||
|
||||
* Threads can be interrupted at __interruption_points__.
|
||||
|
||||
* Condition variables can now be used with any type that implements the __lockable_concept__, through the use of
|
||||
`boost::condition_variable_any` (`boost::condition` is a `typedef` to `boost::condition_variable_any`, provided for backwards
|
||||
compatibility). `boost::condition_variable` is provided as an optimization, and will only work with
|
||||
`boost::unique_lock<boost::mutex>` (`boost::mutex::scoped_lock`).
|
||||
|
||||
* Thread IDs are separated from __thread__, so a thread can obtain it's own ID (using `boost::this_thread::get_id()`), and IDs can
|
||||
be used as keys in associative containers, as they have the full set of comparison operators.
|
||||
|
||||
* Timeouts are now implemented using the Boost DateTime library, through a typedef `boost::system_time` for absolute timeouts, and
|
||||
with support for relative timeouts in many cases. `boost::xtime` is supported for backwards compatibility only.
|
||||
|
||||
* Locks are implemented as publicly accessible templates `boost::lock_guard`, `boost::unique_lock`, `boost::shared_lock`, and
|
||||
`boost::upgrade_lock`, which are templated on the type of the mutex. The __lockable_concept__ has been extended to include publicly
|
||||
available __lock_ref__ and __unlock_ref__ member functions, which are used by the lock types.
|
||||
|
||||
[heading Breaking Changes]
|
||||
|
||||
The list below should cover all changes to the public interface which break backwards compatibility.
|
||||
|
||||
* __try_mutex__ has been removed, and the functionality subsumed into __mutex__. __try_mutex__ is left as a `typedef`,
|
||||
but is no longer a separate class.
|
||||
|
||||
* __recursive_try_mutex__ has been removed, and the functionality subsumed into
|
||||
__recursive_mutex__. __recursive_try_mutex__ is left as a `typedef`, but is no longer a separate class.
|
||||
|
||||
* `boost::detail::thread::lock_ops` has been removed. Code that relies on the `lock_ops` implementation detail will no longer work,
|
||||
as this has been removed, as it is no longer necessary now that mutex types now have public __lock_ref__ and __unlock_ref__ member
|
||||
functions.
|
||||
|
||||
* `scoped_lock` constructors with a second parameter of type `bool` are no longer provided. With previous boost releases,
|
||||
``boost::mutex::scoped_lock some_lock(some_mutex,false);`` could be used to create a lock object that was associated with a mutex,
|
||||
but did not lock it on construction. This facility has now been replaced with the constructor that takes a
|
||||
`boost::defer_lock_type` as the second parameter: ``boost::mutex::scoped_lock some_lock(some_mutex,boost::defer_lock);``
|
||||
|
||||
* The `locked()` member function of the `scoped_lock` types has been renamed to __owns_lock_ref__.
|
||||
|
||||
* You can no longer obtain a __thread__ instance representing the current thread: a default-constructed __thread__ object is not
|
||||
associated with any thread. The only use for such a thread object was to support the comparison operators: this functionality has
|
||||
been moved to __thread_id__.
|
||||
|
||||
* The broken `boost::read_write_mutex` has been replaced with __shared_mutex__.
|
||||
|
||||
* __mutex__ is now never recursive. For Boost releases prior to 1.35 __mutex__ was recursive on Windows and not on POSIX platforms.
|
||||
|
||||
* When using a __recursive_mutex__ with a call to [cond_any_wait_link `boost::condition_variable_any::wait()`], the mutex is only
|
||||
unlocked one level, and not completely. This prior behaviour was not guaranteed and did not feature in the tests.
|
||||
|
||||
[endsect]
|
||||
513
doc/condition_variables.qbk
Normal file
513
doc/condition_variables.qbk
Normal file
@@ -0,0 +1,513 @@
|
||||
[/
|
||||
(C) Copyright 2007-8 Anthony Williams.
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
]
|
||||
|
||||
[section:condvar_ref Condition Variables]
|
||||
|
||||
[heading Synopsis]
|
||||
|
||||
The classes `condition_variable` and `condition_variable_any` provide a
|
||||
mechanism for one thread to wait for notification from another thread that a
|
||||
particular condition has become true. The general usage pattern is that one
|
||||
thread locks a mutex and then calls `wait` on an instance of
|
||||
`condition_variable` or `condition_variable_any`. When the thread is woken from
|
||||
the wait, then it checks to see if the appropriate condition is now true, and
|
||||
continues if so. If the condition is not true, then the thread then calls `wait`
|
||||
again to resume waiting. In the simplest case, this condition is just a boolean
|
||||
variable:
|
||||
|
||||
boost::condition_variable cond;
|
||||
boost::mutex mut;
|
||||
bool data_ready;
|
||||
|
||||
void process_data();
|
||||
|
||||
void wait_for_data_to_process()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lock(mut);
|
||||
while(!data_ready)
|
||||
{
|
||||
cond.wait(lock);
|
||||
}
|
||||
process_data();
|
||||
}
|
||||
|
||||
Notice that the `lock` is passed to `wait`: `wait` will atomically add the
|
||||
thread to the set of threads waiting on the condition variable, and unlock the
|
||||
mutex. When the thread is woken, the mutex will be locked again before the call
|
||||
to `wait` returns. This allows other threads to acquire the mutex in order to
|
||||
update the shared data, and ensures that the data associated with the condition
|
||||
is correctly synchronized.
|
||||
|
||||
In the mean time, another thread sets the condition to `true`, and then calls
|
||||
either `notify_one` or `notify_all` on the condition variable to wake one
|
||||
waiting thread or all the waiting threads respectively.
|
||||
|
||||
void retrieve_data();
|
||||
void prepare_data();
|
||||
|
||||
void prepare_data_for_processing()
|
||||
{
|
||||
retrieve_data();
|
||||
prepare_data();
|
||||
{
|
||||
boost::lock_guard<boost::mutex> lock(mut);
|
||||
data_ready=true;
|
||||
}
|
||||
cond.notify_one();
|
||||
}
|
||||
|
||||
Note that the same mutex is locked before the shared data is updated, but that
|
||||
the mutex does not have to be locked across the call to `notify_one`.
|
||||
|
||||
This example uses an object of type `condition_variable`, but would work just as
|
||||
well with an object of type `condition_variable_any`: `condition_variable_any`
|
||||
is more general, and will work with any kind of lock or mutex, whereas
|
||||
`condition_variable` requires that the lock passed to `wait` is an instance of
|
||||
`boost::unique_lock<boost::mutex>`. This enables `condition_variable` to make
|
||||
optimizations in some cases, based on the knowledge of the mutex type;
|
||||
`condition_variable_any` typically has a more complex implementation than
|
||||
`condition_variable`.
|
||||
|
||||
[section:condition_variable Class `condition_variable`]
|
||||
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
class condition_variable
|
||||
{
|
||||
public:
|
||||
condition_variable();
|
||||
~condition_variable();
|
||||
|
||||
void notify_one();
|
||||
void notify_all();
|
||||
|
||||
void wait(boost::unique_lock<boost::mutex>& lock);
|
||||
|
||||
template<typename predicate_type>
|
||||
void wait(boost::unique_lock<boost::mutex>& lock,predicate_type predicate);
|
||||
|
||||
bool timed_wait(boost::unique_lock<boost::mutex>& lock,boost::system_time const& abs_time);
|
||||
|
||||
template<typename duration_type>
|
||||
bool timed_wait(boost::unique_lock<boost::mutex>& lock,duration_type const& rel_time);
|
||||
|
||||
template<typename predicate_type>
|
||||
bool timed_wait(boost::unique_lock<boost::mutex>& lock,boost::system_time const& abs_time,predicate_type predicate);
|
||||
|
||||
template<typename duration_type,typename predicate_type>
|
||||
bool timed_wait(boost::unique_lock<boost::mutex>& lock,duration_type const& rel_time,predicate_type predicate);
|
||||
|
||||
// backwards compatibility
|
||||
|
||||
bool timed_wait(boost::unique_lock<boost::mutex>& lock,boost::xtime const& abs_time);
|
||||
|
||||
template<typename predicate_type>
|
||||
bool timed_wait(boost::unique_lock<boost::mutex>& lock,boost::xtime const& abs_time,predicate_type predicate);
|
||||
};
|
||||
}
|
||||
|
||||
[section:constructor `condition_variable()`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Constructs an object of class `condition_variable`.]]
|
||||
|
||||
[[Throws:] [__thread_resource_error__ if an error occurs.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:destructor `~condition_variable()`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Precondition:] [All threads waiting on `*this` have been notified by a call to
|
||||
`notify_one` or `notify_all` (though the respective calls to `wait` or
|
||||
`timed_wait` need not have returned).]]
|
||||
|
||||
[[Effects:] [Destroys the object.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:notify_one `void notify_one()`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [If any threads are currently __blocked__ waiting on `*this` in a call
|
||||
to `wait` or `timed_wait`, unblocks one of those threads.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:notify_all `void notify_all()`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [If any threads are currently __blocked__ waiting on `*this` in a call
|
||||
to `wait` or `timed_wait`, unblocks all of those threads.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:wait `void wait(boost::unique_lock<boost::mutex>& lock)`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Precondition:] [`lock` is locked by the current thread, and either no other
|
||||
thread is currently waiting on `*this`, or the execution of the `mutex()` member
|
||||
function on the `lock` objects supplied in the calls to `wait` or `timed_wait`
|
||||
in all the threads currently waiting on `*this` would return the same value as
|
||||
`lock->mutex()` for this call to `wait`.]]
|
||||
|
||||
[[Effects:] [Atomically call `lock.unlock()` and blocks the current thread. The
|
||||
thread will unblock when notified by a call to `this->notify_one()` or
|
||||
`this->notify_all()`, or spuriously. When the thread is unblocked (for whatever
|
||||
reason), the lock is reacquired by invoking `lock.lock()` before the call to
|
||||
`wait` returns. The lock is also reacquired by invoking `lock.lock()` if the
|
||||
function exits with an exception.]]
|
||||
|
||||
[[Postcondition:] [`lock` is locked by the current thread.]]
|
||||
|
||||
[[Throws:] [__thread_resource_error__ if an error
|
||||
occurs. __thread_interrupted__ if the wait was interrupted by a call to
|
||||
__interrupt__ on the __thread__ object associated with the current thread of execution.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:wait_predicate `template<typename predicate_type> void wait(boost::unique_lock<boost::mutex>& lock, predicate_type pred)`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [As-if ``
|
||||
while(!pred())
|
||||
{
|
||||
wait(lock);
|
||||
}
|
||||
``]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:timed_wait `bool timed_wait(boost::unique_lock<boost::mutex>& lock,boost::system_time const& abs_time)`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Precondition:] [`lock` is locked by the current thread, and either no other
|
||||
thread is currently waiting on `*this`, or the execution of the `mutex()` member
|
||||
function on the `lock` objects supplied in the calls to `wait` or `timed_wait`
|
||||
in all the threads currently waiting on `*this` would return the same value as
|
||||
`lock->mutex()` for this call to `wait`.]]
|
||||
|
||||
[[Effects:] [Atomically call `lock.unlock()` and blocks the current thread. The
|
||||
thread will unblock when notified by a call to `this->notify_one()` or
|
||||
`this->notify_all()`, when the time as reported by `boost::get_system_time()`
|
||||
would be equal to or later than the specified `abs_time`, or spuriously. When
|
||||
the thread is unblocked (for whatever reason), the lock is reacquired by
|
||||
invoking `lock.lock()` before the call to `wait` returns. The lock is also
|
||||
reacquired by invoking `lock.lock()` if the function exits with an exception.]]
|
||||
|
||||
[[Returns:] [`false` if the call is returning because the time specified by
|
||||
`abs_time` was reached, `true` otherwise.]]
|
||||
|
||||
[[Postcondition:] [`lock` is locked by the current thread.]]
|
||||
|
||||
[[Throws:] [__thread_resource_error__ if an error
|
||||
occurs. __thread_interrupted__ if the wait was interrupted by a call to
|
||||
__interrupt__ on the __thread__ object associated with the current thread of execution.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:timed_wait_rel `template<typename duration_type> bool timed_wait(boost::unique_lock<boost::mutex>& lock,duration_type const& rel_time)`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Precondition:] [`lock` is locked by the current thread, and either no other
|
||||
thread is currently waiting on `*this`, or the execution of the `mutex()` member
|
||||
function on the `lock` objects supplied in the calls to `wait` or `timed_wait`
|
||||
in all the threads currently waiting on `*this` would return the same value as
|
||||
`lock->mutex()` for this call to `wait`.]]
|
||||
|
||||
[[Effects:] [Atomically call `lock.unlock()` and blocks the current thread. The
|
||||
thread will unblock when notified by a call to `this->notify_one()` or
|
||||
`this->notify_all()`, after the period of time indicated by the `rel_time`
|
||||
argument has elapsed, or spuriously. When the thread is unblocked (for whatever
|
||||
reason), the lock is reacquired by invoking `lock.lock()` before the call to
|
||||
`wait` returns. The lock is also reacquired by invoking `lock.lock()` if the
|
||||
function exits with an exception.]]
|
||||
|
||||
[[Returns:] [`false` if the call is returning because the time period specified
|
||||
by `rel_time` has elapsed, `true` otherwise.]]
|
||||
|
||||
[[Postcondition:] [`lock` is locked by the current thread.]]
|
||||
|
||||
[[Throws:] [__thread_resource_error__ if an error
|
||||
occurs. __thread_interrupted__ if the wait was interrupted by a call to
|
||||
__interrupt__ on the __thread__ object associated with the current thread of execution.]]
|
||||
|
||||
]
|
||||
|
||||
[note The duration overload of timed_wait is difficult to use correctly. The overload taking a predicate should be preferred in most cases.]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:timed_wait_predicate `template<typename predicate_type> bool timed_wait(boost::unique_lock<boost::mutex>& lock, boost::system_time const& abs_time, predicate_type pred)`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [As-if ``
|
||||
while(!pred())
|
||||
{
|
||||
if(!timed_wait(lock,abs_time))
|
||||
{
|
||||
return pred();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
``]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:condition_variable_any Class `condition_variable_any`]
|
||||
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
class condition_variable_any
|
||||
{
|
||||
public:
|
||||
condition_variable_any();
|
||||
~condition_variable_any();
|
||||
|
||||
void notify_one();
|
||||
void notify_all();
|
||||
|
||||
template<typename lock_type>
|
||||
void wait(lock_type& lock);
|
||||
|
||||
template<typename lock_type,typename predicate_type>
|
||||
void wait(lock_type& lock,predicate_type predicate);
|
||||
|
||||
template<typename lock_type>
|
||||
bool timed_wait(lock_type& lock,boost::system_time const& abs_time);
|
||||
|
||||
template<typename lock_type,typename duration_type>
|
||||
bool timed_wait(lock_type& lock,duration_type const& rel_time);
|
||||
|
||||
template<typename lock_type,typename predicate_type>
|
||||
bool timed_wait(lock_type& lock,boost::system_time const& abs_time,predicate_type predicate);
|
||||
|
||||
template<typename lock_type,typename duration_type,typename predicate_type>
|
||||
bool timed_wait(lock_type& lock,duration_type const& rel_time,predicate_type predicate);
|
||||
|
||||
// backwards compatibility
|
||||
|
||||
template<typename lock_type>
|
||||
bool timed_wait(lock_type>& lock,boost::xtime const& abs_time);
|
||||
|
||||
template<typename lock_type,typename predicate_type>
|
||||
bool timed_wait(lock_type& lock,boost::xtime const& abs_time,predicate_type predicate);
|
||||
};
|
||||
}
|
||||
|
||||
[section:constructor `condition_variable_any()`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Constructs an object of class `condition_variable_any`.]]
|
||||
|
||||
[[Throws:] [__thread_resource_error__ if an error occurs.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:destructor `~condition_variable_any()`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Precondition:] [All threads waiting on `*this` have been notified by a call to
|
||||
`notify_one` or `notify_all` (though the respective calls to `wait` or
|
||||
`timed_wait` need not have returned).]]
|
||||
|
||||
[[Effects:] [Destroys the object.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:notify_one `void notify_one()`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [If any threads are currently __blocked__ waiting on `*this` in a call
|
||||
to `wait` or `timed_wait`, unblocks one of those threads.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:notify_all `void notify_all()`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [If any threads are currently __blocked__ waiting on `*this` in a call
|
||||
to `wait` or `timed_wait`, unblocks all of those threads.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:wait `template<typename lock_type> void wait(lock_type& lock)`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Atomically call `lock.unlock()` and blocks the current thread. The
|
||||
thread will unblock when notified by a call to `this->notify_one()` or
|
||||
`this->notify_all()`, or spuriously. When the thread is unblocked (for whatever
|
||||
reason), the lock is reacquired by invoking `lock.lock()` before the call to
|
||||
`wait` returns. The lock is also reacquired by invoking `lock.lock()` if the
|
||||
function exits with an exception.]]
|
||||
|
||||
[[Postcondition:] [`lock` is locked by the current thread.]]
|
||||
|
||||
[[Throws:] [__thread_resource_error__ if an error
|
||||
occurs. __thread_interrupted__ if the wait was interrupted by a call to
|
||||
__interrupt__ on the __thread__ object associated with the current thread of execution.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:wait_predicate `template<typename lock_type,typename predicate_type> void wait(lock_type& lock, predicate_type pred)`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [As-if ``
|
||||
while(!pred())
|
||||
{
|
||||
wait(lock);
|
||||
}
|
||||
``]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:timed_wait `template<typename lock_type> bool timed_wait(lock_type& lock,boost::system_time const& abs_time)`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Atomically call `lock.unlock()` and blocks the current thread. The
|
||||
thread will unblock when notified by a call to `this->notify_one()` or
|
||||
`this->notify_all()`, when the time as reported by `boost::get_system_time()`
|
||||
would be equal to or later than the specified `abs_time`, or spuriously. When
|
||||
the thread is unblocked (for whatever reason), the lock is reacquired by
|
||||
invoking `lock.lock()` before the call to `wait` returns. The lock is also
|
||||
reacquired by invoking `lock.lock()` if the function exits with an exception.]]
|
||||
|
||||
[[Returns:] [`false` if the call is returning because the time specified by
|
||||
`abs_time` was reached, `true` otherwise.]]
|
||||
|
||||
[[Postcondition:] [`lock` is locked by the current thread.]]
|
||||
|
||||
[[Throws:] [__thread_resource_error__ if an error
|
||||
occurs. __thread_interrupted__ if the wait was interrupted by a call to
|
||||
__interrupt__ on the __thread__ object associated with the current thread of execution.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:timed_wait_rel `template<typename lock_type,typename duration_type> bool timed_wait(lock_type& lock,duration_type const& rel_time)`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Atomically call `lock.unlock()` and blocks the current thread. The
|
||||
thread will unblock when notified by a call to `this->notify_one()` or
|
||||
`this->notify_all()`, after the period of time indicated by the `rel_time`
|
||||
argument has elapsed, or spuriously. When the thread is unblocked (for whatever
|
||||
reason), the lock is reacquired by invoking `lock.lock()` before the call to
|
||||
`wait` returns. The lock is also reacquired by invoking `lock.lock()` if the
|
||||
function exits with an exception.]]
|
||||
|
||||
[[Returns:] [`false` if the call is returning because the time period specified
|
||||
by `rel_time` has elapsed, `true` otherwise.]]
|
||||
|
||||
[[Postcondition:] [`lock` is locked by the current thread.]]
|
||||
|
||||
[[Throws:] [__thread_resource_error__ if an error
|
||||
occurs. __thread_interrupted__ if the wait was interrupted by a call to
|
||||
__interrupt__ on the __thread__ object associated with the current thread of execution.]]
|
||||
|
||||
]
|
||||
|
||||
[note The duration overload of timed_wait is difficult to use correctly. The overload taking a predicate should be preferred in most cases.]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:timed_wait_predicate `template<typename lock_type,typename predicate_type> bool timed_wait(lock_type& lock, boost::system_time const& abs_time, predicate_type pred)`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [As-if ``
|
||||
while(!pred())
|
||||
{
|
||||
if(!timed_wait(lock,abs_time))
|
||||
{
|
||||
return pred();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
``]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:condition Typedef `condition`]
|
||||
|
||||
#include <boost/thread/condition.hpp>
|
||||
|
||||
typedef condition_variable_any condition;
|
||||
|
||||
The typedef `condition` is provided for backwards compatibility with previous boost releases.
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
@@ -1,6 +1,6 @@
|
||||
<!-- Copyright (c) 2002-2003 Beman Dawes, William E. Kempf.
|
||||
Subject to the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
|
||||
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
|
||||
1119
doc/mutex_concepts.qbk
Normal file
1119
doc/mutex_concepts.qbk
Normal file
File diff suppressed because it is too large
Load Diff
224
doc/mutexes.qbk
Normal file
224
doc/mutexes.qbk
Normal file
@@ -0,0 +1,224 @@
|
||||
[/
|
||||
(C) Copyright 2007-8 Anthony Williams.
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
]
|
||||
|
||||
[section:mutex_types Mutex Types]
|
||||
|
||||
[section:mutex Class `mutex`]
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
|
||||
class mutex:
|
||||
boost::noncopyable
|
||||
{
|
||||
public:
|
||||
mutex();
|
||||
~mutex();
|
||||
|
||||
void lock();
|
||||
bool try_lock();
|
||||
void unlock();
|
||||
|
||||
typedef platform-specific-type native_handle_type;
|
||||
native_handle_type native_handle();
|
||||
|
||||
typedef unique_lock<mutex> scoped_lock;
|
||||
typedef unspecified-type scoped_try_lock;
|
||||
};
|
||||
|
||||
__mutex__ implements the __lockable_concept__ to provide an exclusive-ownership mutex. At most one thread can own the lock on a given
|
||||
instance of __mutex__ at any time. Multiple concurrent calls to __lock_ref__, __try_lock_ref__ and __unlock_ref__ shall be permitted.
|
||||
|
||||
[section:nativehandle Member function `native_handle()`]
|
||||
|
||||
typedef platform-specific-type native_handle_type;
|
||||
native_handle_type native_handle();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Returns an instance of `native_handle_type` that can be used with platform-specific APIs to manipulate the underlying
|
||||
implementation. If no such instance exists, `native_handle()` and `native_handle_type` are not present.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:try_mutex Typedef `try_mutex`]
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
|
||||
typedef mutex try_mutex;
|
||||
|
||||
__try_mutex__ is a `typedef` to __mutex__, provided for backwards compatibility with previous releases of boost.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:timed_mutex Class `timed_mutex`]
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
|
||||
class timed_mutex:
|
||||
boost::noncopyable
|
||||
{
|
||||
public:
|
||||
timed_mutex();
|
||||
~timed_mutex();
|
||||
|
||||
void lock();
|
||||
void unlock();
|
||||
bool try_lock();
|
||||
bool timed_lock(system_time const & abs_time);
|
||||
|
||||
template<typename TimeDuration>
|
||||
bool timed_lock(TimeDuration const & relative_time);
|
||||
|
||||
typedef platform-specific-type native_handle_type;
|
||||
native_handle_type native_handle();
|
||||
|
||||
typedef unique_lock<timed_mutex> scoped_timed_lock;
|
||||
typedef unspecified-type scoped_try_lock;
|
||||
typedef scoped_timed_lock scoped_lock;
|
||||
};
|
||||
|
||||
__timed_mutex__ implements the __timed_lockable_concept__ to provide an exclusive-ownership mutex. At most one thread can own the
|
||||
lock on a given instance of __timed_mutex__ at any time. Multiple concurrent calls to __lock_ref__, __try_lock_ref__,
|
||||
__timed_lock_ref__, __timed_lock_duration_ref__ and __unlock_ref__ shall be permitted.
|
||||
|
||||
[section:nativehandle Member function `native_handle()`]
|
||||
|
||||
typedef platform-specific-type native_handle_type;
|
||||
native_handle_type native_handle();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Returns an instance of `native_handle_type` that can be used with platform-specific APIs to manipulate the underlying
|
||||
implementation. If no such instance exists, `native_handle()` and `native_handle_type` are not present.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:recursive_mutex Class `recursive_mutex`]
|
||||
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
|
||||
class recursive_mutex:
|
||||
boost::noncopyable
|
||||
{
|
||||
public:
|
||||
recursive_mutex();
|
||||
~recursive_mutex();
|
||||
|
||||
void lock();
|
||||
bool try_lock();
|
||||
void unlock();
|
||||
|
||||
typedef platform-specific-type native_handle_type;
|
||||
native_handle_type native_handle();
|
||||
|
||||
typedef unique_lock<recursive_mutex> scoped_lock;
|
||||
typedef unspecified-type scoped_try_lock;
|
||||
};
|
||||
|
||||
__recursive_mutex__ implements the __lockable_concept__ to provide an exclusive-ownership recursive mutex. At most one thread can
|
||||
own the lock on a given instance of __recursive_mutex__ at any time. Multiple concurrent calls to __lock_ref__, __try_lock_ref__ and
|
||||
__unlock_ref__ shall be permitted. A thread that already has exclusive ownership of a given __recursive_mutex__ instance can call
|
||||
__lock_ref__ or __try_lock_ref__ to acquire an additional level of ownership of the mutex. __unlock_ref__ must be called once for
|
||||
each level of ownership acquired by a single thread before ownership can be acquired by another thread.
|
||||
|
||||
[section:nativehandle Member function `native_handle()`]
|
||||
|
||||
typedef platform-specific-type native_handle_type;
|
||||
native_handle_type native_handle();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Returns an instance of `native_handle_type` that can be used with platform-specific APIs to manipulate the underlying
|
||||
implementation. If no such instance exists, `native_handle()` and `native_handle_type` are not present.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:recursive_try_mutex Typedef `recursive_try_mutex`]
|
||||
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
|
||||
typedef recursive_mutex recursive_try_mutex;
|
||||
|
||||
__recursive_try_mutex__ is a `typedef` to __recursive_mutex__, provided for backwards compatibility with previous releases of boost.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:recursive_timed_mutex Class `recursive_timed_mutex`]
|
||||
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
|
||||
class recursive_timed_mutex:
|
||||
boost::noncopyable
|
||||
{
|
||||
public:
|
||||
recursive_timed_mutex();
|
||||
~recursive_timed_mutex();
|
||||
|
||||
void lock();
|
||||
bool try_lock();
|
||||
void unlock();
|
||||
|
||||
bool timed_lock(system_time const & abs_time);
|
||||
|
||||
template<typename TimeDuration>
|
||||
bool timed_lock(TimeDuration const & relative_time);
|
||||
|
||||
typedef platform-specific-type native_handle_type;
|
||||
native_handle_type native_handle();
|
||||
|
||||
typedef unique_lock<recursive_timed_mutex> scoped_lock;
|
||||
typedef unspecified-type scoped_try_lock;
|
||||
typedef scoped_lock scoped_timed_lock;
|
||||
};
|
||||
|
||||
__recursive_timed_mutex__ implements the __timed_lockable_concept__ to provide an exclusive-ownership recursive mutex. At most one
|
||||
thread can own the lock on a given instance of __recursive_timed_mutex__ at any time. Multiple concurrent calls to __lock_ref__,
|
||||
__try_lock_ref__, __timed_lock_ref__, __timed_lock_duration_ref__ and __unlock_ref__ shall be permitted. A thread that already has
|
||||
exclusive ownership of a given __recursive_timed_mutex__ instance can call __lock_ref__, __timed_lock_ref__,
|
||||
__timed_lock_duration_ref__ or __try_lock_ref__ to acquire an additional level of ownership of the mutex. __unlock_ref__ must be
|
||||
called once for each level of ownership acquired by a single thread before ownership can be acquired by another thread.
|
||||
|
||||
[section:nativehandle Member function `native_handle()`]
|
||||
|
||||
typedef platform-specific-type native_handle_type;
|
||||
native_handle_type native_handle();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Returns an instance of `native_handle_type` that can be used with platform-specific APIs to manipulate the underlying
|
||||
implementation. If no such instance exists, `native_handle()` and `native_handle_type` are not present.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
[include shared_mutex_ref.qbk]
|
||||
|
||||
[endsect]
|
||||
@@ -65,25 +65,23 @@ void init()
|
||||
|
||||
void thread_proc()
|
||||
{
|
||||
boost::call_once(&init, once);
|
||||
boost::call_once(once, &init);
|
||||
}</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>
|
||||
|
||||
<parameter name="func">
|
||||
<paramtype>Function func</paramtype>
|
||||
</parameter>
|
||||
|
||||
<effects>As if (in an atomic fashion):
|
||||
<code>if (flag == BOOST_ONCE_INIT) func();</code></effects>
|
||||
<code>if (flag == BOOST_ONCE_INIT) func();</code>. If <code>func()</code> throws an exception, it shall be as if this
|
||||
thread never invoked <code>call_once</code></effects>
|
||||
|
||||
<postconditions><code>flag != BOOST_ONCE_INIT</code>
|
||||
<postconditions><code>flag != BOOST_ONCE_INIT</code> unless <code>func()</code> throws an exception.
|
||||
</postconditions>
|
||||
</function>
|
||||
</namespace>
|
||||
|
||||
56
doc/once.qbk
Normal file
56
doc/once.qbk
Normal file
@@ -0,0 +1,56 @@
|
||||
[/
|
||||
(C) Copyright 2007-8 Anthony Williams.
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
]
|
||||
|
||||
[section:once One-time Initialization]
|
||||
|
||||
`boost::call_once` provides a mechanism for ensuring that an initialization routine is run exactly once without data races or deadlocks.
|
||||
|
||||
[section:once_flag Typedef `once_flag`]
|
||||
|
||||
#include <boost/thread/once.hpp>
|
||||
|
||||
typedef platform-specific-type once_flag;
|
||||
#define BOOST_ONCE_INIT platform-specific-initializer
|
||||
|
||||
Objects of type `boost::once_flag` shall be initialized with `BOOST_ONCE_INIT`:
|
||||
|
||||
boost::once_flag f=BOOST_ONCE_INIT;
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:call_once Non-member function `call_once`]
|
||||
|
||||
#include <boost/thread/once.hpp>
|
||||
|
||||
template<typename Callable>
|
||||
void call_once(once_flag& flag,Callable func);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [`Callable` is `CopyConstructible`. Copying `func` shall have no side effects, and the effect of calling the copy shall
|
||||
be equivalent to calling the original. ]]
|
||||
|
||||
[[Effects:] [Calls to `call_once` on the same `once_flag` object are serialized. If there has been no prior effective `call_once` on
|
||||
the same `once_flag` object, the argument `func` (or a copy thereof) is called as-if by invoking `func()`, and the invocation of
|
||||
`call_once` is effective if and only if `func()` returns without exception. If an exception is thrown, the exception is
|
||||
propagated to the caller. If there has been a prior effective `call_once` on the same `once_flag` object, the `call_once` returns
|
||||
without invoking `func`. ]]
|
||||
|
||||
[[Synchronization:] [The completion of an effective `call_once` invocation on a `once_flag` object, synchronizes with
|
||||
all subsequent `call_once` invocations on the same `once_flag` object. ]]
|
||||
|
||||
[[Throws:] [`thread_resource_error` when the effects cannot be achieved. or any exception propagated from `func`.]]
|
||||
|
||||
]
|
||||
|
||||
void call_once(void (*func)(),once_flag& flag);
|
||||
|
||||
This second overload is provided for backwards compatibility. The effects of `call_once(func,flag)` shall be the same as those of
|
||||
`call_once(flag,func)`.
|
||||
|
||||
[endsect]
|
||||
[endsect]
|
||||
30
doc/overview.qbk
Normal file
30
doc/overview.qbk
Normal file
@@ -0,0 +1,30 @@
|
||||
[/
|
||||
(C) Copyright 2007-8 Anthony Williams.
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
]
|
||||
|
||||
[section:overview Overview]
|
||||
|
||||
__boost_thread__ enables the use of multiple threads of execution with shared data in portable C++ code. It provides classes and
|
||||
functions for managing the threads themselves, along with others for synchronizing data between the threads or providing separate
|
||||
copies of data specific to individual threads.
|
||||
|
||||
The __boost_thread__ library was originally written and designed by William E. Kempf. This version is a major rewrite designed to
|
||||
closely follow the proposals presented to the C++ Standards Committee, in particular
|
||||
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2497.html N2497],
|
||||
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2320.html N2320],
|
||||
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2184.html N2184],
|
||||
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2139.html N2139], and
|
||||
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2094.html N2094]
|
||||
|
||||
In order to use the classes and functions described here, you can
|
||||
either include the specific headers specified by the descriptions of
|
||||
each class or function, or include the master thread library header:
|
||||
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
which includes all the other headers in turn.
|
||||
|
||||
[endsect]
|
||||
@@ -37,6 +37,16 @@
|
||||
<purpose>
|
||||
<para>The <classname>read_write_mutex</classname> class is a model of the
|
||||
<link linkend="thread.concepts.ReadWriteMutex">ReadWriteMutex</link> concept.</para>
|
||||
<note> Unfortunately it turned out that the current implementation of Read/Write Mutex has
|
||||
some serious problems. So it was decided not to put this implementation into
|
||||
release grade code. Also discussions on the mailing list led to the
|
||||
conclusion that the current concepts need to be rethought. In particular
|
||||
the schedulings <link linkend="thread.concepts.read-write-scheduling-policies.inter-class">
|
||||
Inter-Class Scheduling Policies</link> are deemed unnecessary.
|
||||
There seems to be common belief that a fair scheme suffices.
|
||||
The following documentation has been retained however, to give
|
||||
readers of this document the opportunity to study the original design.
|
||||
</note>
|
||||
</purpose>
|
||||
|
||||
<description>
|
||||
@@ -160,6 +170,16 @@
|
||||
<purpose>
|
||||
<para>The <classname>try_read_write_mutex</classname> class is a model of the
|
||||
<link linkend="thread.concepts.TryReadWriteMutex">TryReadWriteMutex</link> concept.</para>
|
||||
<note> Unfortunately it turned out that the current implementation of Read/Write Mutex has
|
||||
some serious problems. So it was decided not to put this implementation into
|
||||
release grade code. Also discussions on the mailing list led to the
|
||||
conclusion that the current concepts need to be rethought. In particular
|
||||
the schedulings <link linkend="thread.concepts.read-write-scheduling-policies.inter-class">
|
||||
Inter-Class Scheduling Policies</link> are deemed unnecessary.
|
||||
There seems to be common belief that a fair scheme suffices.
|
||||
The following documentation has been retained however, to give
|
||||
readers of this document the opportunity to study the original design.
|
||||
</note>
|
||||
</purpose>
|
||||
|
||||
<description>
|
||||
@@ -302,6 +322,16 @@
|
||||
<purpose>
|
||||
<para>The <classname>timed_read_write_mutex</classname> class is a model of the
|
||||
<link linkend="thread.concepts.TimedReadWriteMutex">TimedReadWriteMutex</link> concept.</para>
|
||||
<note> Unfortunately it turned out that the current implementation of Read/Write Mutex has
|
||||
some serious problems. So it was decided not to put this implementation into
|
||||
release grade code. Also discussions on the mailing list led to the
|
||||
conclusion that the current concepts need to be rethought. In particular
|
||||
the schedulings <link linkend="thread.concepts.read-write-scheduling-policies.inter-class">
|
||||
Inter-Class Scheduling Policies</link> are deemed unnecessary.
|
||||
There seems to be common belief that a fair scheme suffices.
|
||||
The following documentation has been retained however, to give
|
||||
readers of this document the opportunity to study the original design.
|
||||
</note>
|
||||
</purpose>
|
||||
|
||||
<description>
|
||||
|
||||
44
doc/shared_mutex_ref.qbk
Normal file
44
doc/shared_mutex_ref.qbk
Normal file
@@ -0,0 +1,44 @@
|
||||
[/
|
||||
(C) Copyright 2007-8 Anthony Williams.
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
]
|
||||
|
||||
[section:shared_mutex Class `shared_mutex`]
|
||||
|
||||
#include <boost/thread/shared_mutex.hpp>
|
||||
|
||||
class shared_mutex
|
||||
{
|
||||
public:
|
||||
shared_mutex();
|
||||
~shared_mutex();
|
||||
|
||||
void lock_shared();
|
||||
bool try_lock_shared();
|
||||
bool timed_lock_shared(system_time const& timeout);
|
||||
void unlock_shared();
|
||||
|
||||
void lock();
|
||||
bool try_lock();
|
||||
bool timed_lock(system_time const& timeout);
|
||||
void unlock();
|
||||
|
||||
void lock_upgrade();
|
||||
void unlock_upgrade();
|
||||
|
||||
void unlock_upgrade_and_lock();
|
||||
void unlock_and_lock_upgrade();
|
||||
void unlock_and_lock_shared();
|
||||
void unlock_upgrade_and_lock_shared();
|
||||
};
|
||||
|
||||
The class `boost::shared_mutex` provides an implementation of a multiple-reader / single-writer mutex. It implements the
|
||||
__upgrade_lockable_concept__.
|
||||
|
||||
Multiple concurrent calls to __lock_ref__, __try_lock_ref__, __timed_lock_ref__, __lock_shared_ref__, __try_lock_shared_ref__ and
|
||||
__timed_lock_shared_ref__ shall be permitted.
|
||||
|
||||
|
||||
[endsect]
|
||||
167
doc/thread.qbk
Normal file
167
doc/thread.qbk
Normal file
@@ -0,0 +1,167 @@
|
||||
[/
|
||||
(C) Copyright 2007-8 Anthony Williams.
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
]
|
||||
|
||||
[article Thread
|
||||
[quickbook 1.4]
|
||||
[authors [Williams, Anthony]]
|
||||
[copyright 2007-8 Anthony Williams]
|
||||
[purpose C++ Library for launching threads and synchronizing data between them]
|
||||
[category text]
|
||||
[license
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
[@http://www.boost.org/LICENSE_1_0.txt])
|
||||
]
|
||||
]
|
||||
|
||||
[template lockable_concept_link[link_text] [link thread.synchronization.mutex_concepts.lockable [link_text]]]
|
||||
[def __lockable_concept__ [lockable_concept_link `Lockable` concept]]
|
||||
[def __lockable_concept_type__ [lockable_concept_link `Lockable`]]
|
||||
|
||||
[template timed_lockable_concept_link[link_text] [link thread.synchronization.mutex_concepts.timed_lockable [link_text]]]
|
||||
[def __timed_lockable_concept__ [timed_lockable_concept_link `TimedLockable` concept]]
|
||||
[def __timed_lockable_concept_type__ [timed_lockable_concept_link `TimedLockable`]]
|
||||
|
||||
[template shared_lockable_concept_link[link_text] [link thread.synchronization.mutex_concepts.shared_lockable [link_text]]]
|
||||
[def __shared_lockable_concept__ [shared_lockable_concept_link `SharedLockable` concept]]
|
||||
[def __shared_lockable_concept_type__ [shared_lockable_concept_link `SharedLockable`]]
|
||||
|
||||
[template upgrade_lockable_concept_link[link_text] [link thread.synchronization.mutex_concepts.upgrade_lockable [link_text]]]
|
||||
[def __upgrade_lockable_concept__ [upgrade_lockable_concept_link `UpgradeLockable` concept]]
|
||||
[def __upgrade_lockable_concept_type__ [upgrade_lockable_concept_link `UpgradeLockable`]]
|
||||
|
||||
|
||||
[template lock_ref_link[link_text] [link thread.synchronization.mutex_concepts.lockable.lock [link_text]]]
|
||||
[def __lock_ref__ [lock_ref_link `lock()`]]
|
||||
|
||||
[template lock_multiple_ref_link[link_text] [link thread.synchronization.lock_functions.lock_multiple [link_text]]]
|
||||
[def __lock_multiple_ref__ [lock_multiple_ref_link `lock()`]]
|
||||
|
||||
[template try_lock_multiple_ref_link[link_text] [link thread.synchronization.lock_functions.try_lock_multiple [link_text]]]
|
||||
[def __try_lock_multiple_ref__ [try_lock_multiple_ref_link `try_lock()`]]
|
||||
|
||||
[template unlock_ref_link[link_text] [link thread.synchronization.mutex_concepts.lockable.unlock [link_text]]]
|
||||
[def __unlock_ref__ [unlock_ref_link `unlock()`]]
|
||||
|
||||
[template try_lock_ref_link[link_text] [link thread.synchronization.mutex_concepts.lockable.try_lock [link_text]]]
|
||||
[def __try_lock_ref__ [try_lock_ref_link `try_lock()`]]
|
||||
|
||||
[template timed_lock_ref_link[link_text] [link thread.synchronization.mutex_concepts.timed_lockable.timed_lock [link_text]]]
|
||||
[def __timed_lock_ref__ [timed_lock_ref_link `timed_lock()`]]
|
||||
|
||||
[template timed_lock_duration_ref_link[link_text] [link thread.synchronization.mutex_concepts.timed_lockable.timed_lock_duration [link_text]]]
|
||||
[def __timed_lock_duration_ref__ [timed_lock_duration_ref_link `timed_lock()`]]
|
||||
|
||||
[template lock_shared_ref_link[link_text] [link thread.synchronization.mutex_concepts.shared_lockable.lock_shared [link_text]]]
|
||||
[def __lock_shared_ref__ [lock_shared_ref_link `lock_shared()`]]
|
||||
|
||||
[template unlock_shared_ref_link[link_text] [link thread.synchronization.mutex_concepts.shared_lockable.unlock_shared [link_text]]]
|
||||
[def __unlock_shared_ref__ [unlock_shared_ref_link `unlock_shared()`]]
|
||||
|
||||
[template try_lock_shared_ref_link[link_text] [link thread.synchronization.mutex_concepts.shared_lockable.try_lock_shared [link_text]]]
|
||||
[def __try_lock_shared_ref__ [try_lock_shared_ref_link `try_lock_shared()`]]
|
||||
|
||||
[template timed_lock_shared_ref_link[link_text] [link thread.synchronization.mutex_concepts.shared_lockable.timed_lock_shared [link_text]]]
|
||||
[def __timed_lock_shared_ref__ [timed_lock_shared_ref_link `timed_lock_shared()`]]
|
||||
|
||||
[template timed_lock_shared_duration_ref_link[link_text] [link thread.synchronization.mutex_concepts.shared_lockable.timed_lock_shared_duration [link_text]]]
|
||||
[def __timed_lock_shared_duration_ref__ [timed_lock_shared_duration_ref_link `timed_lock_shared()`]]
|
||||
|
||||
[template lock_upgrade_ref_link[link_text] [link thread.synchronization.mutex_concepts.upgrade_lockable.lock_upgrade [link_text]]]
|
||||
[def __lock_upgrade_ref__ [lock_upgrade_ref_link `lock_upgrade()`]]
|
||||
|
||||
[template unlock_upgrade_ref_link[link_text] [link thread.synchronization.mutex_concepts.upgrade_lockable.unlock_upgrade [link_text]]]
|
||||
[def __unlock_upgrade_ref__ [unlock_upgrade_ref_link `unlock_upgrade()`]]
|
||||
|
||||
[template unlock_upgrade_and_lock_ref_link[link_text] [link thread.synchronization.mutex_concepts.upgrade_lockable.unlock_upgrade_and_lock [link_text]]]
|
||||
[def __unlock_upgrade_and_lock_ref__ [unlock_upgrade_and_lock_ref_link `unlock_upgrade_and_lock()`]]
|
||||
|
||||
[template unlock_and_lock_upgrade_ref_link[link_text] [link thread.synchronization.mutex_concepts.upgrade_lockable.unlock_and_lock_upgrade [link_text]]]
|
||||
[def __unlock_and_lock_upgrade_ref__ [unlock_and_lock_upgrade_ref_link `unlock_and_lock_upgrade()`]]
|
||||
|
||||
[template unlock_upgrade_and_lock_shared_ref_link[link_text] [link thread.synchronization.mutex_concepts.upgrade_lockable.unlock_upgrade_and_lock_shared [link_text]]]
|
||||
[def __unlock_upgrade_and_lock_shared_ref__ [unlock_upgrade_and_lock_shared_ref_link `unlock_upgrade_and_lock_shared()`]]
|
||||
|
||||
[template owns_lock_ref_link[link_text] [link thread.synchronization.locks.unique_lock.owns_lock [link_text]]]
|
||||
[def __owns_lock_ref__ [owns_lock_ref_link `owns_lock()`]]
|
||||
|
||||
[template owns_lock_shared_ref_link[link_text] [link thread.synchronization.locks.shared_lock.owns_lock [link_text]]]
|
||||
[def __owns_lock_shared_ref__ [owns_lock_shared_ref_link `owns_lock()`]]
|
||||
|
||||
[template mutex_func_ref_link[link_text] [link thread.synchronization.locks.unique_lock.mutex [link_text]]]
|
||||
[def __mutex_func_ref__ [mutex_func_ref_link `mutex()`]]
|
||||
|
||||
[def __boost_thread__ [*Boost.Thread]]
|
||||
[def __not_a_thread__ ['Not-a-Thread]]
|
||||
[def __interruption_points__ [link interruption_points ['interruption points]]]
|
||||
|
||||
[def __mutex__ [link thread.synchronization.mutex_types.mutex `boost::mutex`]]
|
||||
[def __try_mutex__ [link thread.synchronization.mutex_types.try_mutex `boost::try_mutex`]]
|
||||
[def __timed_mutex__ [link thread.synchronization.mutex_types.timed_mutex `boost::timed_mutex`]]
|
||||
[def __recursive_mutex__ [link thread.synchronization.mutex_types.recursive_mutex `boost::recursive_mutex`]]
|
||||
[def __recursive_try_mutex__ [link thread.synchronization.mutex_types.recursive_try_mutex `boost::recursive_try_mutex`]]
|
||||
[def __recursive_timed_mutex__ [link thread.synchronization.mutex_types.recursive_timed_mutex `boost::recursive_timed_mutex`]]
|
||||
[def __shared_mutex__ [link thread.synchronization.mutex_types.shared_mutex `boost::shared_mutex`]]
|
||||
|
||||
[template unique_lock_link[link_text] [link thread.synchronization.locks.unique_lock [link_text]]]
|
||||
|
||||
[def __lock_guard__ [link thread.synchronization.locks.lock_guard `boost::lock_guard`]]
|
||||
[def __unique_lock__ [unique_lock_link `boost::unique_lock`]]
|
||||
[def __shared_lock__ [link thread.synchronization.locks.shared_lock `boost::shared_lock`]]
|
||||
[def __upgrade_lock__ [link thread.synchronization.locks.upgrade_lock `boost::upgrade_lock`]]
|
||||
[def __upgrade_to_unique_lock__ [link thread.synchronization.locks.upgrade_to_unique_lock `boost::upgrade_to_unique_lock`]]
|
||||
|
||||
|
||||
[def __thread__ [link thread.thread_management.thread `boost::thread`]]
|
||||
[def __thread_id__ [link thread.thread_management.thread.id `boost::thread::id`]]
|
||||
[template join_link[link_text] [link thread.thread_management.thread.join [link_text]]]
|
||||
[def __join__ [join_link `join()`]]
|
||||
[template timed_join_link[link_text] [link thread.thread_management.thread.timed_join [link_text]]]
|
||||
[def __timed_join__ [timed_join_link `timed_join()`]]
|
||||
[def __detach__ [link thread.thread_management.thread.detach `detach()`]]
|
||||
[def __interrupt__ [link thread.thread_management.thread.interrupt `interrupt()`]]
|
||||
[def __sleep__ [link thread.thread_management.this_thread.sleep `boost::this_thread::sleep()`]]
|
||||
|
||||
[def __interruption_enabled__ [link thread.thread_management.this_thread.interruption_enabled `boost::this_thread::interruption_enabled()`]]
|
||||
[def __interruption_requested__ [link thread.thread_management.this_thread.interruption_requested `boost::this_thread::interruption_requested()`]]
|
||||
[def __interruption_point__ [link thread.thread_management.this_thread.interruption_point `boost::this_thread::interruption_point()`]]
|
||||
[def __disable_interruption__ [link thread.thread_management.this_thread.disable_interruption `boost::this_thread::disable_interruption`]]
|
||||
[def __restore_interruption__ [link thread.thread_management.this_thread.restore_interruption `boost::this_thread::restore_interruption`]]
|
||||
|
||||
[def __thread_resource_error__ `boost::thread_resource_error`]
|
||||
[def __thread_interrupted__ `boost::thread_interrupted`]
|
||||
[def __barrier__ [link thread.synchronization.barriers.barrier `boost::barrier`]]
|
||||
|
||||
[template cond_wait_link[link_text] [link thread.synchronization.condvar_ref.condition_variable.wait [link_text]]]
|
||||
[def __cond_wait__ [cond_wait_link `wait()`]]
|
||||
[template cond_timed_wait_link[link_text] [link thread.synchronization.condvar_ref.condition_variable.timed_wait [link_text]]]
|
||||
[def __cond_timed_wait__ [cond_timed_wait_link `timed_wait()`]]
|
||||
[template cond_any_wait_link[link_text] [link thread.synchronization.condvar_ref.condition_variable_any.wait [link_text]]]
|
||||
[def __cond_any_wait__ [cond_any_wait_link `wait()`]]
|
||||
[template cond_any_timed_wait_link[link_text] [link thread.synchronization.condvar_ref.condition_variable_any.timed_wait [link_text]]]
|
||||
[def __cond_any_timed_wait__ [cond_any_timed_wait_link `timed_wait()`]]
|
||||
|
||||
[def __blocked__ ['blocked]]
|
||||
|
||||
[include overview.qbk]
|
||||
[include changes.qbk]
|
||||
|
||||
[include thread_ref.qbk]
|
||||
|
||||
[section:synchronization Synchronization]
|
||||
[include mutex_concepts.qbk]
|
||||
[include mutexes.qbk]
|
||||
[include condition_variables.qbk]
|
||||
[include once.qbk]
|
||||
[include barrier.qbk]
|
||||
[endsect]
|
||||
|
||||
[include tss.qbk]
|
||||
|
||||
[include time.qbk]
|
||||
|
||||
[include acknowledgements.qbk]
|
||||
1064
doc/thread_ref.qbk
Normal file
1064
doc/thread_ref.qbk
Normal file
File diff suppressed because it is too large
Load Diff
75
doc/time.qbk
Normal file
75
doc/time.qbk
Normal file
@@ -0,0 +1,75 @@
|
||||
[/
|
||||
(C) Copyright 2007-8 Anthony Williams.
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
]
|
||||
|
||||
[section:time Date and Time Requirements]
|
||||
|
||||
As of Boost 1.35.0, the __boost_thread__ library uses the [link date_time Boost.Date_Time] library for all operations that require a
|
||||
time out. These include (but are not limited to):
|
||||
|
||||
* __sleep__
|
||||
* __timed_join__
|
||||
* __cond_timed_wait__
|
||||
* __timed_lock_ref__
|
||||
|
||||
For the overloads that accept an absolute time parameter, an object of type [link thread.time.system_time `boost::system_time`] is
|
||||
required. Typically, this will be obtained by adding a duration to the current time, obtained with a call to [link
|
||||
thread.time.get_system_time `boost::get_system_time()`]. e.g.
|
||||
|
||||
boost::system_time const timeout=boost::get_system_time() + boost::posix_time::milliseconds(500);
|
||||
|
||||
extern bool done;
|
||||
extern boost::mutex m;
|
||||
extern boost::condition_variable cond;
|
||||
|
||||
boost::unique_lock<boost::mutex> lk(m);
|
||||
while(!done)
|
||||
{
|
||||
if(!cond.timed_wait(lk,timeout))
|
||||
{
|
||||
throw "timed out";
|
||||
}
|
||||
}
|
||||
|
||||
For the overloads that accept a ['TimeDuration] parameter, an object of any type that meets the [link
|
||||
date_time.posix_time.time_duration Boost.Date_Time Time Duration requirements] can be used, e.g.
|
||||
|
||||
boost::this_thread::sleep(boost::posix_time::milliseconds(25));
|
||||
|
||||
boost::mutex m;
|
||||
if(m.timed_lock(boost::posix_time::nanoseconds(100)))
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
[section:system_time Typedef `system_time`]
|
||||
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
|
||||
typedef boost::posix_time::ptime system_time;
|
||||
|
||||
See the documentation for [link date_time.posix_time.ptime_class `boost::posix_time::ptime`] in the Boost.Date_Time library.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:get_system_time Non-member function `get_system_time()`]
|
||||
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
|
||||
system_time get_system_time();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Returns:] [The current time.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[endsect]
|
||||
184
doc/tss.qbk
Normal file
184
doc/tss.qbk
Normal file
@@ -0,0 +1,184 @@
|
||||
[/
|
||||
(C) Copyright 2007-8 Anthony Williams.
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
]
|
||||
|
||||
[section Thread Local Storage]
|
||||
|
||||
[heading Synopsis]
|
||||
|
||||
Thread local storage allows multi-threaded applications to have a separate instance of a given data item for each thread. Where a
|
||||
single-threaded application would use static or global data, this could lead to contention, deadlock or data corruption in a
|
||||
multi-threaded application. One example is the C `errno` variable, used for storing the error code related to functions from the
|
||||
Standard C library. It is common practice (and required by POSIX) for compilers that support multi-threaded applications to provide
|
||||
a separate instance of `errno` for each thread, in order to avoid different threads competing to read or update the value.
|
||||
|
||||
Though compilers often provide this facility in the form of extensions to the declaration syntax (such as `__declspec(thread)` or
|
||||
`__thread` annotations on `static` or namespace-scope variable declarations), such support is non-portable, and is often limited in
|
||||
some way, such as only supporting POD types.
|
||||
|
||||
[heading Portable thread-local storage with `boost::thread_specific_ptr`]
|
||||
|
||||
`boost::thread_specific_ptr` provides a portable mechanism for thread-local storage that works on all compilers supported by
|
||||
__boost_thread__. Each instance of `boost::thread_specific_ptr` represents a pointer to an object (such as `errno`) where each
|
||||
thread must have a distinct value. The value for the current thread can be obtained using the `get()` member function, or by using
|
||||
the `*` and `->` pointer deference operators. Initially the pointer has a value of `NULL` in each thread, but the value for the
|
||||
current thread can be set using the `reset()` member function.
|
||||
|
||||
If the value of the pointer for the current thread is changed using `reset()`, then the previous value is destroyed by calling the
|
||||
cleanup routine. Alternatively, the stored value can be reset to `NULL` and the prior value returned by calling the `release()`
|
||||
member function, allowing the application to take back responsibility for destroying the object.
|
||||
|
||||
[heading Cleanup at thread exit]
|
||||
|
||||
When a thread exits, the objects associated with each `boost::thread_specific_ptr` instance are destroyed. By default, the object
|
||||
pointed to by a pointer `p` is destroyed by invoking `delete p`, but this can be overridden for a specific instance of
|
||||
`boost::thread_specific_ptr` by providing a cleanup routine to the constructor. In this case, the object is destroyed by invoking
|
||||
`func(p)` where `func` is the cleanup routine supplied to the constructor. The cleanup functions are called in an unspecified
|
||||
order. If a cleanup routine sets the value of associated with an instance of `boost::thread_specific_ptr` that has already been
|
||||
cleaned up, that value is added to the cleanup list. Cleanup finishes when there are no outstanding instances of
|
||||
`boost::thread_specific_ptr` with values.
|
||||
|
||||
|
||||
[section:thread_specific_ptr Class `thread_specific_ptr`]
|
||||
|
||||
#include <boost/thread/tss.hpp>
|
||||
|
||||
template <typename T>
|
||||
class thread_specific_ptr
|
||||
{
|
||||
public:
|
||||
thread_specific_ptr();
|
||||
explicit thread_specific_ptr(void (*cleanup_function)(T*));
|
||||
~thread_specific_ptr();
|
||||
|
||||
T* get() const;
|
||||
T* operator->() const;
|
||||
T& operator*() const;
|
||||
|
||||
T* release();
|
||||
void reset(T* new_value=0);
|
||||
};
|
||||
|
||||
[section:default_constructor `thread_specific_ptr();`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [`delete this->get()` is well-formed.]]
|
||||
|
||||
[[Effects:] [Construct a `thread_specific_ptr` object for storing a pointer to an object of type `T` specific to each thread. The
|
||||
default `delete`-based cleanup function will be used to destroy any thread-local objects when `reset()` is called, or the thread
|
||||
exits.]]
|
||||
|
||||
[[Throws:] [`boost::thread_resource_error` if an error occurs.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:constructor_with_custom_cleanup `explicit thread_specific_ptr(void (*cleanup_function)(T*));`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [`cleanup_function(this->get())` does not throw any exceptions.]]
|
||||
|
||||
[[Effects:] [Construct a `thread_specific_ptr` object for storing a pointer to an object of type `T` specific to each thread. The
|
||||
supplied `cleanup_function` will be used to destroy any thread-local objects when `reset()` is called, or the thread exits.]]
|
||||
|
||||
[[Throws:] [`boost::thread_resource_error` if an error occurs.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:destructor `~thread_specific_ptr();`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Calls `this->reset()` to clean up the associated value for the current thread, and destroys `*this`.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[note Care needs to be taken to ensure that any threads still running after an instance of `boost::thread_specific_ptr` has been
|
||||
destroyed do not call any member functions on that instance.]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:get `T* get() const;`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Returns:] [The pointer associated with the current thread.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[note The initial value associated with an instance of `boost::thread_specific_ptr` is `NULL` for each thread.]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:operator_arrow `T* operator->() const;`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Returns:] [`this->get()`]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:operator_star `T& operator*() const;`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [`this->get` is not `NULL`.]]
|
||||
|
||||
[[Returns:] [`*(this->get())`]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:reset `void reset(T* new_value=0);`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [If `this->get()!=new_value` and `this->get()` is non-`NULL`, invoke `delete this->get()` or
|
||||
`cleanup_function(this->get())` as appropriate. Store `new_value` as the pointer associated with the current thread.]]
|
||||
|
||||
[[Postcondition:] [`this->get()==new_value`]]
|
||||
|
||||
[[Throws:] [`boost::thread_resource_error` if an error occurs.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:release `T* release();`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Return `this->get()` and store `NULL` as the pointer associated with the current thread without invoking the cleanup
|
||||
function.]]
|
||||
|
||||
[[Postcondition:] [`this->get()==0`]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
@@ -46,11 +46,16 @@ private:
|
||||
|
||||
bounded_buffer buf(2);
|
||||
|
||||
boost::mutex io_mutex;
|
||||
|
||||
void sender() {
|
||||
int n = 0;
|
||||
while (n < 100) {
|
||||
buf.send(n);
|
||||
std::cout << "sent: " << n << std::endl;
|
||||
{
|
||||
boost::mutex::scoped_lock io_lock(io_mutex);
|
||||
std::cout << "sent: " << n << std::endl;
|
||||
}
|
||||
++n;
|
||||
}
|
||||
buf.send(-1);
|
||||
@@ -60,7 +65,10 @@ void receiver() {
|
||||
int n;
|
||||
do {
|
||||
n = buf.receive();
|
||||
std::cout << "received: " << n << std::endl;
|
||||
{
|
||||
boost::mutex::scoped_lock io_lock(io_mutex);
|
||||
std::cout << "received: " << n << std::endl;
|
||||
}
|
||||
} while (n != -1); // -1 indicates end of buffer
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +1,25 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
// (C) Copyright 2008 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See www.boost.org/libs/thread for documentation.
|
||||
|
||||
#if !defined(BOOST_THREAD_WEK01082003_HPP)
|
||||
#define BOOST_THREAD_WEK01082003_HPP
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/condition.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/once.hpp>
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
#include <boost/thread/tss.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
#include <boost/thread/shared_mutex.hpp>
|
||||
#include <boost/thread/barrier.hpp>
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// Copyright (C) 2002-2003
|
||||
// David Moore, William E. Kempf
|
||||
// Copyright (C) 2007-8 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -10,35 +11,53 @@
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/condition.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace boost {
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
class BOOST_THREAD_DECL barrier
|
||||
namespace boost
|
||||
{
|
||||
public:
|
||||
barrier(unsigned int count);
|
||||
~barrier();
|
||||
|
||||
bool wait();
|
||||
class barrier
|
||||
{
|
||||
public:
|
||||
barrier(unsigned int count)
|
||||
: m_threshold(count), m_count(count), m_generation(0)
|
||||
{
|
||||
if (count == 0)
|
||||
throw std::invalid_argument("count cannot be zero.");
|
||||
}
|
||||
|
||||
bool 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;
|
||||
}
|
||||
|
||||
private:
|
||||
mutex m_mutex;
|
||||
// disable warnings about non dll import
|
||||
// see: http://www.boost.org/more/separate_compilation.html#dlls
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4251 4231 4660 4275)
|
||||
#endif
|
||||
condition m_cond;
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
unsigned int m_threshold;
|
||||
unsigned int m_count;
|
||||
unsigned int m_generation;
|
||||
};
|
||||
while (gen == m_generation)
|
||||
m_cond.wait(lock);
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
mutex m_mutex;
|
||||
condition_variable m_cond;
|
||||
unsigned int m_threshold;
|
||||
unsigned int m_count;
|
||||
unsigned int m_generation;
|
||||
};
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,201 +1,16 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
#ifndef BOOST_THREAD_CONDITION_HPP
|
||||
#define BOOST_THREAD_CONDITION_HPP
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_CONDITION_WEK070601_HPP
|
||||
#define BOOST_CONDITION_WEK070601_HPP
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/thread/detail/lock.hpp>
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
# include <pthread.h>
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
# include "scoped_critical_region.hpp"
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
struct xtime;
|
||||
// disable warnings about non dll import
|
||||
// see: http://www.boost.org/more/separate_compilation.html#dlls
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4251 4231 4660 4275)
|
||||
#endif
|
||||
|
||||
namespace detail {
|
||||
|
||||
class BOOST_THREAD_DECL condition_impl : private noncopyable
|
||||
namespace boost
|
||||
{
|
||||
friend class condition;
|
||||
typedef condition_variable_any condition;
|
||||
}
|
||||
|
||||
public:
|
||||
condition_impl();
|
||||
~condition_impl();
|
||||
|
||||
void notify_one();
|
||||
void notify_all();
|
||||
|
||||
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||
void enter_wait();
|
||||
void do_wait();
|
||||
bool do_timed_wait(const xtime& xt);
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
void do_wait(pthread_mutex_t* pmutex);
|
||||
bool do_timed_wait(const xtime& xt, pthread_mutex_t* pmutex);
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
void* m_gate;
|
||||
void* m_queue;
|
||||
void* m_mutex;
|
||||
unsigned m_gone; // # threads that timed out and never made it to m_queue
|
||||
unsigned long m_blocked; // # threads blocked on the condition
|
||||
unsigned m_waiting; // # threads no longer waiting for the condition but
|
||||
// still waiting to be removed from m_queue
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
pthread_cond_t m_condition;
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
MPSemaphoreID m_gate;
|
||||
MPSemaphoreID m_queue;
|
||||
threads::mac::detail::scoped_critical_region m_mutex;
|
||||
threads::mac::detail::scoped_critical_region m_mutex_mutex;
|
||||
unsigned m_gone; // # threads that timed out and never made it to m_queue
|
||||
unsigned long m_blocked; // # threads blocked on the condition
|
||||
unsigned m_waiting; // # threads no longer waiting for the condition but
|
||||
// still waiting to be removed from m_queue
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
class condition : private noncopyable
|
||||
{
|
||||
public:
|
||||
condition() { }
|
||||
~condition() { }
|
||||
|
||||
void notify_one() { m_impl.notify_one(); }
|
||||
void notify_all() { m_impl.notify_all(); }
|
||||
|
||||
template <typename L>
|
||||
void wait(L& lock)
|
||||
{
|
||||
if (!lock)
|
||||
throw lock_error();
|
||||
|
||||
do_wait(lock.m_mutex);
|
||||
}
|
||||
|
||||
template <typename L, typename Pr>
|
||||
void wait(L& lock, Pr pred)
|
||||
{
|
||||
if (!lock)
|
||||
throw lock_error();
|
||||
|
||||
while (!pred())
|
||||
do_wait(lock.m_mutex);
|
||||
}
|
||||
|
||||
template <typename L>
|
||||
bool timed_wait(L& lock, const xtime& xt)
|
||||
{
|
||||
if (!lock)
|
||||
throw lock_error();
|
||||
|
||||
return do_timed_wait(lock.m_mutex, xt);
|
||||
}
|
||||
|
||||
template <typename L, typename Pr>
|
||||
bool timed_wait(L& lock, const xtime& xt, Pr pred)
|
||||
{
|
||||
if (!lock)
|
||||
throw lock_error();
|
||||
|
||||
while (!pred())
|
||||
{
|
||||
if (!do_timed_wait(lock.m_mutex, xt))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
detail::condition_impl m_impl;
|
||||
|
||||
template <typename M>
|
||||
void do_wait(M& mutex)
|
||||
{
|
||||
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||
m_impl.enter_wait();
|
||||
#endif
|
||||
|
||||
typedef detail::thread::lock_ops<M>
|
||||
#if defined(__HP_aCC) && __HP_aCC <= 33900 && !defined(BOOST_STRICT_CONFIG)
|
||||
# define lock_ops lock_ops_ // HP confuses lock_ops witht the template
|
||||
#endif
|
||||
lock_ops;
|
||||
|
||||
typename lock_ops::lock_state state;
|
||||
lock_ops::unlock(mutex, state);
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
m_impl.do_wait(state.pmutex);
|
||||
#elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||
m_impl.do_wait();
|
||||
#endif
|
||||
|
||||
lock_ops::lock(mutex, state);
|
||||
#undef lock_ops
|
||||
}
|
||||
|
||||
template <typename M>
|
||||
bool do_timed_wait(M& mutex, const xtime& xt)
|
||||
{
|
||||
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||
m_impl.enter_wait();
|
||||
#endif
|
||||
|
||||
typedef detail::thread::lock_ops<M>
|
||||
#if defined(__HP_aCC) && __HP_aCC <= 33900 && !defined(BOOST_STRICT_CONFIG)
|
||||
# define lock_ops lock_ops_ // HP confuses lock_ops witht the template
|
||||
#endif
|
||||
lock_ops;
|
||||
|
||||
typename lock_ops::lock_state state;
|
||||
lock_ops::unlock(mutex, state);
|
||||
|
||||
bool ret = false;
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
ret = m_impl.do_timed_wait(xt, state.pmutex);
|
||||
#elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||
ret = m_impl.do_timed_wait(xt);
|
||||
#endif
|
||||
|
||||
lock_ops::lock(mutex, state);
|
||||
#undef lock_ops
|
||||
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
} // namespace boost
|
||||
|
||||
// Change Log:
|
||||
// 8 Feb 01 WEKEMPF Initial version.
|
||||
// 22 May 01 WEKEMPF Modified to use xtime for time outs.
|
||||
// 23 May 01 WEKEMPF Removed "duration" timed_waits, as they are too
|
||||
// difficult to use with spurious wakeups.
|
||||
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
|
||||
|
||||
#endif // BOOST_CONDITION_WEK070601_HPP
|
||||
|
||||
21
include/boost/thread/condition_variable.hpp
Normal file
21
include/boost/thread/condition_variable.hpp
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef BOOST_THREAD_CONDITION_VARIABLE_HPP
|
||||
#define BOOST_THREAD_CONDITION_VARIABLE_HPP
|
||||
|
||||
// condition_variable.hpp
|
||||
//
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/platform.hpp>
|
||||
#if defined(BOOST_THREAD_PLATFORM_WIN32)
|
||||
#include <boost/thread/win32/condition_variable.hpp>
|
||||
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
|
||||
#include <boost/thread/pthread/condition_variable.hpp>
|
||||
#else
|
||||
#error "Boost threads unavailable on this platform"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -17,8 +17,7 @@
|
||||
# pragma warn -8066 // Unreachable code
|
||||
#endif
|
||||
|
||||
// insist on threading support being available:
|
||||
#include <boost/config/requires_threads.hpp>
|
||||
#include "platform.hpp"
|
||||
|
||||
// compatibility with the rest of Boost's auto-linking code:
|
||||
#if defined(BOOST_THREAD_DYN_DLL) || defined(BOOST_ALL_DYN_LINK)
|
||||
@@ -31,7 +30,7 @@
|
||||
#elif defined(BOOST_THREAD_USE_DLL) //Use dll
|
||||
#elif defined(BOOST_THREAD_USE_LIB) //Use lib
|
||||
#else //Use default
|
||||
# if defined(BOOST_HAS_WINTHREADS)
|
||||
# if defined(BOOST_THREAD_PLATFORM_WIN32)
|
||||
# if defined(BOOST_MSVC) || defined(BOOST_INTEL_WIN)
|
||||
//For compilers supporting auto-tss cleanup
|
||||
//with Boost.Threads lib, use Boost.Threads lib
|
||||
|
||||
60
include/boost/thread/detail/move.hpp
Normal file
60
include/boost/thread/detail/move.hpp
Normal file
@@ -0,0 +1,60 @@
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007-8 Anthony Williams
|
||||
|
||||
#ifndef BOOST_THREAD_MOVE_HPP
|
||||
#define BOOST_THREAD_MOVE_HPP
|
||||
|
||||
#ifndef BOOST_NO_SFINAE
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
#include <boost/type_traits/is_convertible.hpp>
|
||||
#endif
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template<typename T>
|
||||
struct thread_move_t
|
||||
{
|
||||
T& t;
|
||||
explicit thread_move_t(T& t_):
|
||||
t(t_)
|
||||
{}
|
||||
|
||||
T& operator*() const
|
||||
{
|
||||
return t;
|
||||
}
|
||||
|
||||
T* operator->() const
|
||||
{
|
||||
return &t;
|
||||
}
|
||||
private:
|
||||
void operator=(thread_move_t&);
|
||||
};
|
||||
}
|
||||
|
||||
#ifndef BOOST_NO_SFINAE
|
||||
template<typename T>
|
||||
typename enable_if<boost::is_convertible<T&,detail::thread_move_t<T> >, T >::type move(T& t)
|
||||
{
|
||||
return T(detail::thread_move_t<T>(t));
|
||||
}
|
||||
#endif
|
||||
|
||||
template<typename T>
|
||||
detail::thread_move_t<T> move(detail::thread_move_t<T> t)
|
||||
{
|
||||
return t;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
71
include/boost/thread/detail/platform.hpp
Normal file
71
include/boost/thread/detail/platform.hpp
Normal file
@@ -0,0 +1,71 @@
|
||||
// Copyright 2006 Roland Schwarz.
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// This work is a reimplementation along the design and ideas
|
||||
// of William E. Kempf.
|
||||
|
||||
#ifndef BOOST_THREAD_RS06040501_HPP
|
||||
#define BOOST_THREAD_RS06040501_HPP
|
||||
|
||||
// fetch compiler and platform configuration
|
||||
#include <boost/config.hpp>
|
||||
|
||||
// insist on threading support being available:
|
||||
#include <boost/config/requires_threads.hpp>
|
||||
|
||||
// choose platform
|
||||
#if defined(linux) || defined(__linux) || defined(__linux__)
|
||||
# define BOOST_THREAD_LINUX
|
||||
#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
|
||||
# define BOOST_THREAD_BSD
|
||||
#elif defined(sun) || defined(__sun)
|
||||
# define BOOST_THREAD_SOLARIS
|
||||
#elif defined(__sgi)
|
||||
# define BOOST_THREAD_IRIX
|
||||
#elif defined(__hpux)
|
||||
# define BOOST_THREAD_HPUX
|
||||
#elif defined(__CYGWIN__)
|
||||
# define BOOST_THREAD_CYGWIN
|
||||
#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
|
||||
# define BOOST_THREAD_WIN32
|
||||
#elif defined(__BEOS__)
|
||||
# define BOOST_THREAD_BEOS
|
||||
#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
|
||||
# define BOOST_THREAD_MACOS
|
||||
#elif defined(__IBMCPP__) || defined(_AIX)
|
||||
# define BOOST_THREAD_AIX
|
||||
#elif defined(__amigaos__)
|
||||
# define BOOST_THREAD_AMIGAOS
|
||||
#elif defined(__QNXNTO__)
|
||||
# define BOOST_THREAD_QNXNTO
|
||||
#elif defined(unix) || defined(__unix) || defined(_XOPEN_SOURCE) || defined(_POSIX_SOURCE)
|
||||
# if defined(BOOST_HAS_PTHREADS) && !defined(BOOST_THREAD_POSIX)
|
||||
# define BOOST_THREAD_POSIX
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// For every supported platform add a new entry into the dispatch table below.
|
||||
// BOOST_THREAD_POSIX is tested first, so on platforms where posix and native
|
||||
// threading is available, the user may choose, by defining BOOST_THREAD_POSIX
|
||||
// in her source. If a platform is known to support pthreads and no native
|
||||
// port of boost_thread is available just specify "pthread" in the
|
||||
// dispatcher table. If there is no entry for a platform but pthreads is
|
||||
// available on the platform, pthread is choosen as default. If nothing is
|
||||
// available the preprocessor will fail with a diagnostic message.
|
||||
|
||||
#if defined(BOOST_THREAD_POSIX)
|
||||
# define BOOST_THREAD_PLATFORM_PTHREAD
|
||||
#else
|
||||
# if defined(BOOST_THREAD_WIN32)
|
||||
# define BOOST_THREAD_PLATFORM_WIN32
|
||||
# elif defined(BOOST_HAS_PTHREADS)
|
||||
# define BOOST_THREAD_PLATFORM_PTHREAD
|
||||
# else
|
||||
# error "Sorry, no boost threads are available for this platform."
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif // BOOST_THREAD_RS06040501_HPP
|
||||
575
include/boost/thread/detail/thread.hpp
Normal file
575
include/boost/thread/detail/thread.hpp
Normal file
@@ -0,0 +1,575 @@
|
||||
#ifndef BOOST_THREAD_THREAD_COMMON_HPP
|
||||
#define BOOST_THREAD_THREAD_COMMON_HPP
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007-8 Anthony Williams
|
||||
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <ostream>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <boost/thread/detail/thread_heap_alloc.hpp>
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <list>
|
||||
#include <algorithm>
|
||||
#include <boost/ref.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <stdlib.h>
|
||||
#include <memory>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
#include <boost/type_traits/remove_reference.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4251)
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template<typename F>
|
||||
class thread_data:
|
||||
public detail::thread_data_base
|
||||
{
|
||||
public:
|
||||
#ifdef BOOST_HAS_RVALUE_REFS
|
||||
thread_data(F&& f_):
|
||||
f(static_cast<F&&>(f_))
|
||||
{}
|
||||
#else
|
||||
thread_data(F f_):
|
||||
f(f_)
|
||||
{}
|
||||
thread_data(detail::thread_move_t<F> f_):
|
||||
f(f_)
|
||||
{}
|
||||
#endif
|
||||
void run()
|
||||
{
|
||||
f();
|
||||
}
|
||||
private:
|
||||
F f;
|
||||
|
||||
void operator=(thread_data&);
|
||||
thread_data(thread_data&);
|
||||
};
|
||||
|
||||
template<typename F>
|
||||
class thread_data<boost::reference_wrapper<F> >:
|
||||
public detail::thread_data_base
|
||||
{
|
||||
private:
|
||||
F& f;
|
||||
|
||||
void operator=(thread_data&);
|
||||
thread_data(thread_data&);
|
||||
public:
|
||||
thread_data(boost::reference_wrapper<F> f_):
|
||||
f(f_)
|
||||
{}
|
||||
|
||||
void run()
|
||||
{
|
||||
f();
|
||||
}
|
||||
};
|
||||
|
||||
template<typename F>
|
||||
class thread_data<const boost::reference_wrapper<F> >:
|
||||
public detail::thread_data_base
|
||||
{
|
||||
private:
|
||||
F& f;
|
||||
void operator=(thread_data&);
|
||||
thread_data(thread_data&);
|
||||
public:
|
||||
thread_data(const boost::reference_wrapper<F> f_):
|
||||
f(f_)
|
||||
{}
|
||||
|
||||
void run()
|
||||
{
|
||||
f();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
class BOOST_THREAD_DECL thread
|
||||
{
|
||||
private:
|
||||
thread(thread&);
|
||||
thread& operator=(thread&);
|
||||
|
||||
void release_handle();
|
||||
|
||||
mutable boost::mutex thread_info_mutex;
|
||||
detail::thread_data_ptr thread_info;
|
||||
|
||||
void start_thread();
|
||||
|
||||
explicit thread(detail::thread_data_ptr data);
|
||||
|
||||
detail::thread_data_ptr get_thread_info() const;
|
||||
|
||||
#ifdef BOOST_HAS_RVALUE_REFS
|
||||
template<typename F>
|
||||
static inline detail::thread_data_ptr make_thread_info(F&& f)
|
||||
{
|
||||
return detail::thread_data_ptr(detail::heap_new<detail::thread_data<typename boost::remove_reference<F>::type> >(static_cast<F&&>(f)));
|
||||
}
|
||||
static inline detail::thread_data_ptr make_thread_info(void (*f)())
|
||||
{
|
||||
return detail::thread_data_ptr(detail::heap_new<detail::thread_data<void(*)()> >(f));
|
||||
}
|
||||
#else
|
||||
template<typename F>
|
||||
static inline detail::thread_data_ptr make_thread_info(F f)
|
||||
{
|
||||
return detail::thread_data_ptr(detail::heap_new<detail::thread_data<F> >(f));
|
||||
}
|
||||
template<typename F>
|
||||
static inline detail::thread_data_ptr make_thread_info(boost::detail::thread_move_t<F> f)
|
||||
{
|
||||
return detail::thread_data_ptr(detail::heap_new<detail::thread_data<F> >(f));
|
||||
}
|
||||
|
||||
struct dummy;
|
||||
#endif
|
||||
public:
|
||||
thread();
|
||||
~thread();
|
||||
|
||||
#ifdef BOOST_HAS_RVALUE_REFS
|
||||
template <class F>
|
||||
thread(F&& f):
|
||||
thread_info(make_thread_info(static_cast<F&&>(f)))
|
||||
{
|
||||
start_thread();
|
||||
}
|
||||
|
||||
thread(thread&& other)
|
||||
{
|
||||
thread_info.swap(other.thread_info);
|
||||
}
|
||||
|
||||
thread& operator=(thread&& other)
|
||||
{
|
||||
thread_info=other.thread_info;
|
||||
other.thread_info.reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
thread&& move()
|
||||
{
|
||||
return static_cast<thread&&>(*this);
|
||||
}
|
||||
|
||||
#else
|
||||
#ifdef BOOST_NO_SFINAE
|
||||
template <class F>
|
||||
explicit thread(F f):
|
||||
thread_info(make_thread_info(f))
|
||||
{
|
||||
start_thread();
|
||||
}
|
||||
#else
|
||||
template <class F>
|
||||
explicit thread(F f,typename disable_if<boost::is_convertible<F&,detail::thread_move_t<F> >, dummy* >::type=0):
|
||||
thread_info(make_thread_info(f))
|
||||
{
|
||||
start_thread();
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class F>
|
||||
explicit thread(detail::thread_move_t<F> f):
|
||||
thread_info(make_thread_info(f))
|
||||
{
|
||||
start_thread();
|
||||
}
|
||||
|
||||
thread(detail::thread_move_t<thread> x)
|
||||
{
|
||||
thread_info=x->thread_info;
|
||||
x->thread_info.reset();
|
||||
}
|
||||
|
||||
thread& operator=(detail::thread_move_t<thread> x)
|
||||
{
|
||||
thread new_thread(x);
|
||||
swap(new_thread);
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator detail::thread_move_t<thread>()
|
||||
{
|
||||
return move();
|
||||
}
|
||||
|
||||
detail::thread_move_t<thread> move()
|
||||
{
|
||||
detail::thread_move_t<thread> x(*this);
|
||||
return x;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
template <class F,class A1>
|
||||
thread(F f,A1 a1):
|
||||
thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1)))
|
||||
{
|
||||
start_thread();
|
||||
}
|
||||
template <class F,class A1,class A2>
|
||||
thread(F f,A1 a1,A2 a2):
|
||||
thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2)))
|
||||
{
|
||||
start_thread();
|
||||
}
|
||||
|
||||
template <class F,class A1,class A2,class A3>
|
||||
thread(F f,A1 a1,A2 a2,A3 a3):
|
||||
thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3)))
|
||||
{
|
||||
start_thread();
|
||||
}
|
||||
|
||||
template <class F,class A1,class A2,class A3,class A4>
|
||||
thread(F f,A1 a1,A2 a2,A3 a3,A4 a4):
|
||||
thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4)))
|
||||
{
|
||||
start_thread();
|
||||
}
|
||||
|
||||
template <class F,class A1,class A2,class A3,class A4,class A5>
|
||||
thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5):
|
||||
thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5)))
|
||||
{
|
||||
start_thread();
|
||||
}
|
||||
|
||||
template <class F,class A1,class A2,class A3,class A4,class A5,class A6>
|
||||
thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6):
|
||||
thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5,a6)))
|
||||
{
|
||||
start_thread();
|
||||
}
|
||||
|
||||
template <class F,class A1,class A2,class A3,class A4,class A5,class A6,class A7>
|
||||
thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7):
|
||||
thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5,a6,a7)))
|
||||
{
|
||||
start_thread();
|
||||
}
|
||||
|
||||
template <class F,class A1,class A2,class A3,class A4,class A5,class A6,class A7,class A8>
|
||||
thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7,A8 a8):
|
||||
thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5,a6,a7,a8)))
|
||||
{
|
||||
start_thread();
|
||||
}
|
||||
|
||||
template <class F,class A1,class A2,class A3,class A4,class A5,class A6,class A7,class A8,class A9>
|
||||
thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7,A8 a8,A9 a9):
|
||||
thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5,a6,a7,a8,a9)))
|
||||
{
|
||||
start_thread();
|
||||
}
|
||||
|
||||
void swap(thread& x)
|
||||
{
|
||||
thread_info.swap(x.thread_info);
|
||||
}
|
||||
|
||||
class id;
|
||||
id get_id() const;
|
||||
|
||||
|
||||
bool joinable() const;
|
||||
void join();
|
||||
bool timed_join(const system_time& wait_until);
|
||||
|
||||
template<typename TimeDuration>
|
||||
inline bool timed_join(TimeDuration const& rel_time)
|
||||
{
|
||||
return timed_join(get_system_time()+rel_time);
|
||||
}
|
||||
void detach();
|
||||
|
||||
static unsigned hardware_concurrency();
|
||||
|
||||
typedef detail::thread_data_base::native_handle_type native_handle_type;
|
||||
native_handle_type native_handle();
|
||||
|
||||
// backwards compatibility
|
||||
bool operator==(const thread& other) const;
|
||||
bool operator!=(const thread& other) const;
|
||||
|
||||
static inline void yield()
|
||||
{
|
||||
this_thread::yield();
|
||||
}
|
||||
|
||||
static inline void sleep(const system_time& xt)
|
||||
{
|
||||
this_thread::sleep(xt);
|
||||
}
|
||||
|
||||
// extensions
|
||||
void interrupt();
|
||||
bool interruption_requested() const;
|
||||
};
|
||||
|
||||
inline void swap(thread& lhs,thread& rhs)
|
||||
{
|
||||
return lhs.swap(rhs);
|
||||
}
|
||||
|
||||
#ifdef BOOST_HAS_RVALUE_REFS
|
||||
inline thread&& move(thread&& t)
|
||||
{
|
||||
return t;
|
||||
}
|
||||
#else
|
||||
inline thread move(detail::thread_move_t<thread> t)
|
||||
{
|
||||
return thread(t);
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace this_thread
|
||||
{
|
||||
class BOOST_THREAD_DECL disable_interruption
|
||||
{
|
||||
disable_interruption(const disable_interruption&);
|
||||
disable_interruption& operator=(const disable_interruption&);
|
||||
|
||||
bool interruption_was_enabled;
|
||||
friend class restore_interruption;
|
||||
public:
|
||||
disable_interruption();
|
||||
~disable_interruption();
|
||||
};
|
||||
|
||||
class BOOST_THREAD_DECL restore_interruption
|
||||
{
|
||||
restore_interruption(const restore_interruption&);
|
||||
restore_interruption& operator=(const restore_interruption&);
|
||||
public:
|
||||
explicit restore_interruption(disable_interruption& d);
|
||||
~restore_interruption();
|
||||
};
|
||||
|
||||
thread::id BOOST_THREAD_DECL get_id();
|
||||
|
||||
void BOOST_THREAD_DECL interruption_point();
|
||||
bool BOOST_THREAD_DECL interruption_enabled();
|
||||
bool BOOST_THREAD_DECL interruption_requested();
|
||||
|
||||
inline void sleep(xtime const& abs_time)
|
||||
{
|
||||
sleep(system_time(abs_time));
|
||||
}
|
||||
}
|
||||
|
||||
class thread::id
|
||||
{
|
||||
private:
|
||||
detail::thread_data_ptr thread_data;
|
||||
|
||||
id(detail::thread_data_ptr thread_data_):
|
||||
thread_data(thread_data_)
|
||||
{}
|
||||
friend class thread;
|
||||
friend id this_thread::get_id();
|
||||
public:
|
||||
id():
|
||||
thread_data()
|
||||
{}
|
||||
|
||||
bool operator==(const id& y) const
|
||||
{
|
||||
return thread_data==y.thread_data;
|
||||
}
|
||||
|
||||
bool operator!=(const id& y) const
|
||||
{
|
||||
return thread_data!=y.thread_data;
|
||||
}
|
||||
|
||||
bool operator<(const id& y) const
|
||||
{
|
||||
return thread_data<y.thread_data;
|
||||
}
|
||||
|
||||
bool operator>(const id& y) const
|
||||
{
|
||||
return y.thread_data<thread_data;
|
||||
}
|
||||
|
||||
bool operator<=(const id& y) const
|
||||
{
|
||||
return !(y.thread_data<thread_data);
|
||||
}
|
||||
|
||||
bool operator>=(const id& y) const
|
||||
{
|
||||
return !(thread_data<y.thread_data);
|
||||
}
|
||||
|
||||
template<class charT, class traits>
|
||||
friend std::basic_ostream<charT, traits>&
|
||||
operator<<(std::basic_ostream<charT, traits>& os, const id& x)
|
||||
{
|
||||
if(x.thread_data)
|
||||
{
|
||||
return os<<x.thread_data;
|
||||
}
|
||||
else
|
||||
{
|
||||
return os<<"{Not-any-thread}";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
inline bool thread::operator==(const thread& other) const
|
||||
{
|
||||
return get_id()==other.get_id();
|
||||
}
|
||||
|
||||
inline bool thread::operator!=(const thread& other) const
|
||||
{
|
||||
return get_id()!=other.get_id();
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct thread_exit_function_base
|
||||
{
|
||||
virtual ~thread_exit_function_base()
|
||||
{}
|
||||
virtual void operator()() const=0;
|
||||
};
|
||||
|
||||
template<typename F>
|
||||
struct thread_exit_function:
|
||||
thread_exit_function_base
|
||||
{
|
||||
F f;
|
||||
|
||||
thread_exit_function(F f_):
|
||||
f(f_)
|
||||
{}
|
||||
|
||||
void operator()() const
|
||||
{
|
||||
f();
|
||||
}
|
||||
};
|
||||
|
||||
void add_thread_exit_function(thread_exit_function_base*);
|
||||
}
|
||||
|
||||
namespace this_thread
|
||||
{
|
||||
template<typename F>
|
||||
void at_thread_exit(F f)
|
||||
{
|
||||
detail::thread_exit_function_base* const thread_exit_func=detail::heap_new<detail::thread_exit_function<F> >(f);
|
||||
detail::add_thread_exit_function(thread_exit_func);
|
||||
}
|
||||
}
|
||||
|
||||
class thread_group:
|
||||
private noncopyable
|
||||
{
|
||||
public:
|
||||
~thread_group()
|
||||
{
|
||||
for(std::list<thread*>::iterator it=threads.begin(),end=threads.end();
|
||||
it!=end;
|
||||
++it)
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
thread* create_thread(F threadfunc)
|
||||
{
|
||||
boost::lock_guard<mutex> guard(m);
|
||||
std::auto_ptr<thread> new_thread(new thread(threadfunc));
|
||||
threads.push_back(new_thread.get());
|
||||
return new_thread.release();
|
||||
}
|
||||
|
||||
void add_thread(thread* thrd)
|
||||
{
|
||||
if(thrd)
|
||||
{
|
||||
boost::lock_guard<mutex> guard(m);
|
||||
threads.push_back(thrd);
|
||||
}
|
||||
}
|
||||
|
||||
void remove_thread(thread* thrd)
|
||||
{
|
||||
boost::lock_guard<mutex> guard(m);
|
||||
std::list<thread*>::iterator const it=std::find(threads.begin(),threads.end(),thrd);
|
||||
if(it!=threads.end())
|
||||
{
|
||||
threads.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
void join_all()
|
||||
{
|
||||
boost::lock_guard<mutex> guard(m);
|
||||
|
||||
for(std::list<thread*>::iterator it=threads.begin(),end=threads.end();
|
||||
it!=end;
|
||||
++it)
|
||||
{
|
||||
(*it)->join();
|
||||
}
|
||||
}
|
||||
|
||||
void interrupt_all()
|
||||
{
|
||||
boost::lock_guard<mutex> guard(m);
|
||||
|
||||
for(std::list<thread*>::iterator it=threads.begin(),end=threads.end();
|
||||
it!=end;
|
||||
++it)
|
||||
{
|
||||
(*it)->interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
size_t size() const
|
||||
{
|
||||
boost::lock_guard<mutex> guard(m);
|
||||
return threads.size();
|
||||
}
|
||||
|
||||
private:
|
||||
std::list<thread*> threads;
|
||||
mutable mutex m;
|
||||
};
|
||||
}
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
23
include/boost/thread/detail/thread_heap_alloc.hpp
Normal file
23
include/boost/thread/detail/thread_heap_alloc.hpp
Normal file
@@ -0,0 +1,23 @@
|
||||
#ifndef BOOST_THREAD_THREAD_HEAP_ALLOC_HPP
|
||||
#define BOOST_THREAD_THREAD_HEAP_ALLOC_HPP
|
||||
|
||||
// thread_heap_alloc.hpp
|
||||
//
|
||||
// (C) Copyright 2008 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/platform.hpp>
|
||||
|
||||
#if defined(BOOST_THREAD_PLATFORM_WIN32)
|
||||
#include <boost/thread/win32/thread_heap_alloc.hpp>
|
||||
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
|
||||
#include <boost/thread/pthread/thread_heap_alloc.hpp>
|
||||
#else
|
||||
#error "Boost threads unavailable on this platform"
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
|
||||
typedef void (__cdecl *thread_exit_handler)(void);
|
||||
@@ -59,7 +61,7 @@
|
||||
//a method for doing so has been discovered.
|
||||
//May be omitted; may be called multiple times.
|
||||
|
||||
extern "C" BOOST_THREAD_DECL void on_thread_exit(void);
|
||||
extern "C" BOOST_THREAD_DECL void __cdecl on_thread_exit(void);
|
||||
//Function to be called just be fore a thread ends
|
||||
//in an exe or dll that uses Boost.Threads.
|
||||
//Must be called in the context of the thread
|
||||
@@ -67,7 +69,7 @@
|
||||
//Called automatically by Boost.Threads when
|
||||
//a method for doing so has been discovered.
|
||||
//Must not be omitted; may be called multiple times.
|
||||
|
||||
|
||||
extern "C" void tss_cleanup_implemented(void);
|
||||
//Dummy function used both to detect whether tss cleanup
|
||||
//cleanup has been implemented and to force
|
||||
@@ -75,4 +77,6 @@
|
||||
|
||||
#endif //defined(BOOST_HAS_WINTHREADS)
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif //!defined(BOOST_TLS_HOOKS_HPP)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
// Copyright (C) 2007-8 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -18,7 +19,13 @@
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace boost {
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
class BOOST_THREAD_DECL thread_interrupted
|
||||
{};
|
||||
|
||||
class BOOST_THREAD_DECL thread_exception : public std::exception
|
||||
{
|
||||
@@ -35,6 +42,17 @@ private:
|
||||
int m_sys_err;
|
||||
};
|
||||
|
||||
class condition_error:
|
||||
public std::exception
|
||||
{
|
||||
public:
|
||||
const char* what() const throw()
|
||||
{
|
||||
return "Condition error";
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class BOOST_THREAD_DECL lock_error : public thread_exception
|
||||
{
|
||||
public:
|
||||
@@ -87,6 +105,8 @@ public:
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif // BOOST_THREAD_CONFIG_PDM070801_H
|
||||
|
||||
// Change log:
|
||||
|
||||
1430
include/boost/thread/locks.hpp
Normal file
1430
include/boost/thread/locks.hpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,170 +1,21 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
#ifndef BOOST_THREAD_MUTEX_HPP
|
||||
#define BOOST_THREAD_MUTEX_HPP
|
||||
|
||||
// mutex.hpp
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_MUTEX_WEK070601_HPP
|
||||
#define BOOST_MUTEX_WEK070601_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/thread/detail/lock.hpp>
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
# include <pthread.h>
|
||||
#include <boost/thread/detail/platform.hpp>
|
||||
#if defined(BOOST_THREAD_PLATFORM_WIN32)
|
||||
#include <boost/thread/win32/mutex.hpp>
|
||||
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
|
||||
#include <boost/thread/pthread/mutex.hpp>
|
||||
#else
|
||||
#error "Boost threads unavailable on this platform"
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_HAS_MPTASKS)
|
||||
# include "scoped_critical_region.hpp"
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
struct xtime;
|
||||
// disable warnings about non dll import
|
||||
// see: http://www.boost.org/more/separate_compilation.html#dlls
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4251 4231 4660 4275)
|
||||
#endif
|
||||
|
||||
class BOOST_THREAD_DECL mutex
|
||||
: private noncopyable
|
||||
{
|
||||
public:
|
||||
friend class detail::thread::lock_ops<mutex>;
|
||||
|
||||
typedef detail::thread::scoped_lock<mutex> scoped_lock;
|
||||
|
||||
mutex();
|
||||
~mutex();
|
||||
|
||||
private:
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
typedef void* cv_state;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
struct cv_state
|
||||
{
|
||||
pthread_mutex_t* pmutex;
|
||||
};
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
struct cv_state
|
||||
{
|
||||
};
|
||||
#endif
|
||||
void do_lock();
|
||||
void do_unlock();
|
||||
void do_lock(cv_state& state);
|
||||
void do_unlock(cv_state& state);
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
void* m_mutex;
|
||||
bool m_critical_section;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
pthread_mutex_t m_mutex;
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
threads::mac::detail::scoped_critical_region m_mutex;
|
||||
threads::mac::detail::scoped_critical_region m_mutex_mutex;
|
||||
#endif
|
||||
};
|
||||
|
||||
class BOOST_THREAD_DECL try_mutex
|
||||
: private noncopyable
|
||||
{
|
||||
public:
|
||||
friend class detail::thread::lock_ops<try_mutex>;
|
||||
|
||||
typedef detail::thread::scoped_lock<try_mutex> scoped_lock;
|
||||
typedef detail::thread::scoped_try_lock<try_mutex> scoped_try_lock;
|
||||
|
||||
try_mutex();
|
||||
~try_mutex();
|
||||
|
||||
private:
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
typedef void* cv_state;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
struct cv_state
|
||||
{
|
||||
pthread_mutex_t* pmutex;
|
||||
};
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
struct cv_state
|
||||
{
|
||||
};
|
||||
#endif
|
||||
void do_lock();
|
||||
bool do_trylock();
|
||||
void do_unlock();
|
||||
void do_lock(cv_state& state);
|
||||
void do_unlock(cv_state& state);
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
void* m_mutex;
|
||||
bool m_critical_section;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
pthread_mutex_t m_mutex;
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
threads::mac::detail::scoped_critical_region m_mutex;
|
||||
threads::mac::detail::scoped_critical_region m_mutex_mutex;
|
||||
#endif
|
||||
};
|
||||
|
||||
class BOOST_THREAD_DECL timed_mutex
|
||||
: private noncopyable
|
||||
{
|
||||
public:
|
||||
friend class detail::thread::lock_ops<timed_mutex>;
|
||||
|
||||
typedef detail::thread::scoped_lock<timed_mutex> scoped_lock;
|
||||
typedef detail::thread::scoped_try_lock<timed_mutex> scoped_try_lock;
|
||||
typedef detail::thread::scoped_timed_lock<timed_mutex> scoped_timed_lock;
|
||||
|
||||
timed_mutex();
|
||||
~timed_mutex();
|
||||
|
||||
private:
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
typedef void* cv_state;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
struct cv_state
|
||||
{
|
||||
pthread_mutex_t* pmutex;
|
||||
};
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
struct cv_state
|
||||
{
|
||||
};
|
||||
#endif
|
||||
void do_lock();
|
||||
bool do_trylock();
|
||||
bool do_timedlock(const xtime& xt);
|
||||
void do_unlock();
|
||||
void do_lock(cv_state& state);
|
||||
void do_unlock(cv_state& state);
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
void* m_mutex;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
pthread_mutex_t m_mutex;
|
||||
pthread_cond_t m_condition;
|
||||
bool m_locked;
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
threads::mac::detail::scoped_critical_region m_mutex;
|
||||
threads::mac::detail::scoped_critical_region m_mutex_mutex;
|
||||
#endif
|
||||
};
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
} // namespace boost
|
||||
|
||||
// Change Log:
|
||||
// 8 Feb 01 WEKEMPF Initial version.
|
||||
// 22 May 01 WEKEMPF Modified to use xtime for time outs. Factored out
|
||||
// to three classes, mutex, try_mutex and timed_mutex.
|
||||
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
|
||||
|
||||
#endif // BOOST_MUTEX_WEK070601_HPP
|
||||
|
||||
@@ -1,37 +1,33 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
#ifndef BOOST_THREAD_ONCE_HPP
|
||||
#define BOOST_THREAD_ONCE_HPP
|
||||
|
||||
// once.hpp
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2006-7 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_ONCE_WEK080101_HPP
|
||||
#define BOOST_ONCE_WEK080101_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
# include <pthread.h>
|
||||
#include <boost/thread/detail/platform.hpp>
|
||||
#if defined(BOOST_THREAD_PLATFORM_WIN32)
|
||||
#include <boost/thread/win32/once.hpp>
|
||||
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
|
||||
#include <boost/thread/pthread/once.hpp>
|
||||
#else
|
||||
#error "Boost threads unavailable on this platform"
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
namespace boost
|
||||
{
|
||||
inline void call_once(void (*func)(),once_flag& flag)
|
||||
{
|
||||
call_once(flag,func);
|
||||
}
|
||||
}
|
||||
|
||||
typedef pthread_once_t once_flag;
|
||||
#define BOOST_ONCE_INIT PTHREAD_ONCE_INIT
|
||||
|
||||
#elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||
|
||||
typedef long once_flag;
|
||||
#define BOOST_ONCE_INIT 0
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
|
||||
void BOOST_THREAD_DECL call_once(void (*func)(), once_flag& flag);
|
||||
|
||||
} // namespace boost
|
||||
|
||||
// Change Log:
|
||||
// 1 Aug 01 WEKEMPF Initial version.
|
||||
|
||||
#endif // BOOST_ONCE_WEK080101_HPP
|
||||
|
||||
176
include/boost/thread/pthread/condition_variable.hpp
Normal file
176
include/boost/thread/pthread/condition_variable.hpp
Normal file
@@ -0,0 +1,176 @@
|
||||
#ifndef BOOST_THREAD_CONDITION_VARIABLE_PTHREAD_HPP
|
||||
#define BOOST_THREAD_CONDITION_VARIABLE_PTHREAD_HPP
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007-8 Anthony Williams
|
||||
|
||||
#include "timespec.hpp"
|
||||
#include "pthread_mutex_scoped_lock.hpp"
|
||||
#include "thread_data.hpp"
|
||||
#include "condition_variable_fwd.hpp"
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
inline void condition_variable::wait(unique_lock<mutex>& m)
|
||||
{
|
||||
detail::interruption_checker check_for_interruption(&cond);
|
||||
BOOST_VERIFY(!pthread_cond_wait(&cond,m.mutex()->native_handle()));
|
||||
}
|
||||
|
||||
inline bool condition_variable::timed_wait(unique_lock<mutex>& m,boost::system_time const& wait_until)
|
||||
{
|
||||
detail::interruption_checker check_for_interruption(&cond);
|
||||
struct timespec const timeout=detail::get_timespec(wait_until);
|
||||
int const cond_res=pthread_cond_timedwait(&cond,m.mutex()->native_handle(),&timeout);
|
||||
if(cond_res==ETIMEDOUT)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
BOOST_ASSERT(!cond_res);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void condition_variable::notify_one()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_cond_signal(&cond));
|
||||
}
|
||||
|
||||
inline void condition_variable::notify_all()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_cond_broadcast(&cond));
|
||||
}
|
||||
|
||||
class condition_variable_any
|
||||
{
|
||||
pthread_mutex_t internal_mutex;
|
||||
pthread_cond_t cond;
|
||||
|
||||
condition_variable_any(condition_variable&);
|
||||
condition_variable_any& operator=(condition_variable&);
|
||||
|
||||
public:
|
||||
condition_variable_any()
|
||||
{
|
||||
int const res=pthread_mutex_init(&internal_mutex,NULL);
|
||||
if(res)
|
||||
{
|
||||
throw thread_resource_error();
|
||||
}
|
||||
int const res2=pthread_cond_init(&cond,NULL);
|
||||
if(res2)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex));
|
||||
throw thread_resource_error();
|
||||
}
|
||||
}
|
||||
~condition_variable_any()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex));
|
||||
BOOST_VERIFY(!pthread_cond_destroy(&cond));
|
||||
}
|
||||
|
||||
template<typename lock_type>
|
||||
void wait(lock_type& m)
|
||||
{
|
||||
int res=0;
|
||||
{
|
||||
detail::interruption_checker check_for_interruption(&cond);
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);
|
||||
m.unlock();
|
||||
res=pthread_cond_wait(&cond,&internal_mutex);
|
||||
}
|
||||
m.lock();
|
||||
}
|
||||
if(res)
|
||||
{
|
||||
throw condition_error();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename lock_type,typename predicate_type>
|
||||
void wait(lock_type& m,predicate_type pred)
|
||||
{
|
||||
while(!pred()) wait(m);
|
||||
}
|
||||
|
||||
template<typename lock_type>
|
||||
bool timed_wait(lock_type& m,boost::system_time const& wait_until)
|
||||
{
|
||||
struct timespec const timeout=detail::get_timespec(wait_until);
|
||||
int res=0;
|
||||
{
|
||||
detail::interruption_checker check_for_interruption(&cond);
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);
|
||||
m.unlock();
|
||||
res=pthread_cond_timedwait(&cond,&internal_mutex,&timeout);
|
||||
}
|
||||
m.lock();
|
||||
}
|
||||
if(res==ETIMEDOUT)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(res)
|
||||
{
|
||||
throw condition_error();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
template<typename lock_type>
|
||||
bool timed_wait(lock_type& m,xtime const& wait_until)
|
||||
{
|
||||
return timed_wait(m,system_time(wait_until));
|
||||
}
|
||||
|
||||
template<typename lock_type,typename duration_type>
|
||||
bool timed_wait(lock_type& m,duration_type const& wait_duration)
|
||||
{
|
||||
return timed_wait(m,get_system_time()+wait_duration);
|
||||
}
|
||||
|
||||
template<typename lock_type,typename predicate_type>
|
||||
bool timed_wait(lock_type& m,boost::system_time const& wait_until,predicate_type pred)
|
||||
{
|
||||
while (!pred())
|
||||
{
|
||||
if(!timed_wait(m, wait_until))
|
||||
return pred();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename lock_type,typename predicate_type>
|
||||
bool timed_wait(lock_type& m,xtime const& wait_until,predicate_type pred)
|
||||
{
|
||||
return timed_wait(m,system_time(wait_until),pred);
|
||||
}
|
||||
|
||||
template<typename lock_type,typename duration_type,typename predicate_type>
|
||||
bool timed_wait(lock_type& m,duration_type const& wait_duration,predicate_type pred)
|
||||
{
|
||||
return timed_wait(m,get_system_time()+wait_duration,pred);
|
||||
}
|
||||
|
||||
void notify_one()
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);
|
||||
BOOST_VERIFY(!pthread_cond_signal(&cond));
|
||||
}
|
||||
|
||||
void notify_all()
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);
|
||||
BOOST_VERIFY(!pthread_cond_broadcast(&cond));
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
97
include/boost/thread/pthread/condition_variable_fwd.hpp
Normal file
97
include/boost/thread/pthread/condition_variable_fwd.hpp
Normal file
@@ -0,0 +1,97 @@
|
||||
#ifndef BOOST_THREAD_PTHREAD_CONDITION_VARIABLE_FWD_HPP
|
||||
#define BOOST_THREAD_PTHREAD_CONDITION_VARIABLE_FWD_HPP
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007-8 Anthony Williams
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <pthread.h>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
class condition_variable
|
||||
{
|
||||
private:
|
||||
pthread_cond_t cond;
|
||||
|
||||
condition_variable(condition_variable&);
|
||||
condition_variable& operator=(condition_variable&);
|
||||
|
||||
public:
|
||||
condition_variable()
|
||||
{
|
||||
int const res=pthread_cond_init(&cond,NULL);
|
||||
if(res)
|
||||
{
|
||||
throw thread_resource_error();
|
||||
}
|
||||
}
|
||||
~condition_variable()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_cond_destroy(&cond));
|
||||
}
|
||||
|
||||
void wait(unique_lock<mutex>& m);
|
||||
|
||||
template<typename predicate_type>
|
||||
void wait(unique_lock<mutex>& m,predicate_type pred)
|
||||
{
|
||||
while(!pred()) wait(m);
|
||||
}
|
||||
|
||||
bool timed_wait(unique_lock<mutex>& m,boost::system_time const& wait_until);
|
||||
bool timed_wait(unique_lock<mutex>& m,xtime const& wait_until)
|
||||
{
|
||||
return timed_wait(m,system_time(wait_until));
|
||||
}
|
||||
|
||||
template<typename duration_type>
|
||||
bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration)
|
||||
{
|
||||
return timed_wait(m,get_system_time()+wait_duration);
|
||||
}
|
||||
|
||||
template<typename predicate_type>
|
||||
bool timed_wait(unique_lock<mutex>& m,boost::system_time const& wait_until,predicate_type pred)
|
||||
{
|
||||
while (!pred())
|
||||
{
|
||||
if(!timed_wait(m, wait_until))
|
||||
return pred();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename predicate_type>
|
||||
bool timed_wait(unique_lock<mutex>& m,xtime const& wait_until,predicate_type pred)
|
||||
{
|
||||
return timed_wait(m,system_time(wait_until),pred);
|
||||
}
|
||||
|
||||
template<typename duration_type,typename predicate_type>
|
||||
bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration,predicate_type pred)
|
||||
{
|
||||
return timed_wait(m,get_system_time()+wait_duration,pred);
|
||||
}
|
||||
|
||||
typedef pthread_cond_t* native_handle_type;
|
||||
native_handle_type native_handle()
|
||||
{
|
||||
return &cond;
|
||||
}
|
||||
|
||||
void notify_one();
|
||||
void notify_all();
|
||||
};
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
210
include/boost/thread/pthread/mutex.hpp
Normal file
210
include/boost/thread/pthread/mutex.hpp
Normal file
@@ -0,0 +1,210 @@
|
||||
#ifndef BOOST_THREAD_PTHREAD_MUTEX_HPP
|
||||
#define BOOST_THREAD_PTHREAD_MUTEX_HPP
|
||||
// (C) Copyright 2007-8 Anthony Williams
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <pthread.h>
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <errno.h>
|
||||
#include "timespec.hpp"
|
||||
#include "pthread_mutex_scoped_lock.hpp"
|
||||
|
||||
#ifdef _POSIX_TIMEOUTS
|
||||
#if _POSIX_TIMEOUTS >= 0
|
||||
#define BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
class mutex:
|
||||
boost::noncopyable
|
||||
{
|
||||
private:
|
||||
pthread_mutex_t m;
|
||||
public:
|
||||
mutex()
|
||||
{
|
||||
int const res=pthread_mutex_init(&m,NULL);
|
||||
if(res)
|
||||
{
|
||||
throw thread_resource_error();
|
||||
}
|
||||
}
|
||||
~mutex()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_destroy(&m));
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_lock(&m));
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_unlock(&m));
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
int const res=pthread_mutex_trylock(&m);
|
||||
BOOST_ASSERT(!res || res==EBUSY);
|
||||
return !res;
|
||||
}
|
||||
|
||||
typedef pthread_mutex_t* native_handle_type;
|
||||
native_handle_type native_handle()
|
||||
{
|
||||
return &m;
|
||||
}
|
||||
|
||||
typedef unique_lock<mutex> scoped_lock;
|
||||
typedef detail::try_lock_wrapper<mutex> scoped_try_lock;
|
||||
};
|
||||
|
||||
typedef mutex try_mutex;
|
||||
|
||||
class timed_mutex:
|
||||
boost::noncopyable
|
||||
{
|
||||
private:
|
||||
pthread_mutex_t m;
|
||||
#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
pthread_cond_t cond;
|
||||
bool is_locked;
|
||||
#endif
|
||||
public:
|
||||
timed_mutex()
|
||||
{
|
||||
int const res=pthread_mutex_init(&m,NULL);
|
||||
if(res)
|
||||
{
|
||||
throw thread_resource_error();
|
||||
}
|
||||
#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
int const res2=pthread_cond_init(&cond,NULL);
|
||||
if(res2)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_destroy(&m));
|
||||
throw thread_resource_error();
|
||||
}
|
||||
is_locked=false;
|
||||
#endif
|
||||
}
|
||||
~timed_mutex()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_destroy(&m));
|
||||
#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
BOOST_VERIFY(!pthread_cond_destroy(&cond));
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename TimeDuration>
|
||||
bool timed_lock(TimeDuration const & relative_time)
|
||||
{
|
||||
return timed_lock(get_system_time()+relative_time);
|
||||
}
|
||||
bool timed_lock(boost::xtime const & absolute_time)
|
||||
{
|
||||
return timed_lock(system_time(absolute_time));
|
||||
}
|
||||
|
||||
#ifdef BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
void lock()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_lock(&m));
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_unlock(&m));
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
int const res=pthread_mutex_trylock(&m);
|
||||
BOOST_ASSERT(!res || res==EBUSY);
|
||||
return !res;
|
||||
}
|
||||
bool timed_lock(system_time const & abs_time)
|
||||
{
|
||||
struct timespec const timeout=detail::get_timespec(abs_time);
|
||||
int const res=pthread_mutex_timedlock(&m,&timeout);
|
||||
BOOST_ASSERT(!res || res==ETIMEDOUT);
|
||||
return !res;
|
||||
}
|
||||
|
||||
typedef pthread_mutex_t* native_handle_type;
|
||||
native_handle_type native_handle()
|
||||
{
|
||||
return &m;
|
||||
}
|
||||
|
||||
#else
|
||||
void lock()
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
|
||||
while(is_locked)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_cond_wait(&cond,&m));
|
||||
}
|
||||
is_locked=true;
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
|
||||
is_locked=false;
|
||||
BOOST_VERIFY(!pthread_cond_signal(&cond));
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
|
||||
if(is_locked)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
is_locked=true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool timed_lock(system_time const & abs_time)
|
||||
{
|
||||
struct timespec const timeout=detail::get_timespec(abs_time);
|
||||
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
|
||||
while(is_locked)
|
||||
{
|
||||
int const cond_res=pthread_cond_timedwait(&cond,&m,&timeout);
|
||||
if(cond_res==ETIMEDOUT)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
BOOST_ASSERT(!cond_res);
|
||||
}
|
||||
is_locked=true;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef unique_lock<timed_mutex> scoped_timed_lock;
|
||||
typedef detail::try_lock_wrapper<timed_mutex> scoped_try_lock;
|
||||
typedef scoped_timed_lock scoped_lock;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
|
||||
#endif
|
||||
90
include/boost/thread/pthread/once.hpp
Normal file
90
include/boost/thread/pthread/once.hpp
Normal file
@@ -0,0 +1,90 @@
|
||||
#ifndef BOOST_THREAD_PTHREAD_ONCE_HPP
|
||||
#define BOOST_THREAD_PTHREAD_ONCE_HPP
|
||||
|
||||
// once.hpp
|
||||
//
|
||||
// (C) Copyright 2007-8 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <pthread.h>
|
||||
#include <boost/assert.hpp>
|
||||
#include "pthread_mutex_scoped_lock.hpp"
|
||||
#include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
struct once_flag
|
||||
{
|
||||
boost::uintmax_t epoch;
|
||||
};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
BOOST_THREAD_DECL boost::uintmax_t& get_once_per_thread_epoch();
|
||||
BOOST_THREAD_DECL extern boost::uintmax_t once_global_epoch;
|
||||
BOOST_THREAD_DECL extern pthread_mutex_t once_epoch_mutex;
|
||||
BOOST_THREAD_DECL extern pthread_cond_t once_epoch_cv;
|
||||
}
|
||||
|
||||
#define BOOST_ONCE_INITIAL_FLAG_VALUE 0
|
||||
#define BOOST_ONCE_INIT {BOOST_ONCE_INITIAL_FLAG_VALUE}
|
||||
|
||||
|
||||
// Based on Mike Burrows fast_pthread_once algorithm as described in
|
||||
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2444.html
|
||||
template<typename Function>
|
||||
void call_once(once_flag& flag,Function f)
|
||||
{
|
||||
static boost::uintmax_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE;
|
||||
static boost::uintmax_t const being_initialized=uninitialized_flag+1;
|
||||
boost::uintmax_t const epoch=flag.epoch;
|
||||
boost::uintmax_t& this_thread_epoch=detail::get_once_per_thread_epoch();
|
||||
|
||||
if(epoch<this_thread_epoch)
|
||||
{
|
||||
pthread::pthread_mutex_scoped_lock lk(&detail::once_epoch_mutex);
|
||||
|
||||
while(flag.epoch<=being_initialized)
|
||||
{
|
||||
if(flag.epoch==uninitialized_flag)
|
||||
{
|
||||
flag.epoch=being_initialized;
|
||||
try
|
||||
{
|
||||
pthread::pthread_mutex_scoped_unlock relocker(&detail::once_epoch_mutex);
|
||||
f();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
flag.epoch=uninitialized_flag;
|
||||
BOOST_VERIFY(!pthread_cond_broadcast(&detail::once_epoch_cv));
|
||||
throw;
|
||||
}
|
||||
flag.epoch=--detail::once_global_epoch;
|
||||
BOOST_VERIFY(!pthread_cond_broadcast(&detail::once_epoch_cv));
|
||||
}
|
||||
else
|
||||
{
|
||||
while(flag.epoch==being_initialized)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_cond_wait(&detail::once_epoch_cv,&detail::once_epoch_mutex));
|
||||
}
|
||||
}
|
||||
}
|
||||
this_thread_epoch=detail::once_global_epoch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
54
include/boost/thread/pthread/pthread_mutex_scoped_lock.hpp
Normal file
54
include/boost/thread/pthread/pthread_mutex_scoped_lock.hpp
Normal file
@@ -0,0 +1,54 @@
|
||||
#ifndef BOOST_PTHREAD_MUTEX_SCOPED_LOCK_HPP
|
||||
#define BOOST_PTHREAD_MUTEX_SCOPED_LOCK_HPP
|
||||
// (C) Copyright 2007-8 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <pthread.h>
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace pthread
|
||||
{
|
||||
class pthread_mutex_scoped_lock
|
||||
{
|
||||
pthread_mutex_t* m;
|
||||
public:
|
||||
explicit pthread_mutex_scoped_lock(pthread_mutex_t* m_):
|
||||
m(m_)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_lock(m));
|
||||
}
|
||||
~pthread_mutex_scoped_lock()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_unlock(m));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class pthread_mutex_scoped_unlock
|
||||
{
|
||||
pthread_mutex_t* m;
|
||||
public:
|
||||
explicit pthread_mutex_scoped_unlock(pthread_mutex_t* m_):
|
||||
m(m_)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_unlock(m));
|
||||
}
|
||||
~pthread_mutex_scoped_unlock()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_lock(m));
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
266
include/boost/thread/pthread/recursive_mutex.hpp
Normal file
266
include/boost/thread/pthread/recursive_mutex.hpp
Normal file
@@ -0,0 +1,266 @@
|
||||
#ifndef BOOST_THREAD_PTHREAD_RECURSIVE_MUTEX_HPP
|
||||
#define BOOST_THREAD_PTHREAD_RECURSIVE_MUTEX_HPP
|
||||
// (C) Copyright 2007-8 Anthony Williams
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <pthread.h>
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <boost/date_time/posix_time/conversion.hpp>
|
||||
#include <errno.h>
|
||||
#include "timespec.hpp"
|
||||
#include "pthread_mutex_scoped_lock.hpp"
|
||||
|
||||
#ifdef _POSIX_TIMEOUTS
|
||||
#if _POSIX_TIMEOUTS >= 0
|
||||
#define BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
class recursive_mutex:
|
||||
boost::noncopyable
|
||||
{
|
||||
private:
|
||||
pthread_mutex_t m;
|
||||
public:
|
||||
recursive_mutex()
|
||||
{
|
||||
pthread_mutexattr_t attr;
|
||||
|
||||
int const init_attr_res=pthread_mutexattr_init(&attr);
|
||||
if(init_attr_res)
|
||||
{
|
||||
throw thread_resource_error();
|
||||
}
|
||||
int const set_attr_res=pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE);
|
||||
if(set_attr_res)
|
||||
{
|
||||
throw thread_resource_error();
|
||||
}
|
||||
|
||||
int const res=pthread_mutex_init(&m,&attr);
|
||||
if(res)
|
||||
{
|
||||
throw thread_resource_error();
|
||||
}
|
||||
BOOST_VERIFY(!pthread_mutexattr_destroy(&attr));
|
||||
}
|
||||
~recursive_mutex()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_destroy(&m));
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_lock(&m));
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_unlock(&m));
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
int const res=pthread_mutex_trylock(&m);
|
||||
BOOST_ASSERT(!res || res==EBUSY);
|
||||
return !res;
|
||||
}
|
||||
|
||||
typedef pthread_mutex_t* native_handle_type;
|
||||
native_handle_type native_handle()
|
||||
{
|
||||
return &m;
|
||||
}
|
||||
|
||||
typedef unique_lock<recursive_mutex> scoped_lock;
|
||||
typedef detail::try_lock_wrapper<recursive_mutex> scoped_try_lock;
|
||||
};
|
||||
|
||||
typedef recursive_mutex recursive_try_mutex;
|
||||
|
||||
class recursive_timed_mutex:
|
||||
boost::noncopyable
|
||||
{
|
||||
private:
|
||||
pthread_mutex_t m;
|
||||
#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
pthread_cond_t cond;
|
||||
bool is_locked;
|
||||
pthread_t owner;
|
||||
unsigned count;
|
||||
#endif
|
||||
public:
|
||||
recursive_timed_mutex()
|
||||
{
|
||||
#ifdef BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
pthread_mutexattr_t attr;
|
||||
|
||||
int const init_attr_res=pthread_mutexattr_init(&attr);
|
||||
if(init_attr_res)
|
||||
{
|
||||
throw thread_resource_error();
|
||||
}
|
||||
int const set_attr_res=pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE);
|
||||
if(set_attr_res)
|
||||
{
|
||||
throw thread_resource_error();
|
||||
}
|
||||
|
||||
int const res=pthread_mutex_init(&m,&attr);
|
||||
if(res)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutexattr_destroy(&attr));
|
||||
throw thread_resource_error();
|
||||
}
|
||||
BOOST_VERIFY(!pthread_mutexattr_destroy(&attr));
|
||||
#else
|
||||
int const res=pthread_mutex_init(&m,NULL);
|
||||
if(res)
|
||||
{
|
||||
throw thread_resource_error();
|
||||
}
|
||||
int const res2=pthread_cond_init(&cond,NULL);
|
||||
if(res2)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_destroy(&m));
|
||||
throw thread_resource_error();
|
||||
}
|
||||
is_locked=false;
|
||||
count=0;
|
||||
#endif
|
||||
}
|
||||
~recursive_timed_mutex()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_destroy(&m));
|
||||
#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
BOOST_VERIFY(!pthread_cond_destroy(&cond));
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename TimeDuration>
|
||||
bool timed_lock(TimeDuration const & relative_time)
|
||||
{
|
||||
return timed_lock(get_system_time()+relative_time);
|
||||
}
|
||||
|
||||
#ifdef BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
void lock()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_lock(&m));
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_unlock(&m));
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
int const res=pthread_mutex_trylock(&m);
|
||||
BOOST_ASSERT(!res || res==EBUSY);
|
||||
return !res;
|
||||
}
|
||||
bool timed_lock(system_time const & abs_time)
|
||||
{
|
||||
struct timespec const timeout=detail::get_timespec(abs_time);
|
||||
int const res=pthread_mutex_timedlock(&m,&timeout);
|
||||
BOOST_ASSERT(!res || res==ETIMEDOUT);
|
||||
return !res;
|
||||
}
|
||||
|
||||
typedef pthread_mutex_t* native_handle_type;
|
||||
native_handle_type native_handle()
|
||||
{
|
||||
return &m;
|
||||
}
|
||||
|
||||
#else
|
||||
void lock()
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
|
||||
if(is_locked && pthread_equal(owner,pthread_self()))
|
||||
{
|
||||
++count;
|
||||
return;
|
||||
}
|
||||
|
||||
while(is_locked)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_cond_wait(&cond,&m));
|
||||
}
|
||||
is_locked=true;
|
||||
++count;
|
||||
owner=pthread_self();
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
|
||||
if(!--count)
|
||||
{
|
||||
is_locked=false;
|
||||
}
|
||||
BOOST_VERIFY(!pthread_cond_signal(&cond));
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
|
||||
if(is_locked && !pthread_equal(owner,pthread_self()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
is_locked=true;
|
||||
++count;
|
||||
owner=pthread_self();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool timed_lock(system_time const & abs_time)
|
||||
{
|
||||
struct timespec const timeout=detail::get_timespec(abs_time);
|
||||
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
|
||||
if(is_locked && pthread_equal(owner,pthread_self()))
|
||||
{
|
||||
++count;
|
||||
return true;
|
||||
}
|
||||
while(is_locked)
|
||||
{
|
||||
int const cond_res=pthread_cond_timedwait(&cond,&m,&timeout);
|
||||
if(cond_res==ETIMEDOUT)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
BOOST_ASSERT(!cond_res);
|
||||
}
|
||||
is_locked=true;
|
||||
++count;
|
||||
owner=pthread_self();
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef unique_lock<recursive_timed_mutex> scoped_timed_lock;
|
||||
typedef detail::try_lock_wrapper<recursive_timed_mutex> scoped_try_lock;
|
||||
typedef scoped_timed_lock scoped_lock;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
303
include/boost/thread/pthread/shared_mutex.hpp
Normal file
303
include/boost/thread/pthread/shared_mutex.hpp
Normal file
@@ -0,0 +1,303 @@
|
||||
#ifndef BOOST_THREAD_PTHREAD_SHARED_MUTEX_HPP
|
||||
#define BOOST_THREAD_PTHREAD_SHARED_MUTEX_HPP
|
||||
|
||||
// (C) Copyright 2006-8 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
class shared_mutex
|
||||
{
|
||||
private:
|
||||
struct state_data
|
||||
{
|
||||
unsigned shared_count;
|
||||
bool exclusive;
|
||||
bool upgrade;
|
||||
bool exclusive_waiting_blocked;
|
||||
};
|
||||
|
||||
|
||||
|
||||
state_data state;
|
||||
boost::mutex state_change;
|
||||
boost::condition_variable shared_cond;
|
||||
boost::condition_variable exclusive_cond;
|
||||
boost::condition_variable upgrade_cond;
|
||||
|
||||
void release_waiters()
|
||||
{
|
||||
exclusive_cond.notify_one();
|
||||
shared_cond.notify_all();
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
shared_mutex()
|
||||
{
|
||||
state_data state_={0,0,0,0};
|
||||
state=state_;
|
||||
}
|
||||
|
||||
~shared_mutex()
|
||||
{
|
||||
}
|
||||
|
||||
void lock_shared()
|
||||
{
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
|
||||
while(state.exclusive || state.exclusive_waiting_blocked)
|
||||
{
|
||||
shared_cond.wait(lk);
|
||||
}
|
||||
++state.shared_count;
|
||||
}
|
||||
|
||||
bool try_lock_shared()
|
||||
{
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
|
||||
if(state.exclusive || state.exclusive_waiting_blocked)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
++state.shared_count;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool timed_lock_shared(system_time const& timeout)
|
||||
{
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
|
||||
while(state.exclusive || state.exclusive_waiting_blocked)
|
||||
{
|
||||
if(!shared_cond.timed_wait(lk,timeout))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
++state.shared_count;
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename TimeDuration>
|
||||
bool timed_lock_shared(TimeDuration const & relative_time)
|
||||
{
|
||||
return timed_lock_shared(get_system_time()+relative_time);
|
||||
}
|
||||
|
||||
void unlock_shared()
|
||||
{
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
bool const last_reader=!--state.shared_count;
|
||||
|
||||
if(last_reader)
|
||||
{
|
||||
if(state.upgrade)
|
||||
{
|
||||
state.upgrade=false;
|
||||
state.exclusive=true;
|
||||
upgrade_cond.notify_one();
|
||||
}
|
||||
else
|
||||
{
|
||||
state.exclusive_waiting_blocked=false;
|
||||
}
|
||||
release_waiters();
|
||||
}
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
|
||||
while(state.shared_count || state.exclusive)
|
||||
{
|
||||
state.exclusive_waiting_blocked=true;
|
||||
exclusive_cond.wait(lk);
|
||||
}
|
||||
state.exclusive=true;
|
||||
}
|
||||
|
||||
bool timed_lock(system_time const& timeout)
|
||||
{
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
|
||||
while(state.shared_count || state.exclusive)
|
||||
{
|
||||
state.exclusive_waiting_blocked=true;
|
||||
if(!exclusive_cond.timed_wait(lk,timeout))
|
||||
{
|
||||
if(state.shared_count || state.exclusive)
|
||||
{
|
||||
state.exclusive_waiting_blocked=false;
|
||||
exclusive_cond.notify_one();
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
state.exclusive=true;
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename TimeDuration>
|
||||
bool timed_lock(TimeDuration const & relative_time)
|
||||
{
|
||||
return timed_lock(get_system_time()+relative_time);
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
|
||||
if(state.shared_count || state.exclusive)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
state.exclusive=true;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
state.exclusive=false;
|
||||
state.exclusive_waiting_blocked=false;
|
||||
release_waiters();
|
||||
}
|
||||
|
||||
void lock_upgrade()
|
||||
{
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
|
||||
{
|
||||
shared_cond.wait(lk);
|
||||
}
|
||||
++state.shared_count;
|
||||
state.upgrade=true;
|
||||
}
|
||||
|
||||
bool timed_lock_upgrade(system_time const& timeout)
|
||||
{
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
|
||||
{
|
||||
if(!shared_cond.timed_wait(lk,timeout))
|
||||
{
|
||||
if(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
++state.shared_count;
|
||||
state.upgrade=true;
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename TimeDuration>
|
||||
bool timed_lock_upgrade(TimeDuration const & relative_time)
|
||||
{
|
||||
return timed_lock(get_system_time()+relative_time);
|
||||
}
|
||||
|
||||
bool try_lock_upgrade()
|
||||
{
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
if(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
++state.shared_count;
|
||||
state.upgrade=true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void unlock_upgrade()
|
||||
{
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
state.upgrade=false;
|
||||
bool const last_reader=!--state.shared_count;
|
||||
|
||||
if(last_reader)
|
||||
{
|
||||
state.exclusive_waiting_blocked=false;
|
||||
release_waiters();
|
||||
}
|
||||
}
|
||||
|
||||
void unlock_upgrade_and_lock()
|
||||
{
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
--state.shared_count;
|
||||
while(state.shared_count)
|
||||
{
|
||||
upgrade_cond.wait(lk);
|
||||
}
|
||||
state.upgrade=false;
|
||||
state.exclusive=true;
|
||||
}
|
||||
|
||||
void unlock_and_lock_upgrade()
|
||||
{
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
state.exclusive=false;
|
||||
state.upgrade=true;
|
||||
++state.shared_count;
|
||||
state.exclusive_waiting_blocked=false;
|
||||
release_waiters();
|
||||
}
|
||||
|
||||
void unlock_and_lock_shared()
|
||||
{
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
state.exclusive=false;
|
||||
++state.shared_count;
|
||||
state.exclusive_waiting_blocked=false;
|
||||
release_waiters();
|
||||
}
|
||||
|
||||
void unlock_upgrade_and_lock_shared()
|
||||
{
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
state.upgrade=false;
|
||||
state.exclusive_waiting_blocked=false;
|
||||
release_waiters();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
118
include/boost/thread/pthread/thread_data.hpp
Normal file
118
include/boost/thread/pthread/thread_data.hpp
Normal file
@@ -0,0 +1,118 @@
|
||||
#ifndef BOOST_THREAD_PTHREAD_THREAD_DATA_HPP
|
||||
#define BOOST_THREAD_PTHREAD_THREAD_DATA_HPP
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/enable_shared_from_this.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <pthread.h>
|
||||
#include "condition_variable_fwd.hpp"
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
class thread;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct thread_exit_callback_node;
|
||||
struct tss_data_node;
|
||||
|
||||
struct thread_data_base;
|
||||
typedef boost::shared_ptr<thread_data_base> thread_data_ptr;
|
||||
|
||||
struct BOOST_THREAD_DECL thread_data_base:
|
||||
enable_shared_from_this<thread_data_base>
|
||||
{
|
||||
thread_data_ptr self;
|
||||
pthread_t thread_handle;
|
||||
boost::mutex data_mutex;
|
||||
boost::condition_variable done_condition;
|
||||
boost::mutex sleep_mutex;
|
||||
boost::condition_variable sleep_condition;
|
||||
bool done;
|
||||
bool join_started;
|
||||
bool joined;
|
||||
boost::detail::thread_exit_callback_node* thread_exit_callbacks;
|
||||
boost::detail::tss_data_node* tss_data;
|
||||
bool interrupt_enabled;
|
||||
bool interrupt_requested;
|
||||
pthread_cond_t* current_cond;
|
||||
|
||||
thread_data_base():
|
||||
done(false),join_started(false),joined(false),
|
||||
thread_exit_callbacks(0),tss_data(0),
|
||||
interrupt_enabled(true),
|
||||
interrupt_requested(false),
|
||||
current_cond(0)
|
||||
{}
|
||||
virtual ~thread_data_base();
|
||||
|
||||
typedef pthread_t native_handle_type;
|
||||
|
||||
virtual void run()=0;
|
||||
};
|
||||
|
||||
BOOST_THREAD_DECL thread_data_base* get_current_thread_data();
|
||||
|
||||
class interruption_checker
|
||||
{
|
||||
thread_data_base* const thread_info;
|
||||
|
||||
void check_for_interruption()
|
||||
{
|
||||
if(thread_info->interrupt_requested)
|
||||
{
|
||||
thread_info->interrupt_requested=false;
|
||||
throw thread_interrupted();
|
||||
}
|
||||
}
|
||||
|
||||
void operator=(interruption_checker&);
|
||||
public:
|
||||
explicit interruption_checker(pthread_cond_t* cond):
|
||||
thread_info(detail::get_current_thread_data())
|
||||
{
|
||||
if(thread_info && thread_info->interrupt_enabled)
|
||||
{
|
||||
lock_guard<mutex> guard(thread_info->data_mutex);
|
||||
check_for_interruption();
|
||||
thread_info->current_cond=cond;
|
||||
}
|
||||
}
|
||||
~interruption_checker()
|
||||
{
|
||||
if(thread_info && thread_info->interrupt_enabled)
|
||||
{
|
||||
lock_guard<mutex> guard(thread_info->data_mutex);
|
||||
thread_info->current_cond=NULL;
|
||||
check_for_interruption();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace this_thread
|
||||
{
|
||||
void BOOST_THREAD_DECL yield();
|
||||
|
||||
void BOOST_THREAD_DECL sleep(system_time const& abs_time);
|
||||
|
||||
template<typename TimeDuration>
|
||||
inline void sleep(TimeDuration const& rel_time)
|
||||
{
|
||||
this_thread::sleep(get_system_time()+rel_time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
242
include/boost/thread/pthread/thread_heap_alloc.hpp
Normal file
242
include/boost/thread/pthread/thread_heap_alloc.hpp
Normal file
@@ -0,0 +1,242 @@
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2008 Anthony Williams
|
||||
#ifndef THREAD_HEAP_ALLOC_PTHREAD_HPP
|
||||
#define THREAD_HEAP_ALLOC_PTHREAD_HPP
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template<typename T>
|
||||
inline T* heap_new()
|
||||
{
|
||||
return new T();
|
||||
}
|
||||
|
||||
#ifdef BOOST_HAS_RVALUE_REFS
|
||||
template<typename T,typename A1>
|
||||
inline T* heap_new(A1&& a1)
|
||||
{
|
||||
return new T(static_cast<A1&&>(a1));
|
||||
}
|
||||
template<typename T,typename A1,typename A2>
|
||||
inline T* heap_new(A1&& a1,A2&& a2)
|
||||
{
|
||||
return new T(static_cast<A1&&>(a1),static_cast<A2&&>(a2));
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3>
|
||||
inline T* heap_new(A1&& a1,A2&& a2,A3&& a3)
|
||||
{
|
||||
return new T(static_cast<A1&&>(a1),static_cast<A2&&>(a2),
|
||||
static_cast<A3&&>(a3));
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1&& a1,A2&& a2,A3&& a3,A4&& a4)
|
||||
{
|
||||
return new T(static_cast<A1&&>(a1),static_cast<A2&&>(a2),
|
||||
static_cast<A3&&>(a3),static_cast<A4&&>(a4));
|
||||
}
|
||||
#else
|
||||
template<typename T,typename A1>
|
||||
inline T* heap_new_impl(A1 a1)
|
||||
{
|
||||
return new T(a1);
|
||||
}
|
||||
template<typename T,typename A1,typename A2>
|
||||
inline T* heap_new_impl(A1 a1,A2 a2)
|
||||
{
|
||||
return new T(a1,a2);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3>
|
||||
inline T* heap_new_impl(A1 a1,A2 a2,A3 a3)
|
||||
{
|
||||
return new T(a1,a2,a3);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new_impl(A1 a1,A2 a2,A3 a3,A4 a4)
|
||||
{
|
||||
return new T(a1,a2,a3,a4);
|
||||
}
|
||||
|
||||
template<typename T,typename A1>
|
||||
inline T* heap_new(A1 const& a1)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&>(a1);
|
||||
}
|
||||
template<typename T,typename A1>
|
||||
inline T* heap_new(A1& a1)
|
||||
{
|
||||
return heap_new_impl<T,A1&>(a1);
|
||||
}
|
||||
|
||||
template<typename T,typename A1,typename A2>
|
||||
inline T* heap_new(A1 const& a1,A2 const& a2)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2 const&>(a1,a2);
|
||||
}
|
||||
template<typename T,typename A1,typename A2>
|
||||
inline T* heap_new(A1& a1,A2 const& a2)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2 const&>(a1,a2);
|
||||
}
|
||||
template<typename T,typename A1,typename A2>
|
||||
inline T* heap_new(A1 const& a1,A2& a2)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2&>(a1,a2);
|
||||
}
|
||||
template<typename T,typename A1,typename A2>
|
||||
inline T* heap_new(A1& a1,A2& a2)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2&>(a1,a2);
|
||||
}
|
||||
|
||||
template<typename T,typename A1,typename A2,typename A3>
|
||||
inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2 const&,A3 const&>(a1,a2,a3);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3>
|
||||
inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2 const&,A3 const&>(a1,a2,a3);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3>
|
||||
inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2&,A3 const&>(a1,a2,a3);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3>
|
||||
inline T* heap_new(A1& a1,A2& a2,A3 const& a3)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2&,A3 const&>(a1,a2,a3);
|
||||
}
|
||||
|
||||
template<typename T,typename A1,typename A2,typename A3>
|
||||
inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2 const&,A3&>(a1,a2,a3);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3>
|
||||
inline T* heap_new(A1& a1,A2 const& a2,A3& a3)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2 const&,A3&>(a1,a2,a3);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3>
|
||||
inline T* heap_new(A1 const& a1,A2& a2,A3& a3)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2&,A3&>(a1,a2,a3);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3>
|
||||
inline T* heap_new(A1& a1,A2& a2,A3& a3)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2&,A3&>(a1,a2,a3);
|
||||
}
|
||||
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3,A4 const& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2 const&,A3 const&,A4 const&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3,A4 const& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2 const&,A3 const&,A4 const&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3,A4 const& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2&,A3 const&,A4 const&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1& a1,A2& a2,A3 const& a3,A4 const& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2&,A3 const&,A4 const&>(a1,a2,a3,a4);
|
||||
}
|
||||
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3,A4 const& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2 const&,A3&,A4 const&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1& a1,A2 const& a2,A3& a3,A4 const& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2 const&,A3&,A4 const&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1 const& a1,A2& a2,A3& a3,A4 const& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2&,A3&,A4 const&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1& a1,A2& a2,A3& a3,A4 const& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2&,A3&,A4 const&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3,A4& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2 const&,A3 const&,A4&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3,A4& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2 const&,A3 const&,A4&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3,A4& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2&,A3 const&,A4&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1& a1,A2& a2,A3 const& a3,A4& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2&,A3 const&,A4&>(a1,a2,a3,a4);
|
||||
}
|
||||
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3,A4& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2 const&,A3&,A4&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1& a1,A2 const& a2,A3& a3,A4& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2 const&,A3&,A4&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1 const& a1,A2& a2,A3& a3,A4& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2&,A3&,A4&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1& a1,A2& a2,A3& a3,A4& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2&,A3&,A4&>(a1,a2,a3,a4);
|
||||
}
|
||||
|
||||
#endif
|
||||
template<typename T>
|
||||
inline void heap_delete(T* data)
|
||||
{
|
||||
delete data;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct do_heap_delete
|
||||
{
|
||||
void operator()(T* data) const
|
||||
{
|
||||
detail::heap_delete(data);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
36
include/boost/thread/pthread/timespec.hpp
Normal file
36
include/boost/thread/pthread/timespec.hpp
Normal file
@@ -0,0 +1,36 @@
|
||||
#ifndef BOOST_THREAD_PTHREAD_TIMESPEC_HPP
|
||||
#define BOOST_THREAD_PTHREAD_TIMESPEC_HPP
|
||||
// (C) Copyright 2007-8 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#include <boost/date_time/posix_time/conversion.hpp>
|
||||
#include <pthread.h>
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
inline struct timespec get_timespec(boost::system_time const& abs_time)
|
||||
{
|
||||
struct timespec timeout={0,0};
|
||||
boost::posix_time::time_duration const time_since_epoch=abs_time-boost::posix_time::from_time_t(0);
|
||||
|
||||
timeout.tv_sec=time_since_epoch.total_seconds();
|
||||
timeout.tv_nsec=(long)(time_since_epoch.fractional_seconds()*(1000000000l/time_since_epoch.ticks_per_second()));
|
||||
return timeout;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
@@ -1,184 +1,21 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
#ifndef BOOST_THREAD_RECURSIVE_MUTEX_HPP
|
||||
#define BOOST_THREAD_RECURSIVE_MUTEX_HPP
|
||||
|
||||
// recursive_mutex.hpp
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_RECURSIVE_MUTEX_WEK070601_HPP
|
||||
#define BOOST_RECURSIVE_MUTEX_WEK070601_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/thread/detail/lock.hpp>
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
# include <pthread.h>
|
||||
#include <boost/thread/detail/platform.hpp>
|
||||
#if defined(BOOST_THREAD_PLATFORM_WIN32)
|
||||
#include <boost/thread/win32/recursive_mutex.hpp>
|
||||
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
|
||||
#include <boost/thread/pthread/recursive_mutex.hpp>
|
||||
#else
|
||||
#error "Boost threads unavailable on this platform"
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_HAS_MPTASKS)
|
||||
# include "scoped_critical_region.hpp"
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
struct xtime;
|
||||
// disable warnings about non dll import
|
||||
// see: http://www.boost.org/more/separate_compilation.html#dlls
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4251 4231 4660 4275)
|
||||
#endif
|
||||
class BOOST_THREAD_DECL recursive_mutex
|
||||
: private noncopyable
|
||||
{
|
||||
public:
|
||||
friend class detail::thread::lock_ops<recursive_mutex>;
|
||||
|
||||
typedef detail::thread::scoped_lock<recursive_mutex> scoped_lock;
|
||||
|
||||
recursive_mutex();
|
||||
~recursive_mutex();
|
||||
|
||||
private:
|
||||
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||
typedef std::size_t cv_state;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
struct cv_state
|
||||
{
|
||||
long count;
|
||||
pthread_mutex_t* pmutex;
|
||||
};
|
||||
#endif
|
||||
void do_lock();
|
||||
void do_unlock();
|
||||
void do_lock(cv_state& state);
|
||||
void do_unlock(cv_state& state);
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
void* m_mutex;
|
||||
bool m_critical_section;
|
||||
unsigned long m_count;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
pthread_mutex_t m_mutex;
|
||||
unsigned m_count;
|
||||
# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
|
||||
pthread_cond_t m_unlocked;
|
||||
pthread_t m_thread_id;
|
||||
bool m_valid_id;
|
||||
# endif
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
threads::mac::detail::scoped_critical_region m_mutex;
|
||||
threads::mac::detail::scoped_critical_region m_mutex_mutex;
|
||||
std::size_t m_count;
|
||||
#endif
|
||||
};
|
||||
|
||||
class BOOST_THREAD_DECL recursive_try_mutex
|
||||
: private noncopyable
|
||||
{
|
||||
public:
|
||||
friend class detail::thread::lock_ops<recursive_try_mutex>;
|
||||
|
||||
typedef detail::thread::scoped_lock<recursive_try_mutex> scoped_lock;
|
||||
typedef detail::thread::scoped_try_lock<
|
||||
recursive_try_mutex> scoped_try_lock;
|
||||
|
||||
recursive_try_mutex();
|
||||
~recursive_try_mutex();
|
||||
|
||||
private:
|
||||
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||
typedef std::size_t cv_state;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
struct cv_state
|
||||
{
|
||||
long count;
|
||||
pthread_mutex_t* pmutex;
|
||||
};
|
||||
#endif
|
||||
void do_lock();
|
||||
bool do_trylock();
|
||||
void do_unlock();
|
||||
void do_lock(cv_state& state);
|
||||
void do_unlock(cv_state& state);
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
void* m_mutex;
|
||||
bool m_critical_section;
|
||||
unsigned long m_count;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
pthread_mutex_t m_mutex;
|
||||
unsigned m_count;
|
||||
# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
|
||||
pthread_cond_t m_unlocked;
|
||||
pthread_t m_thread_id;
|
||||
bool m_valid_id;
|
||||
# endif
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
threads::mac::detail::scoped_critical_region m_mutex;
|
||||
threads::mac::detail::scoped_critical_region m_mutex_mutex;
|
||||
std::size_t m_count;
|
||||
#endif
|
||||
};
|
||||
|
||||
class BOOST_THREAD_DECL recursive_timed_mutex
|
||||
: private noncopyable
|
||||
{
|
||||
public:
|
||||
friend class detail::thread::lock_ops<recursive_timed_mutex>;
|
||||
|
||||
typedef detail::thread::scoped_lock<recursive_timed_mutex> scoped_lock;
|
||||
typedef detail::thread::scoped_try_lock<
|
||||
recursive_timed_mutex> scoped_try_lock;
|
||||
typedef detail::thread::scoped_timed_lock<
|
||||
recursive_timed_mutex> scoped_timed_lock;
|
||||
|
||||
recursive_timed_mutex();
|
||||
~recursive_timed_mutex();
|
||||
|
||||
private:
|
||||
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||
typedef std::size_t cv_state;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
struct cv_state
|
||||
{
|
||||
long count;
|
||||
pthread_mutex_t* pmutex;
|
||||
};
|
||||
#endif
|
||||
void do_lock();
|
||||
bool do_trylock();
|
||||
bool do_timedlock(const xtime& xt);
|
||||
void do_unlock();
|
||||
void do_lock(cv_state& state);
|
||||
void do_unlock(cv_state& state);
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
void* m_mutex;
|
||||
unsigned long m_count;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
pthread_mutex_t m_mutex;
|
||||
pthread_cond_t m_unlocked;
|
||||
pthread_t m_thread_id;
|
||||
bool m_valid_id;
|
||||
unsigned m_count;
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
threads::mac::detail::scoped_critical_region m_mutex;
|
||||
threads::mac::detail::scoped_critical_region m_mutex_mutex;
|
||||
std::size_t m_count;
|
||||
#endif
|
||||
};
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_RECURSIVE_MUTEX_WEK070601_HPP
|
||||
|
||||
// Change Log:
|
||||
// 8 Feb 01 WEKEMPF Initial version.
|
||||
// 1 Jun 01 WEKEMPF Modified to use xtime for time outs. Factored out
|
||||
// to three classes, mutex, try_mutex and timed_mutex.
|
||||
// 11 Jun 01 WEKEMPF Modified to use PTHREAD_MUTEX_RECURSIVE if available.
|
||||
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
|
||||
|
||||
21
include/boost/thread/shared_mutex.hpp
Normal file
21
include/boost/thread/shared_mutex.hpp
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef BOOST_THREAD_SHARED_MUTEX_HPP
|
||||
#define BOOST_THREAD_SHARED_MUTEX_HPP
|
||||
|
||||
// shared_mutex.hpp
|
||||
//
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/platform.hpp>
|
||||
#if defined(BOOST_THREAD_PLATFORM_WIN32)
|
||||
#include <boost/thread/win32/shared_mutex.hpp>
|
||||
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
|
||||
#include <boost/thread/pthread/shared_mutex.hpp>
|
||||
#else
|
||||
#error "Boost threads unavailable on this platform"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,89 +1,25 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
#ifndef BOOST_THREAD_THREAD_HPP
|
||||
#define BOOST_THREAD_THREAD_HPP
|
||||
|
||||
// thread.hpp
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007-8 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_THREAD_WEK070601_HPP
|
||||
#define BOOST_THREAD_WEK070601_HPP
|
||||
#include <boost/thread/detail/platform.hpp>
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
# include <pthread.h>
|
||||
# include <boost/thread/condition.hpp>
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
# include <Multiprocessing.h>
|
||||
#if defined(BOOST_THREAD_PLATFORM_WIN32)
|
||||
#include <boost/thread/win32/thread_data.hpp>
|
||||
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
|
||||
#include <boost/thread/pthread/thread_data.hpp>
|
||||
#else
|
||||
#error "Boost threads unavailable on this platform"
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
#include <boost/thread/detail/thread.hpp>
|
||||
|
||||
|
||||
struct xtime;
|
||||
// disable warnings about non dll import
|
||||
// see: http://www.boost.org/more/separate_compilation.html#dlls
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4251 4231 4660 4275)
|
||||
#endif
|
||||
class BOOST_THREAD_DECL thread : private noncopyable
|
||||
{
|
||||
public:
|
||||
thread();
|
||||
explicit thread(const function0<void>& threadfunc);
|
||||
~thread();
|
||||
|
||||
bool operator==(const thread& other) const;
|
||||
bool operator!=(const thread& other) const;
|
||||
|
||||
void join();
|
||||
|
||||
static void sleep(const xtime& xt);
|
||||
static void yield();
|
||||
|
||||
private:
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
void* m_thread;
|
||||
unsigned int m_id;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
private:
|
||||
pthread_t m_thread;
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
MPQueueID m_pJoinQueueID;
|
||||
MPTaskID m_pTaskID;
|
||||
#endif
|
||||
bool m_joinable;
|
||||
};
|
||||
|
||||
class BOOST_THREAD_DECL thread_group : private noncopyable
|
||||
{
|
||||
public:
|
||||
thread_group();
|
||||
~thread_group();
|
||||
|
||||
thread* create_thread(const function0<void>& threadfunc);
|
||||
void add_thread(thread* thrd);
|
||||
void remove_thread(thread* thrd);
|
||||
void join_all();
|
||||
int size();
|
||||
|
||||
private:
|
||||
std::list<thread*> m_threads;
|
||||
mutex m_mutex;
|
||||
};
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
} // namespace boost
|
||||
|
||||
// Change Log:
|
||||
// 8 Feb 01 WEKEMPF Initial version.
|
||||
// 1 Jun 01 WEKEMPF Added boost::thread initial implementation.
|
||||
// 3 Jul 01 WEKEMPF Redesigned boost::thread to be noncopyable.
|
||||
|
||||
#endif // BOOST_THREAD_WEK070601_HPP
|
||||
|
||||
50
include/boost/thread/thread_time.hpp
Normal file
50
include/boost/thread/thread_time.hpp
Normal file
@@ -0,0 +1,50 @@
|
||||
#ifndef BOOST_THREAD_TIME_HPP
|
||||
#define BOOST_THREAD_TIME_HPP
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/date_time/microsec_time_clock.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time_types.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
typedef boost::posix_time::ptime system_time;
|
||||
|
||||
inline system_time get_system_time()
|
||||
{
|
||||
return boost::date_time::microsec_clock<system_time>::universal_time();
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
inline system_time get_system_time_sentinel()
|
||||
{
|
||||
return system_time(boost::posix_time::pos_infin);
|
||||
}
|
||||
|
||||
inline unsigned long get_milliseconds_until(system_time const& target_time)
|
||||
{
|
||||
if(target_time.is_pos_infinity())
|
||||
{
|
||||
return ~(unsigned long)0;
|
||||
}
|
||||
system_time const now=get_system_time();
|
||||
if(target_time<=now)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return static_cast<unsigned long>((target_time-now).total_milliseconds()+1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
@@ -1,128 +1,111 @@
|
||||
// Copyright (C) 2001-2003 William E. Kempf
|
||||
// Copyright (C) 2006 Roland Schwarz
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_TSS_WEK070601_HPP
|
||||
#define BOOST_TSS_WEK070601_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
# include <pthread.h>
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
# include <Multiprocessing.h>
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
// disable warnings about non dll import
|
||||
// see: http://www.boost.org/more/separate_compilation.html#dlls
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4251 4231 4660 4275)
|
||||
#endif
|
||||
|
||||
namespace detail {
|
||||
|
||||
class BOOST_THREAD_DECL tss : private noncopyable
|
||||
{
|
||||
public:
|
||||
tss(boost::function1<void, void*>* pcleanup) {
|
||||
if (pcleanup == 0) throw boost::thread_resource_error();
|
||||
try
|
||||
{
|
||||
init(pcleanup);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
delete pcleanup;
|
||||
throw boost::thread_resource_error();
|
||||
}
|
||||
}
|
||||
|
||||
~tss();
|
||||
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>
|
||||
class thread_specific_ptr : private noncopyable
|
||||
{
|
||||
public:
|
||||
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* operator->() const { return get(); }
|
||||
T& operator*() const { return *get(); }
|
||||
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;
|
||||
m_tss.set(p);
|
||||
if (cur) m_tss.cleanup(cur);
|
||||
}
|
||||
|
||||
private:
|
||||
static void cleanup(T* p) { delete p; }
|
||||
detail::tss m_tss;
|
||||
};
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif //BOOST_TSS_WEK070601_HPP
|
||||
|
||||
// Change Log:
|
||||
// 6 Jun 01
|
||||
// WEKEMPF Initial version.
|
||||
// 30 May 02 WEKEMPF
|
||||
// Added interface to set specific cleanup handlers.
|
||||
// Removed TLS slot limits from most implementations.
|
||||
// 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().
|
||||
#ifndef BOOST_THREAD_TSS_HPP
|
||||
#define BOOST_THREAD_TSS_HPP
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007-8 Anthony Williams
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/thread/detail/thread_heap_alloc.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
struct tss_cleanup_function
|
||||
{
|
||||
virtual ~tss_cleanup_function()
|
||||
{}
|
||||
|
||||
virtual void operator()(void* data)=0;
|
||||
};
|
||||
|
||||
BOOST_THREAD_DECL void set_tss_data(void const* key,boost::shared_ptr<tss_cleanup_function> func,void* tss_data,bool cleanup_existing);
|
||||
BOOST_THREAD_DECL void* get_tss_data(void const* key);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class thread_specific_ptr
|
||||
{
|
||||
private:
|
||||
thread_specific_ptr(thread_specific_ptr&);
|
||||
thread_specific_ptr& operator=(thread_specific_ptr&);
|
||||
|
||||
struct delete_data:
|
||||
detail::tss_cleanup_function
|
||||
{
|
||||
void operator()(void* data)
|
||||
{
|
||||
delete static_cast<T*>(data);
|
||||
}
|
||||
};
|
||||
|
||||
struct run_custom_cleanup_function:
|
||||
detail::tss_cleanup_function
|
||||
{
|
||||
void (*cleanup_function)(T*);
|
||||
|
||||
explicit run_custom_cleanup_function(void (*cleanup_function_)(T*)):
|
||||
cleanup_function(cleanup_function_)
|
||||
{}
|
||||
|
||||
void operator()(void* data)
|
||||
{
|
||||
cleanup_function(static_cast<T*>(data));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
boost::shared_ptr<detail::tss_cleanup_function> cleanup;
|
||||
|
||||
public:
|
||||
thread_specific_ptr():
|
||||
cleanup(detail::heap_new<delete_data>(),detail::do_heap_delete<delete_data>())
|
||||
{}
|
||||
explicit thread_specific_ptr(void (*func_)(T*))
|
||||
{
|
||||
if(func_)
|
||||
{
|
||||
cleanup.reset(detail::heap_new<run_custom_cleanup_function>(func_),detail::do_heap_delete<run_custom_cleanup_function>());
|
||||
}
|
||||
}
|
||||
~thread_specific_ptr()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
T* get() const
|
||||
{
|
||||
return static_cast<T*>(detail::get_tss_data(this));
|
||||
}
|
||||
T* operator->() const
|
||||
{
|
||||
return get();
|
||||
}
|
||||
T& operator*() const
|
||||
{
|
||||
return *get();
|
||||
}
|
||||
T* release()
|
||||
{
|
||||
T* const temp=get();
|
||||
detail::set_tss_data(this,boost::shared_ptr<detail::tss_cleanup_function>(),0,false);
|
||||
return temp;
|
||||
}
|
||||
void reset(T* new_value=0)
|
||||
{
|
||||
T* const current_value=get();
|
||||
if(current_value!=new_value)
|
||||
{
|
||||
detail::set_tss_data(this,cleanup,new_value,true);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
|
||||
120
include/boost/thread/win32/basic_recursive_mutex.hpp
Normal file
120
include/boost/thread/win32/basic_recursive_mutex.hpp
Normal file
@@ -0,0 +1,120 @@
|
||||
#ifndef BOOST_BASIC_RECURSIVE_MUTEX_WIN32_HPP
|
||||
#define BOOST_BASIC_RECURSIVE_MUTEX_WIN32_HPP
|
||||
|
||||
// basic_recursive_mutex.hpp
|
||||
//
|
||||
// (C) Copyright 2006-8 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include "thread_primitives.hpp"
|
||||
#include "basic_timed_mutex.hpp"
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template<typename underlying_mutex_type>
|
||||
struct basic_recursive_mutex_impl
|
||||
{
|
||||
long recursion_count;
|
||||
long locking_thread_id;
|
||||
underlying_mutex_type mutex;
|
||||
|
||||
void initialize()
|
||||
{
|
||||
recursion_count=0;
|
||||
locking_thread_id=0;
|
||||
mutex.initialize();
|
||||
}
|
||||
|
||||
void destroy()
|
||||
{
|
||||
mutex.destroy();
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
long const current_thread_id=win32::GetCurrentThreadId();
|
||||
return try_recursive_lock(current_thread_id) || try_basic_lock(current_thread_id);
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
long const current_thread_id=win32::GetCurrentThreadId();
|
||||
if(!try_recursive_lock(current_thread_id))
|
||||
{
|
||||
mutex.lock();
|
||||
BOOST_INTERLOCKED_EXCHANGE(&locking_thread_id,current_thread_id);
|
||||
recursion_count=1;
|
||||
}
|
||||
}
|
||||
bool timed_lock(::boost::system_time const& target)
|
||||
{
|
||||
long const current_thread_id=win32::GetCurrentThreadId();
|
||||
return try_recursive_lock(current_thread_id) || try_timed_lock(current_thread_id,target);
|
||||
}
|
||||
template<typename Duration>
|
||||
bool timed_lock(Duration const& timeout)
|
||||
{
|
||||
return timed_lock(get_system_time()+timeout);
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
if(!--recursion_count)
|
||||
{
|
||||
BOOST_INTERLOCKED_EXCHANGE(&locking_thread_id,0);
|
||||
mutex.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool try_recursive_lock(long current_thread_id)
|
||||
{
|
||||
if(::boost::detail::interlocked_read_acquire(&locking_thread_id)==current_thread_id)
|
||||
{
|
||||
++recursion_count;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool try_basic_lock(long current_thread_id)
|
||||
{
|
||||
if(mutex.try_lock())
|
||||
{
|
||||
BOOST_INTERLOCKED_EXCHANGE(&locking_thread_id,current_thread_id);
|
||||
recursion_count=1;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool try_timed_lock(long current_thread_id,::boost::system_time const& target)
|
||||
{
|
||||
if(mutex.timed_lock(target))
|
||||
{
|
||||
BOOST_INTERLOCKED_EXCHANGE(&locking_thread_id,current_thread_id);
|
||||
recursion_count=1;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
typedef basic_recursive_mutex_impl<basic_timed_mutex> basic_recursive_mutex;
|
||||
typedef basic_recursive_mutex_impl<basic_timed_mutex> basic_recursive_timed_mutex;
|
||||
}
|
||||
}
|
||||
|
||||
#define BOOST_BASIC_RECURSIVE_MUTEX_INITIALIZER {0}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
178
include/boost/thread/win32/basic_timed_mutex.hpp
Normal file
178
include/boost/thread/win32/basic_timed_mutex.hpp
Normal file
@@ -0,0 +1,178 @@
|
||||
#ifndef BOOST_BASIC_TIMED_MUTEX_WIN32_HPP
|
||||
#define BOOST_BASIC_TIMED_MUTEX_WIN32_HPP
|
||||
|
||||
// basic_timed_mutex_win32.hpp
|
||||
//
|
||||
// (C) Copyright 2006-8 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include "thread_primitives.hpp"
|
||||
#include "interlocked_read.hpp"
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <boost/detail/interlocked.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
struct basic_timed_mutex
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(unsigned char,lock_flag_bit=31);
|
||||
BOOST_STATIC_CONSTANT(unsigned char,event_set_flag_bit=30);
|
||||
BOOST_STATIC_CONSTANT(long,lock_flag_value=1<<lock_flag_bit);
|
||||
BOOST_STATIC_CONSTANT(long,event_set_flag_value=1<<event_set_flag_bit);
|
||||
long active_count;
|
||||
void* event;
|
||||
|
||||
void initialize()
|
||||
{
|
||||
active_count=0;
|
||||
event=0;
|
||||
}
|
||||
|
||||
void destroy()
|
||||
{
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4312)
|
||||
#endif
|
||||
void* const old_event=BOOST_INTERLOCKED_EXCHANGE_POINTER(&event,0);
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
if(old_event)
|
||||
{
|
||||
win32::CloseHandle(old_event);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
return !win32::interlocked_bit_test_and_set(&active_count,lock_flag_bit);
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
BOOST_VERIFY(timed_lock(::boost::detail::get_system_time_sentinel()));
|
||||
}
|
||||
bool timed_lock(::boost::system_time const& wait_until)
|
||||
{
|
||||
if(!win32::interlocked_bit_test_and_set(&active_count,lock_flag_bit))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
long old_count=active_count;
|
||||
for(;;)
|
||||
{
|
||||
long const new_count=(old_count&lock_flag_value)?(old_count+1):(old_count|lock_flag_value);
|
||||
long const current=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&active_count,new_count,old_count);
|
||||
if(current==old_count)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_count=current;
|
||||
}
|
||||
|
||||
if(old_count&lock_flag_value)
|
||||
{
|
||||
bool lock_acquired=false;
|
||||
void* const sem=get_event();
|
||||
|
||||
do
|
||||
{
|
||||
if(win32::WaitForSingleObject(sem,::boost::detail::get_milliseconds_until(wait_until))!=0)
|
||||
{
|
||||
BOOST_INTERLOCKED_DECREMENT(&active_count);
|
||||
return false;
|
||||
}
|
||||
old_count&=~lock_flag_value;
|
||||
old_count|=event_set_flag_value;
|
||||
for(;;)
|
||||
{
|
||||
long const new_count=((old_count&lock_flag_value)?old_count:((old_count-1)|lock_flag_value))&~event_set_flag_value;
|
||||
long const current=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&active_count,new_count,old_count);
|
||||
if(current==old_count)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_count=current;
|
||||
}
|
||||
lock_acquired=!(old_count&lock_flag_value);
|
||||
}
|
||||
while(!lock_acquired);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename Duration>
|
||||
bool timed_lock(Duration const& timeout)
|
||||
{
|
||||
return timed_lock(get_system_time()+timeout);
|
||||
}
|
||||
|
||||
bool timed_lock(boost::xtime const& timeout)
|
||||
{
|
||||
return timed_lock(system_time(timeout));
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
long const offset=lock_flag_value;
|
||||
long const old_count=BOOST_INTERLOCKED_EXCHANGE_ADD(&active_count,lock_flag_value);
|
||||
if(!(old_count&event_set_flag_value) && (old_count>offset))
|
||||
{
|
||||
if(!win32::interlocked_bit_test_and_set(&active_count,event_set_flag_bit))
|
||||
{
|
||||
win32::SetEvent(get_event());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void* get_event()
|
||||
{
|
||||
void* current_event=::boost::detail::interlocked_read_acquire(&event);
|
||||
|
||||
if(!current_event)
|
||||
{
|
||||
void* const new_event=win32::create_anonymous_event(win32::auto_reset_event,win32::event_initially_reset);
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4311)
|
||||
#pragma warning(disable:4312)
|
||||
#endif
|
||||
void* const old_event=BOOST_INTERLOCKED_COMPARE_EXCHANGE_POINTER(&event,new_event,0);
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
if(old_event!=0)
|
||||
{
|
||||
win32::CloseHandle(new_event);
|
||||
return old_event;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new_event;
|
||||
}
|
||||
}
|
||||
return current_event;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#define BOOST_BASIC_TIMED_MUTEX_INITIALIZER {0}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
418
include/boost/thread/win32/condition_variable.hpp
Normal file
418
include/boost/thread/win32/condition_variable.hpp
Normal file
@@ -0,0 +1,418 @@
|
||||
#ifndef BOOST_THREAD_CONDITION_VARIABLE_WIN32_HPP
|
||||
#define BOOST_THREAD_CONDITION_VARIABLE_WIN32_HPP
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007-8 Anthony Williams
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include "thread_primitives.hpp"
|
||||
#include <limits.h>
|
||||
#include <boost/assert.hpp>
|
||||
#include <algorithm>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#include "interlocked_read.hpp"
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <vector>
|
||||
#include <boost/intrusive_ptr.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
class basic_cv_list_entry;
|
||||
void intrusive_ptr_add_ref(basic_cv_list_entry * p);
|
||||
void intrusive_ptr_release(basic_cv_list_entry * p);
|
||||
|
||||
class basic_cv_list_entry
|
||||
{
|
||||
private:
|
||||
detail::win32::handle_manager semaphore;
|
||||
detail::win32::handle_manager wake_sem;
|
||||
long waiters;
|
||||
bool notified;
|
||||
long references;
|
||||
|
||||
basic_cv_list_entry(basic_cv_list_entry&);
|
||||
void operator=(basic_cv_list_entry&);
|
||||
|
||||
public:
|
||||
explicit basic_cv_list_entry(detail::win32::handle_manager const& wake_sem_):
|
||||
semaphore(detail::win32::create_anonymous_semaphore(0,LONG_MAX)),
|
||||
wake_sem(wake_sem_.duplicate()),
|
||||
waiters(1),notified(false),references(0)
|
||||
{}
|
||||
|
||||
static bool no_waiters(boost::intrusive_ptr<basic_cv_list_entry> const& entry)
|
||||
{
|
||||
return !detail::interlocked_read_acquire(&entry->waiters);
|
||||
}
|
||||
|
||||
void add_waiter()
|
||||
{
|
||||
BOOST_INTERLOCKED_INCREMENT(&waiters);
|
||||
}
|
||||
|
||||
void remove_waiter()
|
||||
{
|
||||
BOOST_INTERLOCKED_DECREMENT(&waiters);
|
||||
}
|
||||
|
||||
void release(unsigned count_to_release)
|
||||
{
|
||||
notified=true;
|
||||
detail::win32::ReleaseSemaphore(semaphore,count_to_release,0);
|
||||
}
|
||||
|
||||
void release_waiters()
|
||||
{
|
||||
release(detail::interlocked_read_acquire(&waiters));
|
||||
}
|
||||
|
||||
bool is_notified() const
|
||||
{
|
||||
return notified;
|
||||
}
|
||||
|
||||
bool wait(timeout wait_until)
|
||||
{
|
||||
return this_thread::interruptible_wait(semaphore,wait_until);
|
||||
}
|
||||
|
||||
bool woken()
|
||||
{
|
||||
unsigned long const woken_result=detail::win32::WaitForSingleObject(wake_sem,0);
|
||||
BOOST_ASSERT((woken_result==detail::win32::timeout) || (woken_result==0));
|
||||
return woken_result==0;
|
||||
}
|
||||
|
||||
friend void intrusive_ptr_add_ref(basic_cv_list_entry * p);
|
||||
friend void intrusive_ptr_release(basic_cv_list_entry * p);
|
||||
};
|
||||
|
||||
inline void intrusive_ptr_add_ref(basic_cv_list_entry * p)
|
||||
{
|
||||
BOOST_INTERLOCKED_INCREMENT(&p->references);
|
||||
}
|
||||
|
||||
inline void intrusive_ptr_release(basic_cv_list_entry * p)
|
||||
{
|
||||
if(!BOOST_INTERLOCKED_DECREMENT(&p->references))
|
||||
{
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
|
||||
class basic_condition_variable
|
||||
{
|
||||
boost::mutex internal_mutex;
|
||||
long total_count;
|
||||
unsigned active_generation_count;
|
||||
|
||||
typedef basic_cv_list_entry list_entry;
|
||||
|
||||
typedef boost::intrusive_ptr<list_entry> entry_ptr;
|
||||
typedef std::vector<entry_ptr> generation_list;
|
||||
|
||||
generation_list generations;
|
||||
detail::win32::handle_manager wake_sem;
|
||||
|
||||
void wake_waiters(long count_to_wake)
|
||||
{
|
||||
detail::interlocked_write_release(&total_count,total_count-count_to_wake);
|
||||
detail::win32::ReleaseSemaphore(wake_sem,count_to_wake,0);
|
||||
}
|
||||
|
||||
template<typename lock_type>
|
||||
struct relocker
|
||||
{
|
||||
lock_type& lock;
|
||||
bool unlocked;
|
||||
|
||||
relocker(lock_type& lock_):
|
||||
lock(lock_),unlocked(false)
|
||||
{}
|
||||
void unlock()
|
||||
{
|
||||
lock.unlock();
|
||||
unlocked=true;
|
||||
}
|
||||
~relocker()
|
||||
{
|
||||
if(unlocked)
|
||||
{
|
||||
lock.lock();
|
||||
}
|
||||
|
||||
}
|
||||
private:
|
||||
relocker(relocker&);
|
||||
void operator=(relocker&);
|
||||
};
|
||||
|
||||
|
||||
entry_ptr get_wait_entry()
|
||||
{
|
||||
boost::lock_guard<boost::mutex> internal_lock(internal_mutex);
|
||||
|
||||
if(!wake_sem)
|
||||
{
|
||||
wake_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
|
||||
BOOST_ASSERT(wake_sem);
|
||||
}
|
||||
|
||||
detail::interlocked_write_release(&total_count,total_count+1);
|
||||
if(generations.empty() || generations.back()->is_notified())
|
||||
{
|
||||
entry_ptr new_entry(new list_entry(wake_sem));
|
||||
generations.push_back(new_entry);
|
||||
return new_entry;
|
||||
}
|
||||
else
|
||||
{
|
||||
generations.back()->add_waiter();
|
||||
return generations.back();
|
||||
}
|
||||
}
|
||||
|
||||
struct entry_manager
|
||||
{
|
||||
entry_ptr const entry;
|
||||
|
||||
entry_manager(entry_ptr const& entry_):
|
||||
entry(entry_)
|
||||
{}
|
||||
|
||||
~entry_manager()
|
||||
{
|
||||
entry->remove_waiter();
|
||||
}
|
||||
|
||||
list_entry* operator->()
|
||||
{
|
||||
return entry.get();
|
||||
}
|
||||
|
||||
private:
|
||||
void operator=(entry_manager&);
|
||||
entry_manager(entry_manager&);
|
||||
};
|
||||
|
||||
|
||||
protected:
|
||||
template<typename lock_type>
|
||||
bool do_wait(lock_type& lock,timeout wait_until)
|
||||
{
|
||||
relocker<lock_type> locker(lock);
|
||||
|
||||
entry_manager entry(get_wait_entry());
|
||||
|
||||
locker.unlock();
|
||||
|
||||
bool woken=false;
|
||||
while(!woken)
|
||||
{
|
||||
if(!entry->wait(wait_until))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
woken=entry->woken();
|
||||
}
|
||||
return woken;
|
||||
}
|
||||
|
||||
template<typename lock_type,typename predicate_type>
|
||||
bool do_wait(lock_type& m,timeout const& wait_until,predicate_type pred)
|
||||
{
|
||||
while (!pred())
|
||||
{
|
||||
if(!do_wait(m, wait_until))
|
||||
return pred();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
basic_condition_variable(const basic_condition_variable& other);
|
||||
basic_condition_variable& operator=(const basic_condition_variable& other);
|
||||
|
||||
public:
|
||||
basic_condition_variable():
|
||||
total_count(0),active_generation_count(0),wake_sem(0)
|
||||
{}
|
||||
|
||||
~basic_condition_variable()
|
||||
{}
|
||||
|
||||
void notify_one()
|
||||
{
|
||||
if(detail::interlocked_read_acquire(&total_count))
|
||||
{
|
||||
boost::lock_guard<boost::mutex> internal_lock(internal_mutex);
|
||||
if(!total_count)
|
||||
{
|
||||
return;
|
||||
}
|
||||
wake_waiters(1);
|
||||
|
||||
for(generation_list::iterator it=generations.begin(),
|
||||
end=generations.end();
|
||||
it!=end;++it)
|
||||
{
|
||||
(*it)->release(1);
|
||||
}
|
||||
generations.erase(std::remove_if(generations.begin(),generations.end(),&basic_cv_list_entry::no_waiters),generations.end());
|
||||
}
|
||||
}
|
||||
|
||||
void notify_all()
|
||||
{
|
||||
if(detail::interlocked_read_acquire(&total_count))
|
||||
{
|
||||
boost::lock_guard<boost::mutex> internal_lock(internal_mutex);
|
||||
if(!total_count)
|
||||
{
|
||||
return;
|
||||
}
|
||||
wake_waiters(total_count);
|
||||
for(generation_list::iterator it=generations.begin(),
|
||||
end=generations.end();
|
||||
it!=end;++it)
|
||||
{
|
||||
(*it)->release_waiters();
|
||||
}
|
||||
generations.clear();
|
||||
wake_sem=detail::win32::handle(0);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
class condition_variable:
|
||||
private detail::basic_condition_variable
|
||||
{
|
||||
private:
|
||||
condition_variable(condition_variable&);
|
||||
void operator=(condition_variable&);
|
||||
public:
|
||||
condition_variable()
|
||||
{}
|
||||
|
||||
using detail::basic_condition_variable::notify_one;
|
||||
using detail::basic_condition_variable::notify_all;
|
||||
|
||||
void wait(unique_lock<mutex>& m)
|
||||
{
|
||||
do_wait(m,detail::timeout::sentinel());
|
||||
}
|
||||
|
||||
template<typename predicate_type>
|
||||
void wait(unique_lock<mutex>& m,predicate_type pred)
|
||||
{
|
||||
while(!pred()) wait(m);
|
||||
}
|
||||
|
||||
|
||||
bool timed_wait(unique_lock<mutex>& m,boost::system_time const& wait_until)
|
||||
{
|
||||
return do_wait(m,wait_until);
|
||||
}
|
||||
|
||||
bool timed_wait(unique_lock<mutex>& m,boost::xtime const& wait_until)
|
||||
{
|
||||
return do_wait(m,system_time(wait_until));
|
||||
}
|
||||
template<typename duration_type>
|
||||
bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration)
|
||||
{
|
||||
return do_wait(m,wait_duration.total_milliseconds());
|
||||
}
|
||||
|
||||
template<typename predicate_type>
|
||||
bool timed_wait(unique_lock<mutex>& m,boost::system_time const& wait_until,predicate_type pred)
|
||||
{
|
||||
return do_wait(m,wait_until,pred);
|
||||
}
|
||||
template<typename predicate_type>
|
||||
bool timed_wait(unique_lock<mutex>& m,boost::xtime const& wait_until,predicate_type pred)
|
||||
{
|
||||
return do_wait(m,system_time(wait_until),pred);
|
||||
}
|
||||
template<typename duration_type,typename predicate_type>
|
||||
bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration,predicate_type pred)
|
||||
{
|
||||
return do_wait(m,wait_duration.total_milliseconds(),pred);
|
||||
}
|
||||
};
|
||||
|
||||
class condition_variable_any:
|
||||
private detail::basic_condition_variable
|
||||
{
|
||||
private:
|
||||
condition_variable_any(condition_variable_any&);
|
||||
void operator=(condition_variable_any&);
|
||||
public:
|
||||
condition_variable_any()
|
||||
{}
|
||||
|
||||
using detail::basic_condition_variable::notify_one;
|
||||
using detail::basic_condition_variable::notify_all;
|
||||
|
||||
template<typename lock_type>
|
||||
void wait(lock_type& m)
|
||||
{
|
||||
do_wait(m,detail::timeout::sentinel());
|
||||
}
|
||||
|
||||
template<typename lock_type,typename predicate_type>
|
||||
void wait(lock_type& m,predicate_type pred)
|
||||
{
|
||||
while(!pred()) wait(m);
|
||||
}
|
||||
|
||||
template<typename lock_type>
|
||||
bool timed_wait(lock_type& m,boost::system_time const& wait_until)
|
||||
{
|
||||
return do_wait(m,wait_until);
|
||||
}
|
||||
|
||||
template<typename lock_type>
|
||||
bool timed_wait(lock_type& m,boost::xtime const& wait_until)
|
||||
{
|
||||
return do_wait(m,system_time(wait_until));
|
||||
}
|
||||
|
||||
template<typename lock_type,typename duration_type>
|
||||
bool timed_wait(lock_type& m,duration_type const& wait_duration)
|
||||
{
|
||||
return do_wait(m,wait_duration.total_milliseconds());
|
||||
}
|
||||
|
||||
template<typename lock_type,typename predicate_type>
|
||||
bool timed_wait(lock_type& m,boost::system_time const& wait_until,predicate_type pred)
|
||||
{
|
||||
return do_wait(m,wait_until,pred);
|
||||
}
|
||||
|
||||
template<typename lock_type,typename predicate_type>
|
||||
bool timed_wait(lock_type& m,boost::xtime const& wait_until,predicate_type pred)
|
||||
{
|
||||
return do_wait(m,system_time(wait_until),pred);
|
||||
}
|
||||
|
||||
template<typename lock_type,typename duration_type,typename predicate_type>
|
||||
bool timed_wait(lock_type& m,duration_type const& wait_duration,predicate_type pred)
|
||||
{
|
||||
return do_wait(m,wait_duration.total_milliseconds(),pred);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
80
include/boost/thread/win32/interlocked_read.hpp
Normal file
80
include/boost/thread/win32/interlocked_read.hpp
Normal file
@@ -0,0 +1,80 @@
|
||||
#ifndef BOOST_THREAD_DETAIL_INTERLOCKED_READ_WIN32_HPP
|
||||
#define BOOST_THREAD_DETAIL_INTERLOCKED_READ_WIN32_HPP
|
||||
|
||||
// interlocked_read_win32.hpp
|
||||
//
|
||||
// (C) Copyright 2005-8 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/detail/interlocked.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
|
||||
extern "C" void _ReadWriteBarrier(void);
|
||||
#pragma intrinsic(_ReadWriteBarrier)
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
inline long interlocked_read_acquire(long volatile* x)
|
||||
{
|
||||
long const res=*x;
|
||||
_ReadWriteBarrier();
|
||||
return res;
|
||||
}
|
||||
inline void* interlocked_read_acquire(void* volatile* x)
|
||||
{
|
||||
void* const res=*x;
|
||||
_ReadWriteBarrier();
|
||||
return res;
|
||||
}
|
||||
|
||||
inline void interlocked_write_release(long volatile* x,long value)
|
||||
{
|
||||
_ReadWriteBarrier();
|
||||
*x=value;
|
||||
}
|
||||
inline void interlocked_write_release(void* volatile* x,void* value)
|
||||
{
|
||||
_ReadWriteBarrier();
|
||||
*x=value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
inline long interlocked_read_acquire(long volatile* x)
|
||||
{
|
||||
return BOOST_INTERLOCKED_COMPARE_EXCHANGE(x,0,0);
|
||||
}
|
||||
inline void* interlocked_read_acquire(void* volatile* x)
|
||||
{
|
||||
return BOOST_INTERLOCKED_COMPARE_EXCHANGE_POINTER(x,0,0);
|
||||
}
|
||||
inline void interlocked_write_release(long volatile* x,long value)
|
||||
{
|
||||
BOOST_INTERLOCKED_EXCHANGE(x,value);
|
||||
}
|
||||
inline void interlocked_write_release(void* volatile* x,void* value)
|
||||
{
|
||||
BOOST_INTERLOCKED_EXCHANGE_POINTER(x,value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
65
include/boost/thread/win32/mutex.hpp
Normal file
65
include/boost/thread/win32/mutex.hpp
Normal file
@@ -0,0 +1,65 @@
|
||||
#ifndef BOOST_THREAD_WIN32_MUTEX_HPP
|
||||
#define BOOST_THREAD_WIN32_MUTEX_HPP
|
||||
// (C) Copyright 2005-7 Anthony Williams
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include "basic_timed_mutex.hpp"
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
typedef ::boost::detail::basic_timed_mutex underlying_mutex;
|
||||
}
|
||||
|
||||
class mutex:
|
||||
boost::noncopyable,
|
||||
public ::boost::detail::underlying_mutex
|
||||
{
|
||||
public:
|
||||
mutex()
|
||||
{
|
||||
initialize();
|
||||
}
|
||||
~mutex()
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
|
||||
typedef unique_lock<mutex> scoped_lock;
|
||||
typedef detail::try_lock_wrapper<mutex> scoped_try_lock;
|
||||
};
|
||||
|
||||
typedef mutex try_mutex;
|
||||
|
||||
class timed_mutex:
|
||||
boost::noncopyable,
|
||||
public ::boost::detail::basic_timed_mutex
|
||||
{
|
||||
public:
|
||||
timed_mutex()
|
||||
{
|
||||
initialize();
|
||||
}
|
||||
|
||||
~timed_mutex()
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
|
||||
typedef unique_lock<timed_mutex> scoped_timed_lock;
|
||||
typedef detail::try_lock_wrapper<timed_mutex> scoped_try_lock;
|
||||
typedef scoped_timed_lock scoped_lock;
|
||||
};
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
136
include/boost/thread/win32/once.hpp
Normal file
136
include/boost/thread/win32/once.hpp
Normal file
@@ -0,0 +1,136 @@
|
||||
#ifndef BOOST_THREAD_WIN32_ONCE_HPP
|
||||
#define BOOST_THREAD_WIN32_ONCE_HPP
|
||||
|
||||
// once.hpp
|
||||
//
|
||||
// (C) Copyright 2005-7 Anthony Williams
|
||||
// (C) Copyright 2005 John Maddock
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <cstring>
|
||||
#include <cstddef>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/detail/interlocked.hpp>
|
||||
#include <boost/thread/win32/thread_primitives.hpp>
|
||||
#include <boost/thread/win32/interlocked_read.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
#ifdef BOOST_NO_STDC_NAMESPACE
|
||||
namespace std
|
||||
{
|
||||
using ::memcpy;
|
||||
using ::ptrdiff_t;
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
typedef long once_flag;
|
||||
|
||||
#define BOOST_ONCE_INIT 0
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct win32_mutex_scoped_lock
|
||||
{
|
||||
void* const mutex_handle;
|
||||
explicit win32_mutex_scoped_lock(void* mutex_handle_):
|
||||
mutex_handle(mutex_handle_)
|
||||
{
|
||||
BOOST_VERIFY(!win32::WaitForSingleObject(mutex_handle,win32::infinite));
|
||||
}
|
||||
~win32_mutex_scoped_lock()
|
||||
{
|
||||
BOOST_VERIFY(win32::ReleaseMutex(mutex_handle)!=0);
|
||||
}
|
||||
private:
|
||||
void operator=(win32_mutex_scoped_lock&);
|
||||
};
|
||||
|
||||
#ifdef BOOST_NO_ANSI_APIS
|
||||
template <class I>
|
||||
void int_to_string(I p, wchar_t* buf)
|
||||
{
|
||||
for(unsigned i=0; i < sizeof(I)*2; ++i,++buf)
|
||||
{
|
||||
*buf = L'A' + static_cast<wchar_t>((p >> (i*4)) & 0x0f);
|
||||
}
|
||||
*buf = 0;
|
||||
}
|
||||
#else
|
||||
template <class I>
|
||||
void int_to_string(I p, char* buf)
|
||||
{
|
||||
for(unsigned i=0; i < sizeof(I)*2; ++i,++buf)
|
||||
{
|
||||
*buf = 'A' + static_cast<char>((p >> (i*4)) & 0x0f);
|
||||
}
|
||||
*buf = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
// create a named mutex. It doesn't really matter what this name is
|
||||
// as long as it is unique both to this process, and to the address of "flag":
|
||||
inline void* create_once_mutex(void* flag_address)
|
||||
{
|
||||
|
||||
#ifdef BOOST_NO_ANSI_APIS
|
||||
typedef wchar_t char_type;
|
||||
static const char_type fixed_mutex_name[]=L"{C15730E2-145C-4c5e-B005-3BC753F42475}-once-flag";
|
||||
#else
|
||||
typedef char char_type;
|
||||
static const char_type fixed_mutex_name[]="{C15730E2-145C-4c5e-B005-3BC753F42475}-once-flag";
|
||||
#endif
|
||||
unsigned const once_mutex_name_fixed_buffer_size=sizeof(fixed_mutex_name)/sizeof(char_type);
|
||||
unsigned const once_mutex_name_fixed_length=once_mutex_name_fixed_buffer_size-1;
|
||||
unsigned const once_mutex_name_length=once_mutex_name_fixed_buffer_size+sizeof(void*)*2+sizeof(unsigned long)*2;
|
||||
char_type mutex_name[once_mutex_name_length];
|
||||
|
||||
std::memcpy(mutex_name,fixed_mutex_name,sizeof(fixed_mutex_name));
|
||||
|
||||
BOOST_STATIC_ASSERT(sizeof(void*) == sizeof(std::ptrdiff_t));
|
||||
detail::int_to_string(reinterpret_cast<std::ptrdiff_t>(flag_address), mutex_name + once_mutex_name_fixed_length);
|
||||
detail::int_to_string(win32::GetCurrentProcessId(), mutex_name + once_mutex_name_fixed_length + sizeof(void*)*2);
|
||||
|
||||
#ifdef BOOST_NO_ANSI_APIS
|
||||
return win32::CreateMutexW(0, 0, mutex_name);
|
||||
#else
|
||||
return win32::CreateMutexA(0, 0, mutex_name);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
template<typename Function>
|
||||
void call_once(once_flag& flag,Function f)
|
||||
{
|
||||
// Try for a quick win: if the procedure has already been called
|
||||
// just skip through:
|
||||
long const function_complete_flag_value=0xc15730e2;
|
||||
|
||||
if(::boost::detail::interlocked_read_acquire(&flag)!=function_complete_flag_value)
|
||||
{
|
||||
void* const mutex_handle(::boost::detail::create_once_mutex(&flag));
|
||||
BOOST_ASSERT(mutex_handle);
|
||||
detail::win32::handle_manager const closer(mutex_handle);
|
||||
detail::win32_mutex_scoped_lock const lock(mutex_handle);
|
||||
|
||||
if(flag!=function_complete_flag_value)
|
||||
{
|
||||
f();
|
||||
BOOST_INTERLOCKED_EXCHANGE(&flag,function_complete_flag_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
64
include/boost/thread/win32/recursive_mutex.hpp
Normal file
64
include/boost/thread/win32/recursive_mutex.hpp
Normal file
@@ -0,0 +1,64 @@
|
||||
#ifndef BOOST_RECURSIVE_MUTEX_WIN32_HPP
|
||||
#define BOOST_RECURSIVE_MUTEX_WIN32_HPP
|
||||
|
||||
// recursive_mutex.hpp
|
||||
//
|
||||
// (C) Copyright 2006-7 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
#include "basic_recursive_mutex.hpp"
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
class recursive_mutex:
|
||||
boost::noncopyable,
|
||||
public ::boost::detail::basic_recursive_mutex
|
||||
{
|
||||
public:
|
||||
recursive_mutex()
|
||||
{
|
||||
::boost::detail::basic_recursive_mutex::initialize();
|
||||
}
|
||||
~recursive_mutex()
|
||||
{
|
||||
::boost::detail::basic_recursive_mutex::destroy();
|
||||
}
|
||||
|
||||
typedef unique_lock<recursive_mutex> scoped_lock;
|
||||
typedef detail::try_lock_wrapper<recursive_mutex> scoped_try_lock;
|
||||
};
|
||||
|
||||
typedef recursive_mutex recursive_try_mutex;
|
||||
|
||||
class recursive_timed_mutex:
|
||||
boost::noncopyable,
|
||||
public ::boost::detail::basic_recursive_timed_mutex
|
||||
{
|
||||
public:
|
||||
recursive_timed_mutex()
|
||||
{
|
||||
::boost::detail::basic_recursive_timed_mutex::initialize();
|
||||
}
|
||||
~recursive_timed_mutex()
|
||||
{
|
||||
::boost::detail::basic_recursive_timed_mutex::destroy();
|
||||
}
|
||||
|
||||
typedef unique_lock<recursive_timed_mutex> scoped_timed_lock;
|
||||
typedef detail::try_lock_wrapper<recursive_timed_mutex> scoped_try_lock;
|
||||
typedef scoped_timed_lock scoped_lock;
|
||||
};
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
566
include/boost/thread/win32/shared_mutex.hpp
Normal file
566
include/boost/thread/win32/shared_mutex.hpp
Normal file
@@ -0,0 +1,566 @@
|
||||
#ifndef BOOST_THREAD_WIN32_SHARED_MUTEX_HPP
|
||||
#define BOOST_THREAD_WIN32_SHARED_MUTEX_HPP
|
||||
|
||||
// (C) Copyright 2006-8 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/detail/interlocked.hpp>
|
||||
#include <boost/thread/win32/thread_primitives.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <limits.h>
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
class shared_mutex:
|
||||
private boost::noncopyable
|
||||
{
|
||||
private:
|
||||
struct state_data
|
||||
{
|
||||
unsigned shared_count:11,
|
||||
shared_waiting:11,
|
||||
exclusive:1,
|
||||
upgrade:1,
|
||||
exclusive_waiting:7,
|
||||
exclusive_waiting_blocked:1;
|
||||
|
||||
friend bool operator==(state_data const& lhs,state_data const& rhs)
|
||||
{
|
||||
return *reinterpret_cast<unsigned const*>(&lhs)==*reinterpret_cast<unsigned const*>(&rhs);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
T interlocked_compare_exchange(T* target,T new_value,T comparand)
|
||||
{
|
||||
BOOST_STATIC_ASSERT(sizeof(T)==sizeof(long));
|
||||
long const res=BOOST_INTERLOCKED_COMPARE_EXCHANGE(reinterpret_cast<long*>(target),
|
||||
*reinterpret_cast<long*>(&new_value),
|
||||
*reinterpret_cast<long*>(&comparand));
|
||||
return *reinterpret_cast<T const*>(&res);
|
||||
}
|
||||
|
||||
state_data state;
|
||||
detail::win32::handle semaphores[2];
|
||||
detail::win32::handle &unlock_sem;
|
||||
detail::win32::handle &exclusive_sem;
|
||||
detail::win32::handle upgrade_sem;
|
||||
|
||||
void release_waiters(state_data old_state)
|
||||
{
|
||||
if(old_state.exclusive_waiting)
|
||||
{
|
||||
BOOST_VERIFY(detail::win32::ReleaseSemaphore(exclusive_sem,1,0)!=0);
|
||||
}
|
||||
|
||||
if(old_state.shared_waiting || old_state.exclusive_waiting)
|
||||
{
|
||||
BOOST_VERIFY(detail::win32::ReleaseSemaphore(unlock_sem,old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
shared_mutex():
|
||||
unlock_sem(semaphores[0]),
|
||||
exclusive_sem(semaphores[1])
|
||||
{
|
||||
unlock_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
|
||||
exclusive_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
|
||||
upgrade_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
|
||||
state_data state_={0};
|
||||
state=state_;
|
||||
}
|
||||
|
||||
~shared_mutex()
|
||||
{
|
||||
detail::win32::CloseHandle(upgrade_sem);
|
||||
detail::win32::CloseHandle(unlock_sem);
|
||||
detail::win32::CloseHandle(exclusive_sem);
|
||||
}
|
||||
|
||||
bool try_lock_shared()
|
||||
{
|
||||
state_data old_state=state;
|
||||
for(;;)
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
if(!new_state.exclusive && !new_state.exclusive_waiting_blocked)
|
||||
{
|
||||
++new_state.shared_count;
|
||||
}
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
return !(old_state.exclusive| old_state.exclusive_waiting_blocked);
|
||||
}
|
||||
|
||||
void lock_shared()
|
||||
{
|
||||
BOOST_VERIFY(timed_lock_shared(::boost::detail::get_system_time_sentinel()));
|
||||
}
|
||||
|
||||
template<typename TimeDuration>
|
||||
bool timed_lock_shared(TimeDuration const & relative_time)
|
||||
{
|
||||
return timed_lock_shared(get_system_time()+relative_time);
|
||||
}
|
||||
|
||||
bool timed_lock_shared(boost::system_time const& wait_until)
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
state_data old_state=state;
|
||||
for(;;)
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
if(new_state.exclusive || new_state.exclusive_waiting_blocked)
|
||||
{
|
||||
++new_state.shared_waiting;
|
||||
}
|
||||
else
|
||||
{
|
||||
++new_state.shared_count;
|
||||
}
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
|
||||
if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned long const res=detail::win32::WaitForSingleObject(unlock_sem,::boost::detail::get_milliseconds_until(wait_until));
|
||||
if(res==detail::win32::timeout)
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
if(new_state.exclusive || new_state.exclusive_waiting_blocked)
|
||||
{
|
||||
if(new_state.shared_waiting)
|
||||
{
|
||||
--new_state.shared_waiting;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
++new_state.shared_count;
|
||||
}
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
|
||||
if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(res==0);
|
||||
}
|
||||
}
|
||||
|
||||
void unlock_shared()
|
||||
{
|
||||
state_data old_state=state;
|
||||
for(;;)
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
bool const last_reader=!--new_state.shared_count;
|
||||
|
||||
if(last_reader)
|
||||
{
|
||||
if(new_state.upgrade)
|
||||
{
|
||||
new_state.upgrade=false;
|
||||
new_state.exclusive=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(new_state.exclusive_waiting)
|
||||
{
|
||||
--new_state.exclusive_waiting;
|
||||
new_state.exclusive_waiting_blocked=false;
|
||||
}
|
||||
new_state.shared_waiting=0;
|
||||
}
|
||||
}
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
if(last_reader)
|
||||
{
|
||||
if(old_state.upgrade)
|
||||
{
|
||||
BOOST_VERIFY(detail::win32::ReleaseSemaphore(upgrade_sem,1,0)!=0);
|
||||
}
|
||||
else
|
||||
{
|
||||
release_waiters(old_state);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
BOOST_VERIFY(timed_lock(::boost::detail::get_system_time_sentinel()));
|
||||
}
|
||||
|
||||
template<typename TimeDuration>
|
||||
bool timed_lock(TimeDuration const & relative_time)
|
||||
{
|
||||
return timed_lock(get_system_time()+relative_time);
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
state_data old_state=state;
|
||||
for(;;)
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
if(new_state.shared_count || new_state.exclusive)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
new_state.exclusive=true;
|
||||
}
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool timed_lock(boost::system_time const& wait_until)
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
state_data old_state=state;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
if(new_state.shared_count || new_state.exclusive)
|
||||
{
|
||||
++new_state.exclusive_waiting;
|
||||
new_state.exclusive_waiting_blocked=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
new_state.exclusive=true;
|
||||
}
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
|
||||
if(!old_state.shared_count && !old_state.exclusive)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
unsigned long const wait_res=detail::win32::WaitForMultipleObjects(2,semaphores,true,::boost::detail::get_milliseconds_until(wait_until));
|
||||
if(wait_res==detail::win32::timeout)
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
if(new_state.shared_count || new_state.exclusive)
|
||||
{
|
||||
if(new_state.exclusive_waiting)
|
||||
{
|
||||
if(!--new_state.exclusive_waiting)
|
||||
{
|
||||
new_state.exclusive_waiting_blocked=false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
new_state.exclusive=true;
|
||||
}
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
if(!old_state.shared_count && !old_state.exclusive)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
BOOST_ASSERT(wait_res<2);
|
||||
}
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
state_data old_state=state;
|
||||
for(;;)
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
new_state.exclusive=false;
|
||||
if(new_state.exclusive_waiting)
|
||||
{
|
||||
--new_state.exclusive_waiting;
|
||||
new_state.exclusive_waiting_blocked=false;
|
||||
}
|
||||
new_state.shared_waiting=0;
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
release_waiters(old_state);
|
||||
}
|
||||
|
||||
void lock_upgrade()
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
state_data old_state=state;
|
||||
for(;;)
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
if(new_state.exclusive || new_state.exclusive_waiting_blocked || new_state.upgrade)
|
||||
{
|
||||
++new_state.shared_waiting;
|
||||
}
|
||||
else
|
||||
{
|
||||
++new_state.shared_count;
|
||||
new_state.upgrade=true;
|
||||
}
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
|
||||
if(!(old_state.exclusive|| old_state.exclusive_waiting_blocked|| old_state.upgrade))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BOOST_VERIFY(!detail::win32::WaitForSingleObject(unlock_sem,detail::win32::infinite));
|
||||
}
|
||||
}
|
||||
|
||||
bool try_lock_upgrade()
|
||||
{
|
||||
state_data old_state=state;
|
||||
for(;;)
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
if(new_state.exclusive || new_state.exclusive_waiting_blocked || new_state.upgrade)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
++new_state.shared_count;
|
||||
new_state.upgrade=true;
|
||||
}
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void unlock_upgrade()
|
||||
{
|
||||
state_data old_state=state;
|
||||
for(;;)
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
new_state.upgrade=false;
|
||||
bool const last_reader=!--new_state.shared_count;
|
||||
|
||||
if(last_reader)
|
||||
{
|
||||
if(new_state.exclusive_waiting)
|
||||
{
|
||||
--new_state.exclusive_waiting;
|
||||
new_state.exclusive_waiting_blocked=false;
|
||||
}
|
||||
new_state.shared_waiting=0;
|
||||
}
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
if(last_reader)
|
||||
{
|
||||
release_waiters(old_state);
|
||||
}
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
}
|
||||
|
||||
void unlock_upgrade_and_lock()
|
||||
{
|
||||
state_data old_state=state;
|
||||
for(;;)
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
bool const last_reader=!--new_state.shared_count;
|
||||
|
||||
if(last_reader)
|
||||
{
|
||||
new_state.upgrade=false;
|
||||
new_state.exclusive=true;
|
||||
}
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
if(!last_reader)
|
||||
{
|
||||
BOOST_VERIFY(!detail::win32::WaitForSingleObject(upgrade_sem,detail::win32::infinite));
|
||||
}
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
}
|
||||
|
||||
void unlock_and_lock_upgrade()
|
||||
{
|
||||
state_data old_state=state;
|
||||
for(;;)
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
new_state.exclusive=false;
|
||||
new_state.upgrade=true;
|
||||
++new_state.shared_count;
|
||||
if(new_state.exclusive_waiting)
|
||||
{
|
||||
--new_state.exclusive_waiting;
|
||||
new_state.exclusive_waiting_blocked=false;
|
||||
}
|
||||
new_state.shared_waiting=0;
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
release_waiters(old_state);
|
||||
}
|
||||
|
||||
void unlock_and_lock_shared()
|
||||
{
|
||||
state_data old_state=state;
|
||||
for(;;)
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
new_state.exclusive=false;
|
||||
++new_state.shared_count;
|
||||
if(new_state.exclusive_waiting)
|
||||
{
|
||||
--new_state.exclusive_waiting;
|
||||
new_state.exclusive_waiting_blocked=false;
|
||||
}
|
||||
new_state.shared_waiting=0;
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
release_waiters(old_state);
|
||||
}
|
||||
|
||||
void unlock_upgrade_and_lock_shared()
|
||||
{
|
||||
state_data old_state=state;
|
||||
for(;;)
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
new_state.upgrade=false;
|
||||
if(new_state.exclusive_waiting)
|
||||
{
|
||||
--new_state.exclusive_waiting;
|
||||
new_state.exclusive_waiting_blocked=false;
|
||||
}
|
||||
new_state.shared_waiting=0;
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
release_waiters(old_state);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
178
include/boost/thread/win32/thread_data.hpp
Normal file
178
include/boost/thread/win32/thread_data.hpp
Normal file
@@ -0,0 +1,178 @@
|
||||
#ifndef BOOST_THREAD_PTHREAD_THREAD_DATA_HPP
|
||||
#define BOOST_THREAD_PTHREAD_THREAD_DATA_HPP
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2008 Anthony Williams
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/intrusive_ptr.hpp>
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#include "thread_primitives.hpp"
|
||||
#include "thread_heap_alloc.hpp"
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
struct thread_exit_callback_node;
|
||||
struct tss_data_node;
|
||||
|
||||
struct thread_data_base;
|
||||
void intrusive_ptr_add_ref(thread_data_base * p);
|
||||
void intrusive_ptr_release(thread_data_base * p);
|
||||
|
||||
struct thread_data_base
|
||||
{
|
||||
long count;
|
||||
detail::win32::handle_manager thread_handle;
|
||||
detail::win32::handle_manager interruption_handle;
|
||||
boost::detail::thread_exit_callback_node* thread_exit_callbacks;
|
||||
boost::detail::tss_data_node* tss_data;
|
||||
bool interruption_enabled;
|
||||
unsigned id;
|
||||
|
||||
thread_data_base():
|
||||
count(0),thread_handle(detail::win32::invalid_handle_value),
|
||||
interruption_handle(create_anonymous_event(detail::win32::manual_reset_event,detail::win32::event_initially_reset)),
|
||||
thread_exit_callbacks(0),tss_data(0),
|
||||
interruption_enabled(true),
|
||||
id(0)
|
||||
{}
|
||||
virtual ~thread_data_base()
|
||||
{}
|
||||
|
||||
friend void intrusive_ptr_add_ref(thread_data_base * p)
|
||||
{
|
||||
BOOST_INTERLOCKED_INCREMENT(&p->count);
|
||||
}
|
||||
|
||||
friend void intrusive_ptr_release(thread_data_base * p)
|
||||
{
|
||||
if(!BOOST_INTERLOCKED_DECREMENT(&p->count))
|
||||
{
|
||||
detail::heap_delete(p);
|
||||
}
|
||||
}
|
||||
|
||||
void interrupt()
|
||||
{
|
||||
BOOST_VERIFY(detail::win32::SetEvent(interruption_handle)!=0);
|
||||
}
|
||||
|
||||
typedef detail::win32::handle native_handle_type;
|
||||
|
||||
virtual void run()=0;
|
||||
};
|
||||
|
||||
typedef boost::intrusive_ptr<detail::thread_data_base> thread_data_ptr;
|
||||
|
||||
struct timeout
|
||||
{
|
||||
unsigned long start;
|
||||
uintmax_t milliseconds;
|
||||
bool relative;
|
||||
boost::system_time abs_time;
|
||||
|
||||
static unsigned long const max_non_infinite_wait=0xfffffffe;
|
||||
|
||||
timeout(uintmax_t milliseconds_):
|
||||
start(win32::GetTickCount()),
|
||||
milliseconds(milliseconds_),
|
||||
relative(true),
|
||||
abs_time(boost::get_system_time())
|
||||
{}
|
||||
|
||||
timeout(boost::system_time const& abs_time_):
|
||||
start(win32::GetTickCount()),
|
||||
milliseconds(0),
|
||||
relative(false),
|
||||
abs_time(abs_time_)
|
||||
{}
|
||||
|
||||
struct remaining_time
|
||||
{
|
||||
bool more;
|
||||
unsigned long milliseconds;
|
||||
|
||||
remaining_time(uintmax_t remaining):
|
||||
more(remaining>max_non_infinite_wait),
|
||||
milliseconds(more?max_non_infinite_wait:(unsigned long)remaining)
|
||||
{}
|
||||
};
|
||||
|
||||
remaining_time remaining_milliseconds() const
|
||||
{
|
||||
if(is_sentinel())
|
||||
{
|
||||
return remaining_time(win32::infinite);
|
||||
}
|
||||
else if(relative)
|
||||
{
|
||||
unsigned long const now=win32::GetTickCount();
|
||||
unsigned long const elapsed=now-start;
|
||||
return remaining_time((elapsed<milliseconds)?(milliseconds-elapsed):0);
|
||||
}
|
||||
else
|
||||
{
|
||||
system_time const now=get_system_time();
|
||||
if(abs_time<=now)
|
||||
{
|
||||
return remaining_time(0);
|
||||
}
|
||||
return remaining_time((abs_time-now).total_milliseconds()+1);
|
||||
}
|
||||
}
|
||||
|
||||
bool is_sentinel() const
|
||||
{
|
||||
return milliseconds==~uintmax_t(0);
|
||||
}
|
||||
|
||||
|
||||
static timeout sentinel()
|
||||
{
|
||||
return timeout(sentinel_type());
|
||||
}
|
||||
private:
|
||||
struct sentinel_type
|
||||
{};
|
||||
|
||||
explicit timeout(sentinel_type):
|
||||
start(0),milliseconds(~uintmax_t(0)),relative(true)
|
||||
{}
|
||||
};
|
||||
}
|
||||
|
||||
namespace this_thread
|
||||
{
|
||||
void BOOST_THREAD_DECL yield();
|
||||
|
||||
bool BOOST_THREAD_DECL interruptible_wait(detail::win32::handle handle_to_wait_for,detail::timeout target_time);
|
||||
inline void interruptible_wait(unsigned long milliseconds)
|
||||
{
|
||||
interruptible_wait(detail::win32::invalid_handle_value,milliseconds);
|
||||
}
|
||||
inline void interruptible_wait(system_time const& abs_time)
|
||||
{
|
||||
interruptible_wait(detail::win32::invalid_handle_value,abs_time);
|
||||
}
|
||||
|
||||
template<typename TimeDuration>
|
||||
inline void sleep(TimeDuration const& rel_time)
|
||||
{
|
||||
interruptible_wait(static_cast<unsigned long>(rel_time.total_milliseconds()));
|
||||
}
|
||||
inline void sleep(system_time const& abs_time)
|
||||
{
|
||||
interruptible_wait(abs_time);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
397
include/boost/thread/win32/thread_heap_alloc.hpp
Normal file
397
include/boost/thread/win32/thread_heap_alloc.hpp
Normal file
@@ -0,0 +1,397 @@
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
#ifndef THREAD_HEAP_ALLOC_HPP
|
||||
#define THREAD_HEAP_ALLOC_HPP
|
||||
#include <new>
|
||||
#include "thread_primitives.hpp"
|
||||
#include <stdexcept>
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#if defined( BOOST_USE_WINDOWS_H )
|
||||
# include <windows.h>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
namespace win32
|
||||
{
|
||||
using ::GetProcessHeap;
|
||||
using ::HeapAlloc;
|
||||
using ::HeapFree;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
# ifdef HeapAlloc
|
||||
# undef HeapAlloc
|
||||
# endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
namespace win32
|
||||
{
|
||||
extern "C"
|
||||
{
|
||||
__declspec(dllimport) handle __stdcall GetProcessHeap();
|
||||
__declspec(dllimport) void* __stdcall HeapAlloc(handle,unsigned long,ulong_ptr);
|
||||
__declspec(dllimport) int __stdcall HeapFree(handle,unsigned long,void*);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
inline BOOST_THREAD_DECL void* allocate_raw_heap_memory(unsigned size)
|
||||
{
|
||||
void* const heap_memory=detail::win32::HeapAlloc(detail::win32::GetProcessHeap(),0,size);
|
||||
if(!heap_memory)
|
||||
{
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
return heap_memory;
|
||||
}
|
||||
|
||||
inline BOOST_THREAD_DECL void free_raw_heap_memory(void* heap_memory)
|
||||
{
|
||||
BOOST_VERIFY(detail::win32::HeapFree(detail::win32::GetProcessHeap(),0,heap_memory)!=0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline T* heap_new()
|
||||
{
|
||||
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
|
||||
try
|
||||
{
|
||||
T* const data=new (heap_memory) T();
|
||||
return data;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
free_raw_heap_memory(heap_memory);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef BOOST_HAS_RVALUE_REFS
|
||||
template<typename T,typename A1>
|
||||
inline T* heap_new(A1&& a1)
|
||||
{
|
||||
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
|
||||
try
|
||||
{
|
||||
T* const data=new (heap_memory) T(static_cast<A1&&>(a1));
|
||||
return data;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
free_raw_heap_memory(heap_memory);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
template<typename T,typename A1,typename A2>
|
||||
inline T* heap_new(A1&& a1,A2&& a2)
|
||||
{
|
||||
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
|
||||
try
|
||||
{
|
||||
T* const data=new (heap_memory) T(static_cast<A1&&>(a1),static_cast<A2&&>(a2));
|
||||
return data;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
free_raw_heap_memory(heap_memory);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3>
|
||||
inline T* heap_new(A1&& a1,A2&& a2,A3&& a3)
|
||||
{
|
||||
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
|
||||
try
|
||||
{
|
||||
T* const data=new (heap_memory) T(static_cast<A1&&>(a1),static_cast<A2&&>(a2),
|
||||
static_cast<A3&&>(a3));
|
||||
return data;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
free_raw_heap_memory(heap_memory);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1&& a1,A2&& a2,A3&& a3,A4&& a4)
|
||||
{
|
||||
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
|
||||
try
|
||||
{
|
||||
T* const data=new (heap_memory) T(static_cast<A1&&>(a1),static_cast<A2&&>(a2),
|
||||
static_cast<A3&&>(a3),static_cast<A4&&>(a4));
|
||||
return data;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
free_raw_heap_memory(heap_memory);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
#else
|
||||
template<typename T,typename A1>
|
||||
inline T* heap_new_impl(A1 a1)
|
||||
{
|
||||
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
|
||||
try
|
||||
{
|
||||
T* const data=new (heap_memory) T(a1);
|
||||
return data;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
free_raw_heap_memory(heap_memory);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T,typename A1,typename A2>
|
||||
inline T* heap_new_impl(A1 a1,A2 a2)
|
||||
{
|
||||
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
|
||||
try
|
||||
{
|
||||
T* const data=new (heap_memory) T(a1,a2);
|
||||
return data;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
free_raw_heap_memory(heap_memory);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T,typename A1,typename A2,typename A3>
|
||||
inline T* heap_new_impl(A1 a1,A2 a2,A3 a3)
|
||||
{
|
||||
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
|
||||
try
|
||||
{
|
||||
T* const data=new (heap_memory) T(a1,a2,a3);
|
||||
return data;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
free_raw_heap_memory(heap_memory);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new_impl(A1 a1,A2 a2,A3 a3,A4 a4)
|
||||
{
|
||||
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
|
||||
try
|
||||
{
|
||||
T* const data=new (heap_memory) T(a1,a2,a3,a4);
|
||||
return data;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
free_raw_heap_memory(heap_memory);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename T,typename A1>
|
||||
inline T* heap_new(A1 const& a1)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&>(a1);
|
||||
}
|
||||
template<typename T,typename A1>
|
||||
inline T* heap_new(A1& a1)
|
||||
{
|
||||
return heap_new_impl<T,A1&>(a1);
|
||||
}
|
||||
|
||||
template<typename T,typename A1,typename A2>
|
||||
inline T* heap_new(A1 const& a1,A2 const& a2)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2 const&>(a1,a2);
|
||||
}
|
||||
template<typename T,typename A1,typename A2>
|
||||
inline T* heap_new(A1& a1,A2 const& a2)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2 const&>(a1,a2);
|
||||
}
|
||||
template<typename T,typename A1,typename A2>
|
||||
inline T* heap_new(A1 const& a1,A2& a2)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2&>(a1,a2);
|
||||
}
|
||||
template<typename T,typename A1,typename A2>
|
||||
inline T* heap_new(A1& a1,A2& a2)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2&>(a1,a2);
|
||||
}
|
||||
|
||||
template<typename T,typename A1,typename A2,typename A3>
|
||||
inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2 const&,A3 const&>(a1,a2,a3);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3>
|
||||
inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2 const&,A3 const&>(a1,a2,a3);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3>
|
||||
inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2&,A3 const&>(a1,a2,a3);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3>
|
||||
inline T* heap_new(A1& a1,A2& a2,A3 const& a3)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2&,A3 const&>(a1,a2,a3);
|
||||
}
|
||||
|
||||
template<typename T,typename A1,typename A2,typename A3>
|
||||
inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2 const&,A3&>(a1,a2,a3);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3>
|
||||
inline T* heap_new(A1& a1,A2 const& a2,A3& a3)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2 const&,A3&>(a1,a2,a3);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3>
|
||||
inline T* heap_new(A1 const& a1,A2& a2,A3& a3)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2&,A3&>(a1,a2,a3);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3>
|
||||
inline T* heap_new(A1& a1,A2& a2,A3& a3)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2&,A3&>(a1,a2,a3);
|
||||
}
|
||||
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3,A4 const& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2 const&,A3 const&,A4 const&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3,A4 const& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2 const&,A3 const&,A4 const&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3,A4 const& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2&,A3 const&,A4 const&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1& a1,A2& a2,A3 const& a3,A4 const& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2&,A3 const&,A4 const&>(a1,a2,a3,a4);
|
||||
}
|
||||
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3,A4 const& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2 const&,A3&,A4 const&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1& a1,A2 const& a2,A3& a3,A4 const& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2 const&,A3&,A4 const&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1 const& a1,A2& a2,A3& a3,A4 const& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2&,A3&,A4 const&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1& a1,A2& a2,A3& a3,A4 const& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2&,A3&,A4 const&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3,A4& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2 const&,A3 const&,A4&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3,A4& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2 const&,A3 const&,A4&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3,A4& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2&,A3 const&,A4&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1& a1,A2& a2,A3 const& a3,A4& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2&,A3 const&,A4&>(a1,a2,a3,a4);
|
||||
}
|
||||
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3,A4& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2 const&,A3&,A4&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1& a1,A2 const& a2,A3& a3,A4& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2 const&,A3&,A4&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1 const& a1,A2& a2,A3& a3,A4& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2&,A3&,A4&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1& a1,A2& a2,A3& a3,A4& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2&,A3&,A4&>(a1,a2,a3,a4);
|
||||
}
|
||||
|
||||
#endif
|
||||
template<typename T>
|
||||
inline void heap_delete(T* data)
|
||||
{
|
||||
data->~T();
|
||||
free_raw_heap_memory(data);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct do_heap_delete
|
||||
{
|
||||
void operator()(T* data) const
|
||||
{
|
||||
detail::heap_delete(data);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
|
||||
#endif
|
||||
398
include/boost/thread/win32/thread_primitives.hpp
Normal file
398
include/boost/thread/win32/thread_primitives.hpp
Normal file
@@ -0,0 +1,398 @@
|
||||
#ifndef BOOST_WIN32_THREAD_PRIMITIVES_HPP
|
||||
#define BOOST_WIN32_THREAD_PRIMITIVES_HPP
|
||||
|
||||
// win32_thread_primitives.hpp
|
||||
//
|
||||
// (C) Copyright 2005-7 Anthony Williams
|
||||
// (C) Copyright 2007 David Deakins
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/detail/interlocked.hpp>
|
||||
#include <algorithm>
|
||||
|
||||
#if defined( BOOST_USE_WINDOWS_H )
|
||||
# include <windows.h>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
namespace win32
|
||||
{
|
||||
typedef ULONG_PTR ulong_ptr;
|
||||
typedef HANDLE handle;
|
||||
unsigned const infinite=INFINITE;
|
||||
unsigned const timeout=WAIT_TIMEOUT;
|
||||
handle const invalid_handle_value=INVALID_HANDLE_VALUE;
|
||||
|
||||
# ifdef BOOST_NO_ANSI_APIS
|
||||
using ::CreateMutexW;
|
||||
using ::CreateEventW;
|
||||
using ::CreateSemaphoreW;
|
||||
# else
|
||||
using ::CreateMutexA;
|
||||
using ::CreateEventA;
|
||||
using ::CreateSemaphoreA;
|
||||
# endif
|
||||
using ::CloseHandle;
|
||||
using ::ReleaseMutex;
|
||||
using ::ReleaseSemaphore;
|
||||
using ::SetEvent;
|
||||
using ::ResetEvent;
|
||||
using ::WaitForMultipleObjects;
|
||||
using ::WaitForSingleObject;
|
||||
using ::GetCurrentProcessId;
|
||||
using ::GetCurrentThreadId;
|
||||
using ::GetCurrentThread;
|
||||
using ::GetCurrentProcess;
|
||||
using ::DuplicateHandle;
|
||||
using ::SleepEx;
|
||||
using ::Sleep;
|
||||
using ::QueueUserAPC;
|
||||
using ::GetTickCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
#elif defined( WIN32 ) || defined( _WIN32 ) || defined( __WIN32__ )
|
||||
|
||||
# ifdef UNDER_CE
|
||||
# ifndef WINAPI
|
||||
# ifndef _WIN32_WCE_EMULATION
|
||||
# define WINAPI __cdecl // Note this doesn't match the desktop definition
|
||||
# else
|
||||
# define WINAPI __stdcall
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# ifdef __cplusplus
|
||||
extern "C" {
|
||||
# endif
|
||||
typedef int BOOL;
|
||||
typedef unsigned long DWORD;
|
||||
typedef void* HANDLE;
|
||||
|
||||
# include <kfuncs.h>
|
||||
# ifdef __cplusplus
|
||||
}
|
||||
# endif
|
||||
# endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
namespace win32
|
||||
{
|
||||
|
||||
# ifdef _WIN64
|
||||
typedef unsigned __int64 ulong_ptr;
|
||||
# else
|
||||
typedef unsigned long ulong_ptr;
|
||||
# endif
|
||||
typedef void* handle;
|
||||
unsigned const infinite=~0U;
|
||||
unsigned const timeout=258U;
|
||||
handle const invalid_handle_value=(handle)(-1);
|
||||
|
||||
extern "C"
|
||||
{
|
||||
struct _SECURITY_ATTRIBUTES;
|
||||
# ifdef BOOST_NO_ANSI_APIS
|
||||
__declspec(dllimport) void* __stdcall CreateMutexW(_SECURITY_ATTRIBUTES*,int,wchar_t const*);
|
||||
__declspec(dllimport) void* __stdcall CreateSemaphoreW(_SECURITY_ATTRIBUTES*,long,long,wchar_t const*);
|
||||
__declspec(dllimport) void* __stdcall CreateEventW(_SECURITY_ATTRIBUTES*,int,int,wchar_t const*);
|
||||
# else
|
||||
__declspec(dllimport) void* __stdcall CreateMutexA(_SECURITY_ATTRIBUTES*,int,char const*);
|
||||
__declspec(dllimport) void* __stdcall CreateSemaphoreA(_SECURITY_ATTRIBUTES*,long,long,char const*);
|
||||
__declspec(dllimport) void* __stdcall CreateEventA(_SECURITY_ATTRIBUTES*,int,int,char const*);
|
||||
# endif
|
||||
__declspec(dllimport) int __stdcall CloseHandle(void*);
|
||||
__declspec(dllimport) int __stdcall ReleaseMutex(void*);
|
||||
__declspec(dllimport) unsigned long __stdcall WaitForSingleObject(void*,unsigned long);
|
||||
__declspec(dllimport) unsigned long __stdcall WaitForMultipleObjects(unsigned long nCount,void* const * lpHandles,int bWaitAll,unsigned long dwMilliseconds);
|
||||
__declspec(dllimport) int __stdcall ReleaseSemaphore(void*,long,long*);
|
||||
__declspec(dllimport) int __stdcall DuplicateHandle(void*,void*,void*,void**,unsigned long,int,unsigned long);
|
||||
__declspec(dllimport) unsigned long __stdcall SleepEx(unsigned long,int);
|
||||
__declspec(dllimport) void __stdcall Sleep(unsigned long);
|
||||
typedef void (__stdcall *queue_user_apc_callback_function)(ulong_ptr);
|
||||
__declspec(dllimport) unsigned long __stdcall QueueUserAPC(queue_user_apc_callback_function,void*,ulong_ptr);
|
||||
|
||||
__declspec(dllimport) unsigned long __stdcall GetTickCount();
|
||||
|
||||
# ifndef UNDER_CE
|
||||
__declspec(dllimport) unsigned long __stdcall GetCurrentProcessId();
|
||||
__declspec(dllimport) unsigned long __stdcall GetCurrentThreadId();
|
||||
__declspec(dllimport) void* __stdcall GetCurrentThread();
|
||||
__declspec(dllimport) void* __stdcall GetCurrentProcess();
|
||||
__declspec(dllimport) int __stdcall SetEvent(void*);
|
||||
__declspec(dllimport) int __stdcall ResetEvent(void*);
|
||||
# else
|
||||
using ::GetCurrentProcessId;
|
||||
using ::GetCurrentThreadId;
|
||||
using ::GetCurrentThread;
|
||||
using ::GetCurrentProcess;
|
||||
using ::SetEvent;
|
||||
using ::ResetEvent;
|
||||
# endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
# error "Win32 functions not available"
|
||||
#endif
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
namespace win32
|
||||
{
|
||||
enum event_type
|
||||
{
|
||||
auto_reset_event=false,
|
||||
manual_reset_event=true
|
||||
};
|
||||
|
||||
enum initial_event_state
|
||||
{
|
||||
event_initially_reset=false,
|
||||
event_initially_set=true
|
||||
};
|
||||
|
||||
inline handle create_anonymous_event(event_type type,initial_event_state state)
|
||||
{
|
||||
#if !defined(BOOST_NO_ANSI_APIS)
|
||||
handle const res=win32::CreateEventA(0,type,state,0);
|
||||
#else
|
||||
handle const res=win32::CreateEventW(0,type,state,0);
|
||||
#endif
|
||||
if(!res)
|
||||
{
|
||||
throw thread_resource_error();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
inline handle create_anonymous_semaphore(long initial_count,long max_count)
|
||||
{
|
||||
#if !defined(BOOST_NO_ANSI_APIS)
|
||||
handle const res=CreateSemaphoreA(0,initial_count,max_count,0);
|
||||
#else
|
||||
handle const res=CreateSemaphoreW(0,initial_count,max_count,0);
|
||||
#endif
|
||||
if(!res)
|
||||
{
|
||||
throw thread_resource_error();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
inline handle duplicate_handle(handle source)
|
||||
{
|
||||
handle const current_process=GetCurrentProcess();
|
||||
long const same_access_flag=2;
|
||||
handle new_handle=0;
|
||||
bool const success=DuplicateHandle(current_process,source,current_process,&new_handle,0,false,same_access_flag)!=0;
|
||||
if(!success)
|
||||
{
|
||||
throw thread_resource_error();
|
||||
}
|
||||
return new_handle;
|
||||
}
|
||||
|
||||
inline void release_semaphore(handle semaphore,long count)
|
||||
{
|
||||
BOOST_VERIFY(ReleaseSemaphore(semaphore,count,0)!=0);
|
||||
}
|
||||
|
||||
class handle_manager
|
||||
{
|
||||
private:
|
||||
handle handle_to_manage;
|
||||
handle_manager(handle_manager&);
|
||||
handle_manager& operator=(handle_manager&);
|
||||
|
||||
void cleanup()
|
||||
{
|
||||
if(handle_to_manage && handle_to_manage!=invalid_handle_value)
|
||||
{
|
||||
BOOST_VERIFY(CloseHandle(handle_to_manage));
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
explicit handle_manager(handle handle_to_manage_):
|
||||
handle_to_manage(handle_to_manage_)
|
||||
{}
|
||||
handle_manager():
|
||||
handle_to_manage(0)
|
||||
{}
|
||||
|
||||
handle_manager& operator=(handle new_handle)
|
||||
{
|
||||
cleanup();
|
||||
handle_to_manage=new_handle;
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator handle() const
|
||||
{
|
||||
return handle_to_manage;
|
||||
}
|
||||
|
||||
handle duplicate() const
|
||||
{
|
||||
return duplicate_handle(handle_to_manage);
|
||||
}
|
||||
|
||||
void swap(handle_manager& other)
|
||||
{
|
||||
std::swap(handle_to_manage,other.handle_to_manage);
|
||||
}
|
||||
|
||||
handle release()
|
||||
{
|
||||
handle const res=handle_to_manage;
|
||||
handle_to_manage=0;
|
||||
return res;
|
||||
}
|
||||
|
||||
bool operator!() const
|
||||
{
|
||||
return !handle_to_manage;
|
||||
}
|
||||
|
||||
~handle_manager()
|
||||
{
|
||||
cleanup();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(BOOST_MSVC) && (_MSC_VER>=1400) && !defined(UNDER_CE)
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
namespace win32
|
||||
{
|
||||
#if _MSC_VER==1400
|
||||
extern "C" unsigned char _interlockedbittestandset(long *a,long b);
|
||||
extern "C" unsigned char _interlockedbittestandreset(long *a,long b);
|
||||
#else
|
||||
extern "C" unsigned char _interlockedbittestandset(volatile long *a,long b);
|
||||
extern "C" unsigned char _interlockedbittestandreset(volatile long *a,long b);
|
||||
#endif
|
||||
|
||||
#pragma intrinsic(_interlockedbittestandset)
|
||||
#pragma intrinsic(_interlockedbittestandreset)
|
||||
|
||||
inline bool interlocked_bit_test_and_set(long* x,long bit)
|
||||
{
|
||||
return _interlockedbittestandset(x,bit)!=0;
|
||||
}
|
||||
|
||||
inline bool interlocked_bit_test_and_reset(long* x,long bit)
|
||||
{
|
||||
return _interlockedbittestandreset(x,bit)!=0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
#define BOOST_THREAD_BTS_DEFINED
|
||||
#elif (defined(BOOST_MSVC) || defined(BOOST_INTEL_WIN)) && defined(_M_IX86)
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
namespace win32
|
||||
{
|
||||
inline bool interlocked_bit_test_and_set(long* x,long bit)
|
||||
{
|
||||
__asm {
|
||||
mov eax,bit;
|
||||
mov edx,x;
|
||||
lock bts [edx],eax;
|
||||
setc al;
|
||||
};
|
||||
}
|
||||
|
||||
inline bool interlocked_bit_test_and_reset(long* x,long bit)
|
||||
{
|
||||
__asm {
|
||||
mov eax,bit;
|
||||
mov edx,x;
|
||||
lock btr [edx],eax;
|
||||
setc al;
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
#define BOOST_THREAD_BTS_DEFINED
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_THREAD_BTS_DEFINED
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
namespace win32
|
||||
{
|
||||
inline bool interlocked_bit_test_and_set(long* x,long bit)
|
||||
{
|
||||
long const value=1<<bit;
|
||||
long old=*x;
|
||||
do
|
||||
{
|
||||
long const current=BOOST_INTERLOCKED_COMPARE_EXCHANGE(x,old|value,old);
|
||||
if(current==old)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old=current;
|
||||
}
|
||||
while(true);
|
||||
return (old&value)!=0;
|
||||
}
|
||||
|
||||
inline bool interlocked_bit_test_and_reset(long* x,long bit)
|
||||
{
|
||||
long const value=1<<bit;
|
||||
long old=*x;
|
||||
do
|
||||
{
|
||||
long const current=BOOST_INTERLOCKED_COMPARE_EXCHANGE(x,old&~value,old);
|
||||
if(current==old)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old=current;
|
||||
}
|
||||
while(true);
|
||||
return (old&value)!=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
@@ -1,5 +1,6 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
// Copyright (C) 2007-8 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -10,6 +11,10 @@
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#include <boost/date_time/posix_time/conversion.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost {
|
||||
|
||||
@@ -37,9 +42,40 @@ struct xtime
|
||||
|
||||
xtime_sec_t sec;
|
||||
xtime_nsec_t nsec;
|
||||
|
||||
operator system_time() const
|
||||
{
|
||||
return boost::posix_time::from_time_t(0)+
|
||||
boost::posix_time::seconds(static_cast<long>(sec))+
|
||||
#ifdef BOOST_DATE_TIME_HAS_NANOSECONDS
|
||||
boost::posix_time::nanoseconds(nsec);
|
||||
#else
|
||||
boost::posix_time::microseconds((nsec+500)/1000);
|
||||
#endif
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
int BOOST_THREAD_DECL xtime_get(struct xtime* xtp, int clock_type);
|
||||
inline xtime get_xtime(boost::system_time const& abs_time)
|
||||
{
|
||||
xtime res;
|
||||
boost::posix_time::time_duration const time_since_epoch=abs_time-boost::posix_time::from_time_t(0);
|
||||
|
||||
res.sec=static_cast<xtime::xtime_sec_t>(time_since_epoch.total_seconds());
|
||||
res.nsec=static_cast<xtime::xtime_nsec_t>(time_since_epoch.fractional_seconds()*(1000000000/time_since_epoch.ticks_per_second()));
|
||||
return res;
|
||||
}
|
||||
|
||||
inline int xtime_get(struct xtime* xtp, int clock_type)
|
||||
{
|
||||
if (clock_type == TIME_UTC)
|
||||
{
|
||||
*xtp=get_xtime(get_system_time());
|
||||
return clock_type;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
inline int xtime_cmp(const xtime& xt1, const xtime& xt2)
|
||||
{
|
||||
@@ -51,4 +87,6 @@ inline int xtime_cmp(const xtime& xt1, const xtime& xt2)
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif //BOOST_XTIME_WEK070601_HPP
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<!-- Copyright (c) 2002-2003 William E. Kempf.
|
||||
Subject to the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
|
||||
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
-->
|
||||
|
||||
<html>
|
||||
|
||||
@@ -342,6 +342,9 @@ condition_impl::condition_impl()
|
||||
res = pthread_cond_init(&m_condition, 0);
|
||||
if (res != 0)
|
||||
throw thread_resource_error();
|
||||
res = pthread_mutex_init(&m_mutex, 0);
|
||||
if (res != 0)
|
||||
throw thread_resource_error();
|
||||
}
|
||||
|
||||
condition_impl::~condition_impl()
|
||||
@@ -349,20 +352,30 @@ condition_impl::~condition_impl()
|
||||
int res = 0;
|
||||
res = pthread_cond_destroy(&m_condition);
|
||||
assert(res == 0);
|
||||
res = pthread_mutex_destroy(&m_mutex);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
void condition_impl::notify_one()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_lock(&m_mutex);
|
||||
assert(res == 0);
|
||||
res = pthread_cond_signal(&m_condition);
|
||||
assert(res == 0);
|
||||
res = pthread_mutex_unlock(&m_mutex);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
void condition_impl::notify_all()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_lock(&m_mutex);
|
||||
assert(res == 0);
|
||||
res = pthread_cond_broadcast(&m_condition);
|
||||
assert(res == 0);
|
||||
res = pthread_mutex_unlock(&m_mutex);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
void condition_impl::do_wait(pthread_mutex_t* pmutex)
|
||||
|
||||
561
src/mutex.cpp
561
src/mutex.cpp
@@ -1,561 +0,0 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/limits.hpp>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <cassert>
|
||||
#include "timeconv.inl"
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
# include <new>
|
||||
# include <boost/thread/once.hpp>
|
||||
# include <windows.h>
|
||||
# include <time.h>
|
||||
# include "mutex.inl"
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
# include <errno.h>
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
# include <MacErrors.h>
|
||||
# include "mac/init.hpp"
|
||||
# include "mac/safe.hpp"
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
|
||||
mutex::mutex()
|
||||
: m_mutex(0)
|
||||
, m_critical_section(false)
|
||||
{
|
||||
m_critical_section = true;
|
||||
if (m_critical_section)
|
||||
m_mutex = new_critical_section();
|
||||
else
|
||||
m_mutex = new_mutex(0);
|
||||
}
|
||||
|
||||
mutex::~mutex()
|
||||
{
|
||||
if (m_critical_section)
|
||||
delete_critical_section(m_mutex);
|
||||
else
|
||||
delete_mutex(m_mutex);
|
||||
}
|
||||
|
||||
void mutex::do_lock()
|
||||
{
|
||||
if (m_critical_section)
|
||||
wait_critical_section_infinite(m_mutex);
|
||||
else
|
||||
wait_mutex(m_mutex, INFINITE);
|
||||
}
|
||||
|
||||
void mutex::do_unlock()
|
||||
{
|
||||
if (m_critical_section)
|
||||
release_critical_section(m_mutex);
|
||||
else
|
||||
release_mutex(m_mutex);
|
||||
}
|
||||
|
||||
void mutex::do_lock(cv_state&)
|
||||
{
|
||||
do_lock();
|
||||
}
|
||||
|
||||
void mutex::do_unlock(cv_state&)
|
||||
{
|
||||
do_unlock();
|
||||
}
|
||||
|
||||
try_mutex::try_mutex()
|
||||
: m_mutex(0)
|
||||
, m_critical_section(false)
|
||||
{
|
||||
m_critical_section = has_TryEnterCriticalSection();
|
||||
if (m_critical_section)
|
||||
m_mutex = new_critical_section();
|
||||
else
|
||||
m_mutex = new_mutex(0);
|
||||
}
|
||||
|
||||
try_mutex::~try_mutex()
|
||||
{
|
||||
if (m_critical_section)
|
||||
delete_critical_section(m_mutex);
|
||||
else
|
||||
delete_mutex(m_mutex);
|
||||
}
|
||||
|
||||
void try_mutex::do_lock()
|
||||
{
|
||||
if (m_critical_section)
|
||||
wait_critical_section_infinite(m_mutex);
|
||||
else
|
||||
wait_mutex(m_mutex, INFINITE);
|
||||
}
|
||||
|
||||
bool try_mutex::do_trylock()
|
||||
{
|
||||
if (m_critical_section)
|
||||
return wait_critical_section_try(m_mutex);
|
||||
else
|
||||
return wait_mutex(m_mutex, 0) == WAIT_OBJECT_0;
|
||||
}
|
||||
|
||||
void try_mutex::do_unlock()
|
||||
{
|
||||
if (m_critical_section)
|
||||
release_critical_section(m_mutex);
|
||||
else
|
||||
release_mutex(m_mutex);
|
||||
}
|
||||
|
||||
void try_mutex::do_lock(cv_state&)
|
||||
{
|
||||
do_lock();
|
||||
}
|
||||
|
||||
void try_mutex::do_unlock(cv_state&)
|
||||
{
|
||||
do_unlock();
|
||||
}
|
||||
|
||||
timed_mutex::timed_mutex()
|
||||
: m_mutex(0)
|
||||
{
|
||||
m_mutex = new_mutex(0);
|
||||
}
|
||||
|
||||
timed_mutex::~timed_mutex()
|
||||
{
|
||||
delete_mutex(m_mutex);
|
||||
}
|
||||
|
||||
void timed_mutex::do_lock()
|
||||
{
|
||||
wait_mutex(m_mutex, INFINITE);
|
||||
}
|
||||
|
||||
bool timed_mutex::do_trylock()
|
||||
{
|
||||
return wait_mutex(m_mutex, 0) == WAIT_OBJECT_0;
|
||||
}
|
||||
|
||||
bool timed_mutex::do_timedlock(const xtime& xt)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
int milliseconds;
|
||||
to_duration(xt, milliseconds);
|
||||
|
||||
int res = wait_mutex(m_mutex, milliseconds);
|
||||
|
||||
if (res == WAIT_TIMEOUT)
|
||||
{
|
||||
boost::xtime cur;
|
||||
boost::xtime_get(&cur, boost::TIME_UTC);
|
||||
if (boost::xtime_cmp(xt, cur) > 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
return res == WAIT_OBJECT_0;
|
||||
}
|
||||
}
|
||||
|
||||
void timed_mutex::do_unlock()
|
||||
{
|
||||
release_mutex(m_mutex);
|
||||
}
|
||||
|
||||
void timed_mutex::do_lock(cv_state&)
|
||||
{
|
||||
do_lock();
|
||||
}
|
||||
|
||||
void timed_mutex::do_unlock(cv_state&)
|
||||
{
|
||||
do_unlock();
|
||||
}
|
||||
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
|
||||
mutex::mutex()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_init(&m_mutex, 0);
|
||||
if (res != 0)
|
||||
throw thread_resource_error();
|
||||
}
|
||||
|
||||
mutex::~mutex()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_destroy(&m_mutex);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
void mutex::do_lock()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_lock(&m_mutex);
|
||||
if (res == EDEADLK) throw lock_error();
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
void mutex::do_unlock()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_unlock(&m_mutex);
|
||||
if (res == EPERM) throw lock_error();
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
void mutex::do_lock(cv_state&)
|
||||
{
|
||||
}
|
||||
|
||||
void mutex::do_unlock(cv_state& state)
|
||||
{
|
||||
state.pmutex = &m_mutex;
|
||||
}
|
||||
|
||||
try_mutex::try_mutex()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_init(&m_mutex, 0);
|
||||
if (res != 0)
|
||||
throw thread_resource_error();
|
||||
}
|
||||
|
||||
try_mutex::~try_mutex()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_destroy(&m_mutex);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
void try_mutex::do_lock()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_lock(&m_mutex);
|
||||
if (res == EDEADLK) throw lock_error();
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
bool try_mutex::do_trylock()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_trylock(&m_mutex);
|
||||
if (res == EDEADLK) throw lock_error();
|
||||
assert(res == 0 || res == EBUSY);
|
||||
return res == 0;
|
||||
}
|
||||
|
||||
void try_mutex::do_unlock()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_unlock(&m_mutex);
|
||||
if (res == EPERM) throw lock_error();
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
void try_mutex::do_lock(cv_state&)
|
||||
{
|
||||
}
|
||||
|
||||
void try_mutex::do_unlock(cv_state& state)
|
||||
{
|
||||
state.pmutex = &m_mutex;
|
||||
}
|
||||
|
||||
timed_mutex::timed_mutex()
|
||||
: m_locked(false)
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_init(&m_mutex, 0);
|
||||
if (res != 0)
|
||||
throw thread_resource_error();
|
||||
|
||||
res = pthread_cond_init(&m_condition, 0);
|
||||
if (res != 0)
|
||||
{
|
||||
pthread_mutex_destroy(&m_mutex);
|
||||
throw thread_resource_error();
|
||||
}
|
||||
}
|
||||
|
||||
timed_mutex::~timed_mutex()
|
||||
{
|
||||
assert(!m_locked);
|
||||
int res = 0;
|
||||
res = pthread_mutex_destroy(&m_mutex);
|
||||
assert(res == 0);
|
||||
|
||||
res = pthread_cond_destroy(&m_condition);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
void timed_mutex::do_lock()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_lock(&m_mutex);
|
||||
assert(res == 0);
|
||||
|
||||
while (m_locked)
|
||||
{
|
||||
res = pthread_cond_wait(&m_condition, &m_mutex);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
assert(!m_locked);
|
||||
m_locked = true;
|
||||
|
||||
res = pthread_mutex_unlock(&m_mutex);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
bool timed_mutex::do_trylock()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_lock(&m_mutex);
|
||||
assert(res == 0);
|
||||
|
||||
bool ret = false;
|
||||
if (!m_locked)
|
||||
{
|
||||
m_locked = true;
|
||||
ret = true;
|
||||
}
|
||||
|
||||
res = pthread_mutex_unlock(&m_mutex);
|
||||
assert(res == 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool timed_mutex::do_timedlock(const xtime& xt)
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_lock(&m_mutex);
|
||||
assert(res == 0);
|
||||
|
||||
timespec ts;
|
||||
to_timespec(xt, ts);
|
||||
|
||||
while (m_locked)
|
||||
{
|
||||
res = pthread_cond_timedwait(&m_condition, &m_mutex, &ts);
|
||||
assert(res == 0 || res == ETIMEDOUT);
|
||||
|
||||
if (res == ETIMEDOUT)
|
||||
break;
|
||||
}
|
||||
|
||||
bool ret = false;
|
||||
if (!m_locked)
|
||||
{
|
||||
m_locked = true;
|
||||
ret = true;
|
||||
}
|
||||
|
||||
res = pthread_mutex_unlock(&m_mutex);
|
||||
assert(res == 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void timed_mutex::do_unlock()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_lock(&m_mutex);
|
||||
assert(res == 0);
|
||||
|
||||
assert(m_locked);
|
||||
m_locked = false;
|
||||
|
||||
res = pthread_cond_signal(&m_condition);
|
||||
assert(res == 0);
|
||||
|
||||
res = pthread_mutex_unlock(&m_mutex);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
void timed_mutex::do_lock(cv_state&)
|
||||
{
|
||||
int res = 0;
|
||||
while (m_locked)
|
||||
{
|
||||
res = pthread_cond_wait(&m_condition, &m_mutex);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
assert(!m_locked);
|
||||
m_locked = true;
|
||||
|
||||
res = pthread_mutex_unlock(&m_mutex);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
void timed_mutex::do_unlock(cv_state& state)
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_lock(&m_mutex);
|
||||
assert(res == 0);
|
||||
|
||||
assert(m_locked);
|
||||
m_locked = false;
|
||||
|
||||
res = pthread_cond_signal(&m_condition);
|
||||
assert(res == 0);
|
||||
|
||||
state.pmutex = &m_mutex;
|
||||
}
|
||||
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
|
||||
using threads::mac::detail::safe_enter_critical_region;
|
||||
|
||||
mutex::mutex()
|
||||
{
|
||||
}
|
||||
|
||||
mutex::~mutex()
|
||||
{
|
||||
}
|
||||
|
||||
void mutex::do_lock()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||
m_mutex_mutex);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
void mutex::do_unlock()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = MPExitCriticalRegion(m_mutex);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
void mutex::do_lock(cv_state& /*state*/)
|
||||
{
|
||||
do_lock();
|
||||
}
|
||||
|
||||
void mutex::do_unlock(cv_state& /*state*/)
|
||||
{
|
||||
do_unlock();
|
||||
}
|
||||
|
||||
try_mutex::try_mutex()
|
||||
{
|
||||
}
|
||||
|
||||
try_mutex::~try_mutex()
|
||||
{
|
||||
}
|
||||
|
||||
void try_mutex::do_lock()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||
m_mutex_mutex);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
bool try_mutex::do_trylock()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = MPEnterCriticalRegion(m_mutex, kDurationImmediate);
|
||||
assert(lStatus == noErr || lStatus == kMPTimeoutErr);
|
||||
return lStatus == noErr;
|
||||
}
|
||||
|
||||
void try_mutex::do_unlock()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = MPExitCriticalRegion(m_mutex);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
void try_mutex::do_lock(cv_state& /*state*/)
|
||||
{
|
||||
do_lock();
|
||||
}
|
||||
|
||||
void try_mutex::do_unlock(cv_state& /*state*/)
|
||||
{
|
||||
do_unlock();
|
||||
}
|
||||
|
||||
timed_mutex::timed_mutex()
|
||||
{
|
||||
}
|
||||
|
||||
timed_mutex::~timed_mutex()
|
||||
{
|
||||
}
|
||||
|
||||
void timed_mutex::do_lock()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||
m_mutex_mutex);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
bool timed_mutex::do_trylock()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = MPEnterCriticalRegion(m_mutex, kDurationImmediate);
|
||||
assert(lStatus == noErr || lStatus == kMPTimeoutErr);
|
||||
return(lStatus == noErr);
|
||||
}
|
||||
|
||||
bool timed_mutex::do_timedlock(const xtime& xt)
|
||||
{
|
||||
int microseconds;
|
||||
to_microduration(xt, microseconds);
|
||||
Duration lDuration = kDurationMicrosecond * microseconds;
|
||||
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = safe_enter_critical_region(m_mutex, lDuration, m_mutex_mutex);
|
||||
assert(lStatus == noErr || lStatus == kMPTimeoutErr);
|
||||
|
||||
return(lStatus == noErr);
|
||||
}
|
||||
|
||||
void timed_mutex::do_unlock()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = MPExitCriticalRegion(m_mutex);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
void timed_mutex::do_lock(cv_state& /*state*/)
|
||||
{
|
||||
do_lock();
|
||||
}
|
||||
|
||||
void timed_mutex::do_unlock(cv_state& /*state*/)
|
||||
{
|
||||
do_unlock();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace boost
|
||||
|
||||
// Change Log:
|
||||
// 8 Feb 01 WEKEMPF Initial version.
|
||||
120
src/mutex.inl
120
src/mutex.inl
@@ -1,120 +0,0 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
// boostinspect:nounnamed
|
||||
|
||||
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, TEXT("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
|
||||
|
||||
}
|
||||
213
src/once.cpp
213
src/once.cpp
@@ -1,213 +0,0 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/detail/workaround.hpp>
|
||||
|
||||
#include <boost/thread/once.hpp>
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
# if BOOST_WORKAROUND(__BORLANDC__,<= 0x551)
|
||||
using std::size_t;
|
||||
# endif
|
||||
# include <windows.h>
|
||||
# if defined(BOOST_NO_STRINGSTREAM)
|
||||
# include <strstream>
|
||||
|
||||
class unfreezer
|
||||
{
|
||||
public:
|
||||
unfreezer(std::ostrstream& s) : m_stream(s) {}
|
||||
~unfreezer() { m_stream.freeze(false); }
|
||||
private:
|
||||
std::ostrstream& m_stream;
|
||||
};
|
||||
|
||||
# else
|
||||
# include <sstream>
|
||||
# endif
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
# include <Multiprocessing.h>
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_NO_STDC_NAMESPACE
|
||||
namespace std { using ::sprintf; }
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
namespace {
|
||||
pthread_key_t key;
|
||||
pthread_once_t once = PTHREAD_ONCE_INIT;
|
||||
|
||||
typedef void (*once_callback)();
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
static void key_init()
|
||||
{
|
||||
pthread_key_create(&key, 0);
|
||||
}
|
||||
|
||||
static void do_once()
|
||||
{
|
||||
once_callback* cb = reinterpret_cast<once_callback*>(
|
||||
pthread_getspecific(key));
|
||||
(**cb)();
|
||||
}
|
||||
|
||||
}
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
namespace {
|
||||
void *remote_call_proxy(void *pData)
|
||||
{
|
||||
std::pair<void (*)(), boost::once_flag *> &rData(
|
||||
*reinterpret_cast<std::pair<void (*)(), boost::once_flag *> *>(pData));
|
||||
|
||||
if(*rData.second == false)
|
||||
{
|
||||
rData.first();
|
||||
*rData.second = true;
|
||||
}
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(BOOST_HAS_WINTHREADS)
|
||||
namespace {
|
||||
// The signature for InterlockedCompareExchange has changed with the
|
||||
// addition of Win64 support. I can't determine any (consistent and
|
||||
// portable) way of using conditional compilation to detect this, so
|
||||
// we use these type wrappers. Unfortunately, the various vendors
|
||||
// use different calling conventions and other signature anamolies,
|
||||
// and thus have unique types as well. This is known to work on VC6,
|
||||
// VC7, Borland 5.5.2 and gcc 3.2. Are there other signatures for
|
||||
// other platforms?
|
||||
inline LONG ice_wrapper(LONG (__stdcall *ice)(LONG*, LONG, LONG),
|
||||
volatile LONG* dest, LONG exch, LONG cmp)
|
||||
{
|
||||
return (*ice)(const_cast<LONG*>(dest), exch, cmp);
|
||||
}
|
||||
|
||||
inline LONG ice_wrapper(LONG (__stdcall *ice)(volatile LONG*, LONG, LONG),
|
||||
volatile LONG* dest, LONG exch, LONG cmp)
|
||||
{
|
||||
return (*ice)(dest, exch, cmp);
|
||||
}
|
||||
|
||||
inline LONG ice_wrapper(LPVOID (__stdcall *ice)(LPVOID*, LPVOID, LPVOID),
|
||||
volatile LONG* dest, LONG exch, LONG cmp)
|
||||
{
|
||||
return (LONG)(*ice)((LPVOID*)dest, (LPVOID)exch, (LPVOID)cmp);
|
||||
}
|
||||
|
||||
// The friendly form of InterlockedCompareExchange that defers
|
||||
// according to the above function type wrappers.
|
||||
inline LONG compare_exchange(volatile LPLONG dest, LONG exch, LONG cmp)
|
||||
{
|
||||
#ifdef _WIN64
|
||||
// Original patch from Anthony Williams.
|
||||
// I (Roland Schwarz) am trying this for RC_1_34_0, since x64 regressions are
|
||||
// currently not run on x64 platforms for HEAD
|
||||
return InterlockedCompareExchange(dest, exch,cmp);
|
||||
#else
|
||||
return ice_wrapper(&InterlockedCompareExchange, dest, exch, cmp);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
void call_once(void (*func)(), once_flag& flag)
|
||||
{
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
if (compare_exchange(&flag, 1, 1) == 0)
|
||||
{
|
||||
#if defined(BOOST_NO_STRINGSTREAM)
|
||||
std::ostrstream strm;
|
||||
strm << "2AC1A572DB6944B0A65C38C4140AF2F4"
|
||||
<< std::hex
|
||||
<< GetCurrentProcessId()
|
||||
<< &flag
|
||||
<< std::ends;
|
||||
unfreezer unfreeze(strm);
|
||||
# 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
|
||||
# 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;
|
||||
strm << "2AC1A572DB6944B0A65C38C4140AF2F4"
|
||||
<< std::hex
|
||||
<< GetCurrentProcessId()
|
||||
<< &flag;
|
||||
HANDLE mutex = CreateMutexA(NULL, FALSE, strm.str().c_str());
|
||||
# endif
|
||||
#endif
|
||||
assert(mutex != NULL);
|
||||
|
||||
int res = 0;
|
||||
res = WaitForSingleObject(mutex, INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
|
||||
if (compare_exchange(&flag, 1, 1) == 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
func();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
res = ReleaseMutex(mutex);
|
||||
assert(res);
|
||||
res = CloseHandle(mutex);
|
||||
assert(res);
|
||||
throw;
|
||||
}
|
||||
InterlockedExchange(&flag, 1);
|
||||
}
|
||||
|
||||
res = ReleaseMutex(mutex);
|
||||
assert(res);
|
||||
res = CloseHandle(mutex);
|
||||
assert(res);
|
||||
}
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
pthread_once(&once, &key_init);
|
||||
pthread_setspecific(key, &func);
|
||||
pthread_once(&flag, do_once);
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
if(flag == false)
|
||||
{
|
||||
// all we do here is make a remote call to blue, as blue is not
|
||||
// reentrant.
|
||||
std::pair<void (*)(), once_flag *> sData(func, &flag);
|
||||
MPRemoteCall(remote_call_proxy, &sData, kMPOwningProcessRemoteContext);
|
||||
assert(flag == true);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Change Log:
|
||||
// 1 Aug 01 WEKEMPF Initial version.
|
||||
124
src/pthread/exceptions.cpp
Normal file
124
src/pthread/exceptions.cpp
Normal file
@@ -0,0 +1,124 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
namespace boost {
|
||||
|
||||
thread_exception::thread_exception()
|
||||
: m_sys_err(0)
|
||||
{
|
||||
}
|
||||
|
||||
thread_exception::thread_exception(int sys_err_code)
|
||||
: m_sys_err(sys_err_code)
|
||||
{
|
||||
}
|
||||
|
||||
thread_exception::~thread_exception() throw()
|
||||
{
|
||||
}
|
||||
|
||||
int thread_exception::native_error() const
|
||||
{
|
||||
return m_sys_err;
|
||||
}
|
||||
|
||||
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
|
||||
51
src/pthread/once.cpp
Normal file
51
src/pthread/once.cpp
Normal file
@@ -0,0 +1,51 @@
|
||||
// Copyright (C) 2007 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#define __STDC_CONSTANT_MACROS
|
||||
#include <boost/thread/once.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
BOOST_THREAD_DECL boost::uintmax_t once_global_epoch=UINTMAX_C(~0);
|
||||
BOOST_THREAD_DECL pthread_mutex_t once_epoch_mutex=PTHREAD_MUTEX_INITIALIZER;
|
||||
BOOST_THREAD_DECL pthread_cond_t once_epoch_cv = PTHREAD_COND_INITIALIZER;
|
||||
|
||||
namespace
|
||||
{
|
||||
pthread_key_t epoch_tss_key;
|
||||
pthread_once_t epoch_tss_key_flag=PTHREAD_ONCE_INIT;
|
||||
|
||||
extern "C" void delete_epoch_tss_data(void* data)
|
||||
{
|
||||
free(data);
|
||||
}
|
||||
|
||||
extern "C" void create_epoch_tss_key()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_key_create(&epoch_tss_key,delete_epoch_tss_data));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
boost::uintmax_t& get_once_per_thread_epoch()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_once(&epoch_tss_key_flag,create_epoch_tss_key));
|
||||
void* data=pthread_getspecific(epoch_tss_key);
|
||||
if(!data)
|
||||
{
|
||||
data=malloc(sizeof(boost::uintmax_t));
|
||||
BOOST_VERIFY(!pthread_setspecific(epoch_tss_key,data));
|
||||
*static_cast<boost::uintmax_t*>(data)=UINTMAX_C(~0);
|
||||
}
|
||||
return *static_cast<boost::uintmax_t*>(data);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
676
src/pthread/thread.cpp
Normal file
676
src/pthread/thread.cpp
Normal file
@@ -0,0 +1,676 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
// Copyright (C) 2007-8 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <boost/thread/condition.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
#include <boost/thread/once.hpp>
|
||||
#include <boost/thread/tss.hpp>
|
||||
#ifdef __linux__
|
||||
#include <sys/sysinfo.h>
|
||||
#elif defined(__APPLE__) || defined(__FreeBSD__)
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
#elif defined BOOST_HAS_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "timeconv.inl"
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
thread_data_base::~thread_data_base()
|
||||
{}
|
||||
|
||||
struct thread_exit_callback_node
|
||||
{
|
||||
boost::detail::thread_exit_function_base* func;
|
||||
thread_exit_callback_node* next;
|
||||
|
||||
thread_exit_callback_node(boost::detail::thread_exit_function_base* func_,
|
||||
thread_exit_callback_node* next_):
|
||||
func(func_),next(next_)
|
||||
{}
|
||||
};
|
||||
|
||||
struct tss_data_node
|
||||
{
|
||||
void const* key;
|
||||
boost::shared_ptr<boost::detail::tss_cleanup_function> func;
|
||||
void* value;
|
||||
tss_data_node* next;
|
||||
|
||||
tss_data_node(void const* key_,boost::shared_ptr<boost::detail::tss_cleanup_function> func_,void* value_,
|
||||
tss_data_node* next_):
|
||||
key(key_),func(func_),value(value_),next(next_)
|
||||
{}
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
boost::once_flag current_thread_tls_init_flag=BOOST_ONCE_INIT;
|
||||
pthread_key_t current_thread_tls_key;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
void tls_destructor(void* data)
|
||||
{
|
||||
boost::detail::thread_data_base* thread_info=static_cast<boost::detail::thread_data_base*>(data);
|
||||
if(thread_info)
|
||||
{
|
||||
while(thread_info->tss_data || thread_info->thread_exit_callbacks)
|
||||
{
|
||||
while(thread_info->thread_exit_callbacks)
|
||||
{
|
||||
detail::thread_exit_callback_node* const current_node=thread_info->thread_exit_callbacks;
|
||||
thread_info->thread_exit_callbacks=current_node->next;
|
||||
if(current_node->func)
|
||||
{
|
||||
(*current_node->func)();
|
||||
delete current_node->func;
|
||||
}
|
||||
delete current_node;
|
||||
}
|
||||
while(thread_info->tss_data)
|
||||
{
|
||||
detail::tss_data_node* const current_node=thread_info->tss_data;
|
||||
thread_info->tss_data=current_node->next;
|
||||
if(current_node->func)
|
||||
{
|
||||
(*current_node->func)(current_node->value);
|
||||
}
|
||||
delete current_node;
|
||||
}
|
||||
}
|
||||
thread_info->self.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void create_current_thread_tls_key()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_key_create(¤t_thread_tls_key,&tls_destructor));
|
||||
}
|
||||
}
|
||||
|
||||
boost::detail::thread_data_base* get_current_thread_data()
|
||||
{
|
||||
boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key);
|
||||
return (boost::detail::thread_data_base*)pthread_getspecific(current_thread_tls_key);
|
||||
}
|
||||
|
||||
void set_current_thread_data(detail::thread_data_base* new_data)
|
||||
{
|
||||
boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key);
|
||||
BOOST_VERIFY(!pthread_setspecific(current_thread_tls_key,new_data));
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
extern "C"
|
||||
{
|
||||
void* thread_proxy(void* param)
|
||||
{
|
||||
boost::detail::thread_data_ptr thread_info = static_cast<boost::detail::thread_data_base*>(param)->self;
|
||||
thread_info->self.reset();
|
||||
detail::set_current_thread_data(thread_info.get());
|
||||
try
|
||||
{
|
||||
thread_info->run();
|
||||
}
|
||||
catch(thread_interrupted const&)
|
||||
{
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
detail::tls_destructor(thread_info.get());
|
||||
detail::set_current_thread_data(0);
|
||||
boost::lock_guard<boost::mutex> lock(thread_info->data_mutex);
|
||||
thread_info->done=true;
|
||||
thread_info->done_condition.notify_all();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
struct externally_launched_thread:
|
||||
detail::thread_data_base
|
||||
{
|
||||
externally_launched_thread()
|
||||
{
|
||||
interrupt_enabled=false;
|
||||
}
|
||||
|
||||
void run()
|
||||
{}
|
||||
|
||||
private:
|
||||
externally_launched_thread(externally_launched_thread&);
|
||||
void operator=(externally_launched_thread&);
|
||||
};
|
||||
|
||||
detail::thread_data_base* make_external_thread_data()
|
||||
{
|
||||
detail::thread_data_base* const me(new externally_launched_thread());
|
||||
me->self.reset(me);
|
||||
set_current_thread_data(me);
|
||||
return me;
|
||||
}
|
||||
|
||||
|
||||
detail::thread_data_base* get_or_make_current_thread_data()
|
||||
{
|
||||
detail::thread_data_base* current_thread_data(detail::get_current_thread_data());
|
||||
if(!current_thread_data)
|
||||
{
|
||||
current_thread_data=make_external_thread_data();
|
||||
}
|
||||
return current_thread_data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
thread::thread()
|
||||
{}
|
||||
|
||||
void thread::start_thread()
|
||||
{
|
||||
thread_info->self=thread_info;
|
||||
int const res = pthread_create(&thread_info->thread_handle, 0, &thread_proxy, thread_info.get());
|
||||
if (res != 0)
|
||||
{
|
||||
thread_info->self.reset();
|
||||
throw thread_resource_error();
|
||||
}
|
||||
}
|
||||
|
||||
thread::~thread()
|
||||
{
|
||||
detach();
|
||||
}
|
||||
|
||||
detail::thread_data_ptr thread::get_thread_info() const
|
||||
{
|
||||
lock_guard<mutex> l(thread_info_mutex);
|
||||
return thread_info;
|
||||
}
|
||||
|
||||
void thread::join()
|
||||
{
|
||||
detail::thread_data_ptr const local_thread_info=get_thread_info();
|
||||
if(local_thread_info)
|
||||
{
|
||||
bool do_join=false;
|
||||
|
||||
{
|
||||
unique_lock<mutex> lock(local_thread_info->data_mutex);
|
||||
while(!local_thread_info->done)
|
||||
{
|
||||
local_thread_info->done_condition.wait(lock);
|
||||
}
|
||||
do_join=!local_thread_info->join_started;
|
||||
|
||||
if(do_join)
|
||||
{
|
||||
local_thread_info->join_started=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
while(!local_thread_info->joined)
|
||||
{
|
||||
local_thread_info->done_condition.wait(lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(do_join)
|
||||
{
|
||||
void* result=0;
|
||||
BOOST_VERIFY(!pthread_join(local_thread_info->thread_handle,&result));
|
||||
lock_guard<mutex> lock(local_thread_info->data_mutex);
|
||||
local_thread_info->joined=true;
|
||||
local_thread_info->done_condition.notify_all();
|
||||
}
|
||||
|
||||
lock_guard<mutex> l1(thread_info_mutex);
|
||||
if(thread_info==local_thread_info)
|
||||
{
|
||||
thread_info.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool thread::timed_join(system_time const& wait_until)
|
||||
{
|
||||
detail::thread_data_ptr const local_thread_info=get_thread_info();
|
||||
if(local_thread_info)
|
||||
{
|
||||
bool do_join=false;
|
||||
|
||||
{
|
||||
unique_lock<mutex> lock(local_thread_info->data_mutex);
|
||||
while(!local_thread_info->done)
|
||||
{
|
||||
if(!local_thread_info->done_condition.timed_wait(lock,wait_until))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
do_join=!local_thread_info->join_started;
|
||||
|
||||
if(do_join)
|
||||
{
|
||||
local_thread_info->join_started=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
while(!local_thread_info->joined)
|
||||
{
|
||||
local_thread_info->done_condition.wait(lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(do_join)
|
||||
{
|
||||
void* result=0;
|
||||
BOOST_VERIFY(!pthread_join(local_thread_info->thread_handle,&result));
|
||||
lock_guard<mutex> lock(local_thread_info->data_mutex);
|
||||
local_thread_info->joined=true;
|
||||
local_thread_info->done_condition.notify_all();
|
||||
}
|
||||
|
||||
lock_guard<mutex> l1(thread_info_mutex);
|
||||
if(thread_info==local_thread_info)
|
||||
{
|
||||
thread_info.reset();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool thread::joinable() const
|
||||
{
|
||||
return get_thread_info();
|
||||
}
|
||||
|
||||
|
||||
void thread::detach()
|
||||
{
|
||||
detail::thread_data_ptr local_thread_info;
|
||||
{
|
||||
lock_guard<mutex> l1(thread_info_mutex);
|
||||
thread_info.swap(local_thread_info);
|
||||
}
|
||||
|
||||
if(local_thread_info)
|
||||
{
|
||||
lock_guard<mutex> lock(local_thread_info->data_mutex);
|
||||
if(!local_thread_info->join_started)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_detach(local_thread_info->thread_handle));
|
||||
local_thread_info->join_started=true;
|
||||
local_thread_info->joined=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace this_thread
|
||||
{
|
||||
|
||||
void sleep(const system_time& st)
|
||||
{
|
||||
detail::thread_data_base* const thread_info=detail::get_current_thread_data();
|
||||
|
||||
if(thread_info)
|
||||
{
|
||||
unique_lock<mutex> lk(thread_info->sleep_mutex);
|
||||
while(thread_info->sleep_condition.timed_wait(lk,st));
|
||||
}
|
||||
else
|
||||
{
|
||||
xtime const xt=get_xtime(st);
|
||||
|
||||
for (int foo=0; foo < 5; ++foo)
|
||||
{
|
||||
# if defined(BOOST_HAS_PTHREAD_DELAY_NP)
|
||||
timespec ts;
|
||||
to_timespec_duration(xt, ts);
|
||||
BOOST_VERIFY(!pthread_delay_np(&ts));
|
||||
# elif defined(BOOST_HAS_NANOSLEEP)
|
||||
timespec ts;
|
||||
to_timespec_duration(xt, ts);
|
||||
|
||||
// nanosleep takes a timespec that is an offset, not
|
||||
// an absolute time.
|
||||
nanosleep(&ts, 0);
|
||||
# else
|
||||
mutex mx;
|
||||
mutex::scoped_lock lock(mx);
|
||||
condition cond;
|
||||
cond.timed_wait(lock, xt);
|
||||
# endif
|
||||
xtime cur;
|
||||
xtime_get(&cur, TIME_UTC);
|
||||
if (xtime_cmp(xt, cur) <= 0)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void yield()
|
||||
{
|
||||
# if defined(BOOST_HAS_SCHED_YIELD)
|
||||
BOOST_VERIFY(!sched_yield());
|
||||
# elif defined(BOOST_HAS_PTHREAD_YIELD)
|
||||
BOOST_VERIFY(!pthread_yield());
|
||||
# else
|
||||
xtime xt;
|
||||
xtime_get(&xt, TIME_UTC);
|
||||
sleep(xt);
|
||||
# endif
|
||||
}
|
||||
}
|
||||
|
||||
unsigned thread::hardware_concurrency()
|
||||
{
|
||||
#if defined(PTW32_VERSION) || defined(__hpux)
|
||||
return pthread_num_processors_np();
|
||||
#elif defined(__linux__)
|
||||
return get_nprocs();
|
||||
#elif defined(__APPLE__) || defined(__FreeBSD__)
|
||||
int count;
|
||||
size_t size=sizeof(count);
|
||||
return sysctlbyname("hw.ncpu",&count,&size,NULL,0)?0:count;
|
||||
#elif defined(BOOST_HAS_UNISTD_H) && defined(_SC_NPROCESSORS_ONLN)
|
||||
int const count=sysconf(_SC_NPROCESSORS_ONLN);
|
||||
return (count>0)?count:0;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
thread::id thread::get_id() const
|
||||
{
|
||||
detail::thread_data_ptr const local_thread_info=get_thread_info();
|
||||
if(local_thread_info)
|
||||
{
|
||||
return id(local_thread_info);
|
||||
}
|
||||
else
|
||||
{
|
||||
return id();
|
||||
}
|
||||
}
|
||||
|
||||
void thread::interrupt()
|
||||
{
|
||||
detail::thread_data_ptr const local_thread_info=get_thread_info();
|
||||
if(local_thread_info)
|
||||
{
|
||||
lock_guard<mutex> lk(local_thread_info->data_mutex);
|
||||
local_thread_info->interrupt_requested=true;
|
||||
if(local_thread_info->current_cond)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_cond_broadcast(local_thread_info->current_cond));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool thread::interruption_requested() const
|
||||
{
|
||||
detail::thread_data_ptr const local_thread_info=get_thread_info();
|
||||
if(local_thread_info)
|
||||
{
|
||||
lock_guard<mutex> lk(local_thread_info->data_mutex);
|
||||
return local_thread_info->interrupt_requested;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
thread::native_handle_type thread::native_handle()
|
||||
{
|
||||
detail::thread_data_ptr const local_thread_info=get_thread_info();
|
||||
if(local_thread_info)
|
||||
{
|
||||
lock_guard<mutex> lk(local_thread_info->data_mutex);
|
||||
return local_thread_info->thread_handle;
|
||||
}
|
||||
else
|
||||
{
|
||||
return pthread_t();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
namespace this_thread
|
||||
{
|
||||
thread::id get_id()
|
||||
{
|
||||
boost::detail::thread_data_base* const thread_info=get_or_make_current_thread_data();
|
||||
return thread::id(thread_info?thread_info->shared_from_this():detail::thread_data_ptr());
|
||||
}
|
||||
|
||||
void interruption_point()
|
||||
{
|
||||
boost::detail::thread_data_base* const thread_info=detail::get_current_thread_data();
|
||||
if(thread_info && thread_info->interrupt_enabled)
|
||||
{
|
||||
lock_guard<mutex> lg(thread_info->data_mutex);
|
||||
if(thread_info->interrupt_requested)
|
||||
{
|
||||
thread_info->interrupt_requested=false;
|
||||
throw thread_interrupted();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool interruption_enabled()
|
||||
{
|
||||
boost::detail::thread_data_base* const thread_info=detail::get_current_thread_data();
|
||||
return thread_info && thread_info->interrupt_enabled;
|
||||
}
|
||||
|
||||
bool interruption_requested()
|
||||
{
|
||||
boost::detail::thread_data_base* const thread_info=detail::get_current_thread_data();
|
||||
if(!thread_info)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
lock_guard<mutex> lg(thread_info->data_mutex);
|
||||
return thread_info->interrupt_requested;
|
||||
}
|
||||
}
|
||||
|
||||
disable_interruption::disable_interruption():
|
||||
interruption_was_enabled(interruption_enabled())
|
||||
{
|
||||
if(interruption_was_enabled)
|
||||
{
|
||||
detail::get_current_thread_data()->interrupt_enabled=false;
|
||||
}
|
||||
}
|
||||
|
||||
disable_interruption::~disable_interruption()
|
||||
{
|
||||
if(detail::get_current_thread_data())
|
||||
{
|
||||
detail::get_current_thread_data()->interrupt_enabled=interruption_was_enabled;
|
||||
}
|
||||
}
|
||||
|
||||
restore_interruption::restore_interruption(disable_interruption& d)
|
||||
{
|
||||
if(d.interruption_was_enabled)
|
||||
{
|
||||
detail::get_current_thread_data()->interrupt_enabled=true;
|
||||
}
|
||||
}
|
||||
|
||||
restore_interruption::~restore_interruption()
|
||||
{
|
||||
if(detail::get_current_thread_data())
|
||||
{
|
||||
detail::get_current_thread_data()->interrupt_enabled=false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
void add_thread_exit_function(thread_exit_function_base* func)
|
||||
{
|
||||
detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
|
||||
thread_exit_callback_node* const new_node=
|
||||
new thread_exit_callback_node(func,current_thread_data->thread_exit_callbacks);
|
||||
current_thread_data->thread_exit_callbacks=new_node;
|
||||
}
|
||||
|
||||
tss_data_node* find_tss_data(void const* key)
|
||||
{
|
||||
detail::thread_data_base* const current_thread_data(get_current_thread_data());
|
||||
if(current_thread_data)
|
||||
{
|
||||
detail::tss_data_node* current_node=current_thread_data->tss_data;
|
||||
while(current_node)
|
||||
{
|
||||
if(current_node->key==key)
|
||||
{
|
||||
return current_node;
|
||||
}
|
||||
current_node=current_node->next;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* get_tss_data(void const* key)
|
||||
{
|
||||
if(tss_data_node* const current_node=find_tss_data(key))
|
||||
{
|
||||
return current_node->value;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void set_tss_data(void const* key,boost::shared_ptr<tss_cleanup_function> func,void* tss_data,bool cleanup_existing)
|
||||
{
|
||||
if(tss_data_node* const current_node=find_tss_data(key))
|
||||
{
|
||||
if(cleanup_existing && current_node->func)
|
||||
{
|
||||
(*current_node->func)(current_node->value);
|
||||
}
|
||||
current_node->func=func;
|
||||
current_node->value=tss_data;
|
||||
}
|
||||
else
|
||||
{
|
||||
detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
|
||||
tss_data_node* const new_node=new tss_data_node(key,func,tss_data,current_thread_data->tss_data);
|
||||
current_thread_data->tss_data=new_node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// thread_group::thread_group()
|
||||
// {
|
||||
// }
|
||||
|
||||
// thread_group::~thread_group()
|
||||
// {
|
||||
// // We shouldn't have to scoped_lock here, since referencing this object
|
||||
// // from another thread while we're deleting it in the current thread is
|
||||
// // going to lead to undefined behavior any way.
|
||||
// for (std::list<thread*>::iterator it = m_threads.begin();
|
||||
// it != m_threads.end(); ++it)
|
||||
// {
|
||||
// delete (*it);
|
||||
// }
|
||||
// }
|
||||
|
||||
// thread* thread_group::create_thread(const function0<void>& threadfunc)
|
||||
// {
|
||||
// // No scoped_lock required here since the only "shared data" that's
|
||||
// // modified here occurs inside add_thread which does scoped_lock.
|
||||
// std::auto_ptr<thread> thrd(new thread(threadfunc));
|
||||
// add_thread(thrd.get());
|
||||
// return thrd.release();
|
||||
// }
|
||||
|
||||
// void thread_group::add_thread(thread* thrd)
|
||||
// {
|
||||
// mutex::scoped_lock scoped_lock(m_mutex);
|
||||
|
||||
// // For now we'll simply ignore requests to add a thread object multiple
|
||||
// // times. Should we consider this an error and either throw or return an
|
||||
// // error value?
|
||||
// std::list<thread*>::iterator it = std::find(m_threads.begin(),
|
||||
// m_threads.end(), thrd);
|
||||
// BOOST_ASSERT(it == m_threads.end());
|
||||
// if (it == m_threads.end())
|
||||
// m_threads.push_back(thrd);
|
||||
// }
|
||||
|
||||
// void thread_group::remove_thread(thread* thrd)
|
||||
// {
|
||||
// mutex::scoped_lock scoped_lock(m_mutex);
|
||||
|
||||
// // For now we'll simply ignore requests to remove a thread object that's
|
||||
// // not in the group. Should we consider this an error and either throw or
|
||||
// // return an error value?
|
||||
// std::list<thread*>::iterator it = std::find(m_threads.begin(),
|
||||
// m_threads.end(), thrd);
|
||||
// BOOST_ASSERT(it != m_threads.end());
|
||||
// if (it != m_threads.end())
|
||||
// m_threads.erase(it);
|
||||
// }
|
||||
|
||||
// void thread_group::join_all()
|
||||
// {
|
||||
// mutex::scoped_lock scoped_lock(m_mutex);
|
||||
// for (std::list<thread*>::iterator it = m_threads.begin();
|
||||
// it != m_threads.end(); ++it)
|
||||
// {
|
||||
// (*it)->join();
|
||||
// }
|
||||
// }
|
||||
|
||||
// void thread_group::interrupt_all()
|
||||
// {
|
||||
// boost::lock_guard<mutex> guard(m_mutex);
|
||||
|
||||
// for(std::list<thread*>::iterator it=m_threads.begin(),end=m_threads.end();
|
||||
// it!=end;
|
||||
// ++it)
|
||||
// {
|
||||
// (*it)->interrupt();
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
// size_t thread_group::size() const
|
||||
// {
|
||||
// return m_threads.size();
|
||||
// }
|
||||
|
||||
}
|
||||
130
src/pthread/timeconv.inl
Normal file
130
src/pthread/timeconv.inl
Normal file
@@ -0,0 +1,130 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// boostinspect:nounnamed
|
||||
|
||||
namespace {
|
||||
const int MILLISECONDS_PER_SECOND = 1000;
|
||||
const int NANOSECONDS_PER_SECOND = 1000000000;
|
||||
const int NANOSECONDS_PER_MILLISECOND = 1000000;
|
||||
|
||||
const int MICROSECONDS_PER_SECOND = 1000000;
|
||||
const int NANOSECONDS_PER_MICROSECOND = 1000;
|
||||
|
||||
inline void to_time(int milliseconds, boost::xtime& xt)
|
||||
{
|
||||
int res = 0;
|
||||
res = boost::xtime_get(&xt, boost::TIME_UTC);
|
||||
assert(res == boost::TIME_UTC);
|
||||
|
||||
xt.sec += (milliseconds / MILLISECONDS_PER_SECOND);
|
||||
xt.nsec += ((milliseconds % MILLISECONDS_PER_SECOND) *
|
||||
NANOSECONDS_PER_MILLISECOND);
|
||||
|
||||
if (xt.nsec >= NANOSECONDS_PER_SECOND)
|
||||
{
|
||||
++xt.sec;
|
||||
xt.nsec -= NANOSECONDS_PER_SECOND;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
inline void to_timespec(const boost::xtime& xt, timespec& ts)
|
||||
{
|
||||
ts.tv_sec = static_cast<int>(xt.sec);
|
||||
ts.tv_nsec = static_cast<int>(xt.nsec);
|
||||
if(ts.tv_nsec >= NANOSECONDS_PER_SECOND)
|
||||
{
|
||||
ts.tv_sec += ts.tv_nsec / NANOSECONDS_PER_SECOND;
|
||||
ts.tv_nsec %= NANOSECONDS_PER_SECOND;
|
||||
}
|
||||
}
|
||||
|
||||
inline void to_time(int milliseconds, timespec& ts)
|
||||
{
|
||||
boost::xtime xt;
|
||||
to_time(milliseconds, xt);
|
||||
to_timespec(xt, ts);
|
||||
}
|
||||
|
||||
inline void to_timespec_duration(const boost::xtime& xt, timespec& ts)
|
||||
{
|
||||
boost::xtime cur;
|
||||
int res = 0;
|
||||
res = boost::xtime_get(&cur, boost::TIME_UTC);
|
||||
assert(res == boost::TIME_UTC);
|
||||
|
||||
if (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 >= NANOSECONDS_PER_SECOND)
|
||||
{
|
||||
ts.tv_sec += ts.tv_nsec / NANOSECONDS_PER_SECOND;
|
||||
ts.tv_nsec %= NANOSECONDS_PER_SECOND;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
inline void to_duration(boost::xtime xt, int& milliseconds)
|
||||
{
|
||||
boost::xtime cur;
|
||||
int res = 0;
|
||||
res = boost::xtime_get(&cur, boost::TIME_UTC);
|
||||
assert(res == boost::TIME_UTC);
|
||||
|
||||
if (boost::xtime_cmp(xt, cur) <= 0)
|
||||
milliseconds = 0;
|
||||
else
|
||||
{
|
||||
if (cur.nsec > xt.nsec)
|
||||
{
|
||||
xt.nsec += NANOSECONDS_PER_SECOND;
|
||||
--xt.sec;
|
||||
}
|
||||
milliseconds = (int)((xt.sec - cur.sec) * MILLISECONDS_PER_SECOND) +
|
||||
(((xt.nsec - cur.nsec) + (NANOSECONDS_PER_MILLISECOND/2)) /
|
||||
NANOSECONDS_PER_MILLISECOND);
|
||||
}
|
||||
}
|
||||
|
||||
inline void to_microduration(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_cmp(xt, cur) <= 0)
|
||||
microseconds = 0;
|
||||
else
|
||||
{
|
||||
if (cur.nsec > xt.nsec)
|
||||
{
|
||||
xt.nsec += NANOSECONDS_PER_SECOND;
|
||||
--xt.sec;
|
||||
}
|
||||
microseconds = (int)((xt.sec - cur.sec) * MICROSECONDS_PER_SECOND) +
|
||||
(((xt.nsec - cur.nsec) + (NANOSECONDS_PER_MICROSECOND/2)) /
|
||||
NANOSECONDS_PER_MICROSECOND);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Change Log:
|
||||
// 1 Jun 01 Initial creation.
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,6 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
// Copyright (C) 2007 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -9,6 +10,7 @@
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <boost/thread/condition.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
#include <cassert>
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
@@ -100,22 +102,13 @@ extern "C" {
|
||||
static OSStatus thread_proxy(void* param)
|
||||
#endif
|
||||
{
|
||||
//try
|
||||
//{
|
||||
thread_param* p = static_cast<thread_param*>(param);
|
||||
boost::function0<void> threadfunc = p->m_threadfunc;
|
||||
p->started();
|
||||
threadfunc();
|
||||
thread_param* p = static_cast<thread_param*>(param);
|
||||
boost::function0<void> threadfunc = p->m_threadfunc;
|
||||
p->started();
|
||||
threadfunc();
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
on_thread_exit();
|
||||
on_thread_exit();
|
||||
#endif
|
||||
//}
|
||||
//catch (...)
|
||||
//{
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
// on_thread_exit();
|
||||
#endif
|
||||
//}
|
||||
#if defined(BOOST_HAS_MPTASKS)
|
||||
::boost::detail::thread_cleanup();
|
||||
#endif
|
||||
@@ -363,7 +356,7 @@ void thread_group::join_all()
|
||||
}
|
||||
}
|
||||
|
||||
int thread_group::size()
|
||||
int thread_group::size() const
|
||||
{
|
||||
return m_threads.size();
|
||||
}
|
||||
|
||||
10
src/tss.cpp
10
src/tss.cpp
@@ -31,7 +31,7 @@ boost::once_flag tss_data_once = BOOST_ONCE_INIT;
|
||||
boost::mutex* tss_data_mutex = 0;
|
||||
tss_data_cleanup_handlers_type* tss_data_cleanup_handlers = 0;
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
DWORD tss_data_native_key;
|
||||
DWORD tss_data_native_key=TLS_OUT_OF_INDEXES;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
pthread_key_t tss_data_native_key;
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
@@ -60,6 +60,7 @@ void tss_data_dec_use(boost::mutex::scoped_lock& lk)
|
||||
tss_data_mutex = 0;
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
TlsFree(tss_data_native_key);
|
||||
tss_data_native_key=TLS_OUT_OF_INDEXES;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
pthread_key_delete(tss_data_native_key);
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
@@ -78,6 +79,9 @@ extern "C" void cleanup_slots(void* p)
|
||||
(*(*tss_data_cleanup_handlers)[i])((*slots)[i]);
|
||||
(*slots)[i] = 0;
|
||||
}
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
TlsSetValue(tss_data_native_key,0);
|
||||
#endif
|
||||
tss_data_dec_use(lock);
|
||||
delete slots;
|
||||
}
|
||||
@@ -97,7 +101,7 @@ void init_tss_data()
|
||||
|
||||
//Allocate tls slot
|
||||
tss_data_native_key = TlsAlloc();
|
||||
if (tss_data_native_key == 0xFFFFFFFF)
|
||||
if (tss_data_native_key == TLS_OUT_OF_INDEXES)
|
||||
return;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
int res = pthread_key_create(&tss_data_native_key, &cleanup_slots);
|
||||
@@ -178,7 +182,7 @@ namespace boost {
|
||||
namespace detail {
|
||||
void tss::init(boost::function1<void, void*>* pcleanup)
|
||||
{
|
||||
boost::call_once(&init_tss_data, tss_data_once);
|
||||
boost::call_once(tss_data_once, &init_tss_data);
|
||||
if (tss_data_cleanup_handlers == 0)
|
||||
throw thread_resource_error();
|
||||
boost::mutex::scoped_lock lock(*tss_data_mutex);
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
thread_exit_handler exit_handler
|
||||
)
|
||||
{
|
||||
boost::call_once(init_threadmon_mutex, once_init_threadmon_mutex);
|
||||
boost::call_once(once_init_threadmon_mutex, init_threadmon_mutex);
|
||||
//boost::mutex::scoped_lock lock(*threadmon_mutex);
|
||||
CScopedCSLock lock(&threadmon_mutex);
|
||||
|
||||
@@ -141,7 +141,7 @@
|
||||
|
||||
extern "C" BOOST_THREAD_DECL void on_process_enter(void)
|
||||
{
|
||||
boost::call_once(init_threadmon_mutex, once_init_threadmon_mutex);
|
||||
boost::call_once(once_init_threadmon_mutex, init_threadmon_mutex);
|
||||
// boost::mutex::scoped_lock lock(*threadmon_mutex);
|
||||
CScopedCSLock lock(&threadmon_mutex);
|
||||
|
||||
@@ -150,7 +150,7 @@
|
||||
|
||||
extern "C" BOOST_THREAD_DECL void on_process_exit(void)
|
||||
{
|
||||
boost::call_once(init_threadmon_mutex, once_init_threadmon_mutex);
|
||||
boost::call_once(once_init_threadmon_mutex, init_threadmon_mutex);
|
||||
// boost::mutex::scoped_lock lock(*threadmon_mutex);
|
||||
CScopedCSLock lock(&threadmon_mutex);
|
||||
|
||||
@@ -173,7 +173,7 @@
|
||||
|
||||
extern "C" BOOST_THREAD_DECL void on_thread_exit(void)
|
||||
{
|
||||
boost::call_once(init_threadmon_mutex, once_init_threadmon_mutex);
|
||||
boost::call_once(once_init_threadmon_mutex, init_threadmon_mutex);
|
||||
// boost::mutex::scoped_lock lock(*threadmon_mutex);
|
||||
CScopedCSLock lock(&threadmon_mutex);
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
// (C) Copyright Michael Glassford 2004.
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS) && (defined(BOOST_THREAD_BUILD_LIB) || defined(BOOST_THREAD_TEST)) && !defined(_MSC_VER)
|
||||
#if defined(BOOST_HAS_WINTHREADS) && (defined(BOOST_THREAD_BUILD_LIB) || defined(BOOST_THREAD_TEST) || defined(UNDER_CE)) && (!defined(_MSC_VER) || defined(UNDER_CE))
|
||||
|
||||
/*
|
||||
This file is a "null" implementation of tss cleanup; it's
|
||||
|
||||
124
src/win32/exceptions.cpp
Normal file
124
src/win32/exceptions.cpp
Normal file
@@ -0,0 +1,124 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
namespace boost {
|
||||
|
||||
thread_exception::thread_exception()
|
||||
: m_sys_err(0)
|
||||
{
|
||||
}
|
||||
|
||||
thread_exception::thread_exception(int sys_err_code)
|
||||
: m_sys_err(sys_err_code)
|
||||
{
|
||||
}
|
||||
|
||||
thread_exception::~thread_exception() throw()
|
||||
{
|
||||
}
|
||||
|
||||
int thread_exception::native_error() const
|
||||
{
|
||||
return m_sys_err;
|
||||
}
|
||||
|
||||
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
|
||||
595
src/win32/thread.cpp
Normal file
595
src/win32/thread.cpp
Normal file
@@ -0,0 +1,595 @@
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
// (C) Copyright 2007 David Deakins
|
||||
|
||||
#define _WIN32_WINNT 0x400
|
||||
#define WINVER 0x400
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <algorithm>
|
||||
#include <windows.h>
|
||||
#ifndef UNDER_CE
|
||||
#include <process.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <boost/thread/once.hpp>
|
||||
#include <boost/thread/tss.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/thread/detail/tss_hooks.hpp>
|
||||
#include <boost/date_time/posix_time/conversion.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace
|
||||
{
|
||||
boost::once_flag current_thread_tls_init_flag=BOOST_ONCE_INIT;
|
||||
DWORD current_thread_tls_key=0;
|
||||
|
||||
void create_current_thread_tls_key()
|
||||
{
|
||||
tss_cleanup_implemented(); // if anyone uses TSS, we need the cleanup linked in
|
||||
current_thread_tls_key=TlsAlloc();
|
||||
BOOST_ASSERT(current_thread_tls_key!=TLS_OUT_OF_INDEXES);
|
||||
}
|
||||
|
||||
void cleanup_tls_key()
|
||||
{
|
||||
if(current_thread_tls_key)
|
||||
{
|
||||
TlsFree(current_thread_tls_key);
|
||||
current_thread_tls_key=0;
|
||||
}
|
||||
}
|
||||
|
||||
detail::thread_data_base* get_current_thread_data()
|
||||
{
|
||||
if(!current_thread_tls_key)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return (detail::thread_data_base*)TlsGetValue(current_thread_tls_key);
|
||||
}
|
||||
|
||||
void set_current_thread_data(detail::thread_data_base* new_data)
|
||||
{
|
||||
boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key);
|
||||
BOOST_VERIFY(TlsSetValue(current_thread_tls_key,new_data));
|
||||
}
|
||||
|
||||
#ifdef BOOST_NO_THREADEX
|
||||
// Windows CE doesn't define _beginthreadex
|
||||
|
||||
struct ThreadProxyData
|
||||
{
|
||||
typedef unsigned (__stdcall* func)(void*);
|
||||
func start_address_;
|
||||
void* arglist_;
|
||||
ThreadProxyData(func start_address,void* arglist) : start_address_(start_address), arglist_(arglist) {}
|
||||
};
|
||||
|
||||
DWORD WINAPI ThreadProxy(LPVOID args)
|
||||
{
|
||||
ThreadProxyData* data=reinterpret_cast<ThreadProxyData*>(args);
|
||||
DWORD ret=data->start_address_(data->arglist_);
|
||||
delete data;
|
||||
return ret;
|
||||
}
|
||||
|
||||
typedef void* uintptr_t;
|
||||
|
||||
inline uintptr_t const _beginthreadex(void* security, unsigned stack_size, unsigned (__stdcall* start_address)(void*),
|
||||
void* arglist, unsigned initflag, unsigned* thrdaddr)
|
||||
{
|
||||
DWORD threadID;
|
||||
HANDLE hthread=CreateThread(static_cast<LPSECURITY_ATTRIBUTES>(security),stack_size,ThreadProxy,
|
||||
new ThreadProxyData(start_address,arglist),initflag,&threadID);
|
||||
if (hthread!=0)
|
||||
*thrdaddr=threadID;
|
||||
return reinterpret_cast<uintptr_t const>(hthread);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct thread_exit_callback_node
|
||||
{
|
||||
boost::detail::thread_exit_function_base* func;
|
||||
thread_exit_callback_node* next;
|
||||
|
||||
thread_exit_callback_node(boost::detail::thread_exit_function_base* func_,
|
||||
thread_exit_callback_node* next_):
|
||||
func(func_),next(next_)
|
||||
{}
|
||||
};
|
||||
|
||||
struct tss_data_node
|
||||
{
|
||||
void const* key;
|
||||
boost::shared_ptr<boost::detail::tss_cleanup_function> func;
|
||||
void* value;
|
||||
tss_data_node* next;
|
||||
|
||||
tss_data_node(void const* key_,boost::shared_ptr<boost::detail::tss_cleanup_function> func_,void* value_,
|
||||
tss_data_node* next_):
|
||||
key(key_),func(func_),value(value_),next(next_)
|
||||
{}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
void run_thread_exit_callbacks()
|
||||
{
|
||||
detail::thread_data_ptr current_thread_data(get_current_thread_data(),false);
|
||||
if(current_thread_data)
|
||||
{
|
||||
while(current_thread_data->tss_data || current_thread_data->thread_exit_callbacks)
|
||||
{
|
||||
while(current_thread_data->thread_exit_callbacks)
|
||||
{
|
||||
detail::thread_exit_callback_node* const current_node=current_thread_data->thread_exit_callbacks;
|
||||
current_thread_data->thread_exit_callbacks=current_node->next;
|
||||
if(current_node->func)
|
||||
{
|
||||
(*current_node->func)();
|
||||
boost::detail::heap_delete(current_node->func);
|
||||
}
|
||||
boost::detail::heap_delete(current_node);
|
||||
}
|
||||
while(current_thread_data->tss_data)
|
||||
{
|
||||
detail::tss_data_node* const current_node=current_thread_data->tss_data;
|
||||
current_thread_data->tss_data=current_node->next;
|
||||
if(current_node->func)
|
||||
{
|
||||
(*current_node->func)(current_node->value);
|
||||
}
|
||||
boost::detail::heap_delete(current_node);
|
||||
}
|
||||
}
|
||||
|
||||
set_current_thread_data(0);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned __stdcall thread_start_function(void* param)
|
||||
{
|
||||
detail::thread_data_base* const thread_info(reinterpret_cast<detail::thread_data_base*>(param));
|
||||
set_current_thread_data(thread_info);
|
||||
try
|
||||
{
|
||||
thread_info->run();
|
||||
}
|
||||
catch(thread_interrupted const&)
|
||||
{
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
std::terminate();
|
||||
}
|
||||
run_thread_exit_callbacks();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
thread::thread()
|
||||
{}
|
||||
|
||||
void thread::start_thread()
|
||||
{
|
||||
uintptr_t const new_thread=_beginthreadex(0,0,&thread_start_function,thread_info.get(),CREATE_SUSPENDED,&thread_info->id);
|
||||
if(!new_thread)
|
||||
{
|
||||
throw thread_resource_error();
|
||||
}
|
||||
intrusive_ptr_add_ref(thread_info.get());
|
||||
thread_info->thread_handle=(detail::win32::handle)(new_thread);
|
||||
ResumeThread(thread_info->thread_handle);
|
||||
}
|
||||
|
||||
thread::thread(detail::thread_data_ptr data):
|
||||
thread_info(data)
|
||||
{}
|
||||
|
||||
namespace
|
||||
{
|
||||
struct externally_launched_thread:
|
||||
detail::thread_data_base
|
||||
{
|
||||
externally_launched_thread()
|
||||
{
|
||||
++count;
|
||||
interruption_enabled=false;
|
||||
}
|
||||
|
||||
void run()
|
||||
{}
|
||||
private:
|
||||
externally_launched_thread(externally_launched_thread&);
|
||||
void operator=(externally_launched_thread&);
|
||||
};
|
||||
|
||||
void make_external_thread_data()
|
||||
{
|
||||
externally_launched_thread* me=detail::heap_new<externally_launched_thread>();
|
||||
set_current_thread_data(me);
|
||||
}
|
||||
|
||||
detail::thread_data_base* get_or_make_current_thread_data()
|
||||
{
|
||||
detail::thread_data_base* current_thread_data(get_current_thread_data());
|
||||
if(!current_thread_data)
|
||||
{
|
||||
make_external_thread_data();
|
||||
current_thread_data=get_current_thread_data();
|
||||
}
|
||||
return current_thread_data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
thread::~thread()
|
||||
{
|
||||
detach();
|
||||
}
|
||||
|
||||
thread::id thread::get_id() const
|
||||
{
|
||||
return thread::id(get_thread_info());
|
||||
}
|
||||
|
||||
bool thread::joinable() const
|
||||
{
|
||||
return get_thread_info();
|
||||
}
|
||||
|
||||
void thread::join()
|
||||
{
|
||||
detail::thread_data_ptr local_thread_info=get_thread_info();
|
||||
if(local_thread_info)
|
||||
{
|
||||
this_thread::interruptible_wait(local_thread_info->thread_handle,detail::timeout::sentinel());
|
||||
release_handle();
|
||||
}
|
||||
}
|
||||
|
||||
bool thread::timed_join(boost::system_time const& wait_until)
|
||||
{
|
||||
detail::thread_data_ptr local_thread_info=get_thread_info();
|
||||
if(local_thread_info)
|
||||
{
|
||||
if(!this_thread::interruptible_wait(local_thread_info->thread_handle,get_milliseconds_until(wait_until)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
release_handle();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void thread::detach()
|
||||
{
|
||||
release_handle();
|
||||
}
|
||||
|
||||
void thread::release_handle()
|
||||
{
|
||||
lock_guard<mutex> l1(thread_info_mutex);
|
||||
thread_info=0;
|
||||
}
|
||||
|
||||
void thread::interrupt()
|
||||
{
|
||||
detail::thread_data_ptr local_thread_info=get_thread_info();
|
||||
if(local_thread_info)
|
||||
{
|
||||
local_thread_info->interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
bool thread::interruption_requested() const
|
||||
{
|
||||
detail::thread_data_ptr local_thread_info=get_thread_info();
|
||||
return local_thread_info.get() && (detail::win32::WaitForSingleObject(local_thread_info->interruption_handle,0)==0);
|
||||
}
|
||||
|
||||
unsigned thread::hardware_concurrency()
|
||||
{
|
||||
SYSTEM_INFO info={0};
|
||||
GetSystemInfo(&info);
|
||||
return info.dwNumberOfProcessors;
|
||||
}
|
||||
|
||||
thread::native_handle_type thread::native_handle()
|
||||
{
|
||||
detail::thread_data_ptr local_thread_info=get_thread_info();
|
||||
return local_thread_info?(detail::win32::handle)local_thread_info->thread_handle:detail::win32::invalid_handle_value;
|
||||
}
|
||||
|
||||
detail::thread_data_ptr thread::get_thread_info() const
|
||||
{
|
||||
boost::mutex::scoped_lock l(thread_info_mutex);
|
||||
return thread_info;
|
||||
}
|
||||
|
||||
namespace this_thread
|
||||
{
|
||||
namespace
|
||||
{
|
||||
LARGE_INTEGER get_due_time(detail::timeout const& target_time)
|
||||
{
|
||||
LARGE_INTEGER due_time={0};
|
||||
if(target_time.relative)
|
||||
{
|
||||
unsigned long const elapsed_milliseconds=GetTickCount()-target_time.start;
|
||||
LONGLONG const remaining_milliseconds=(target_time.milliseconds-elapsed_milliseconds);
|
||||
LONGLONG const hundred_nanoseconds_in_one_millisecond=10000;
|
||||
|
||||
if(remaining_milliseconds>0)
|
||||
{
|
||||
due_time.QuadPart=-(remaining_milliseconds*hundred_nanoseconds_in_one_millisecond);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SYSTEMTIME target_system_time={0};
|
||||
target_system_time.wYear=target_time.abs_time.date().year();
|
||||
target_system_time.wMonth=target_time.abs_time.date().month();
|
||||
target_system_time.wDay=target_time.abs_time.date().day();
|
||||
target_system_time.wHour=(WORD)target_time.abs_time.time_of_day().hours();
|
||||
target_system_time.wMinute=(WORD)target_time.abs_time.time_of_day().minutes();
|
||||
target_system_time.wSecond=(WORD)target_time.abs_time.time_of_day().seconds();
|
||||
|
||||
if(!SystemTimeToFileTime(&target_system_time,((FILETIME*)&due_time)))
|
||||
{
|
||||
due_time.QuadPart=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
long const hundred_nanoseconds_in_one_second=10000000;
|
||||
due_time.QuadPart+=target_time.abs_time.time_of_day().fractional_seconds()*(hundred_nanoseconds_in_one_second/target_time.abs_time.time_of_day().ticks_per_second());
|
||||
}
|
||||
}
|
||||
return due_time;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool interruptible_wait(detail::win32::handle handle_to_wait_for,detail::timeout target_time)
|
||||
{
|
||||
detail::win32::handle handles[3]={0};
|
||||
unsigned handle_count=0;
|
||||
unsigned wait_handle_index=~0U;
|
||||
unsigned interruption_index=~0U;
|
||||
unsigned timeout_index=~0U;
|
||||
if(handle_to_wait_for!=detail::win32::invalid_handle_value)
|
||||
{
|
||||
wait_handle_index=handle_count;
|
||||
handles[handle_count++]=handle_to_wait_for;
|
||||
}
|
||||
if(get_current_thread_data() && get_current_thread_data()->interruption_enabled)
|
||||
{
|
||||
interruption_index=handle_count;
|
||||
handles[handle_count++]=get_current_thread_data()->interruption_handle;
|
||||
}
|
||||
|
||||
detail::win32::handle_manager timer_handle;
|
||||
|
||||
#ifndef UNDER_CE
|
||||
unsigned const min_timer_wait_period=20;
|
||||
|
||||
if(!target_time.is_sentinel())
|
||||
{
|
||||
detail::timeout::remaining_time const time_left=target_time.remaining_milliseconds();
|
||||
if(time_left.milliseconds > min_timer_wait_period)
|
||||
{
|
||||
// for a long-enough timeout, use a waitable timer (which tracks clock changes)
|
||||
timer_handle=CreateWaitableTimer(NULL,false,NULL);
|
||||
if(timer_handle!=0)
|
||||
{
|
||||
LARGE_INTEGER due_time=get_due_time(target_time);
|
||||
|
||||
bool const set_time_succeeded=SetWaitableTimer(timer_handle,&due_time,0,0,0,false)!=0;
|
||||
if(set_time_succeeded)
|
||||
{
|
||||
timeout_index=handle_count;
|
||||
handles[handle_count++]=timer_handle;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(!target_time.relative)
|
||||
{
|
||||
// convert short absolute-time timeouts into relative ones, so we don't race against clock changes
|
||||
target_time=detail::timeout(time_left.milliseconds);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool const using_timer=timeout_index!=~0u;
|
||||
detail::timeout::remaining_time time_left(0);
|
||||
|
||||
do
|
||||
{
|
||||
if(!using_timer)
|
||||
{
|
||||
time_left=target_time.remaining_milliseconds();
|
||||
}
|
||||
|
||||
if(handle_count)
|
||||
{
|
||||
unsigned long const notified_index=detail::win32::WaitForMultipleObjects(handle_count,handles,false,using_timer?INFINITE:time_left.milliseconds);
|
||||
if(notified_index<handle_count)
|
||||
{
|
||||
if(notified_index==wait_handle_index)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if(notified_index==interruption_index)
|
||||
{
|
||||
detail::win32::ResetEvent(get_current_thread_data()->interruption_handle);
|
||||
throw thread_interrupted();
|
||||
}
|
||||
else if(notified_index==timeout_index)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
detail::win32::Sleep(time_left.milliseconds);
|
||||
}
|
||||
if(target_time.relative)
|
||||
{
|
||||
target_time.milliseconds-=detail::timeout::max_non_infinite_wait;
|
||||
}
|
||||
}
|
||||
while(time_left.more);
|
||||
return false;
|
||||
}
|
||||
|
||||
thread::id get_id()
|
||||
{
|
||||
return thread::id(get_or_make_current_thread_data());
|
||||
}
|
||||
|
||||
void interruption_point()
|
||||
{
|
||||
if(interruption_enabled() && interruption_requested())
|
||||
{
|
||||
detail::win32::ResetEvent(get_current_thread_data()->interruption_handle);
|
||||
throw thread_interrupted();
|
||||
}
|
||||
}
|
||||
|
||||
bool interruption_enabled()
|
||||
{
|
||||
return get_current_thread_data() && get_current_thread_data()->interruption_enabled;
|
||||
}
|
||||
|
||||
bool interruption_requested()
|
||||
{
|
||||
return get_current_thread_data() && (detail::win32::WaitForSingleObject(get_current_thread_data()->interruption_handle,0)==0);
|
||||
}
|
||||
|
||||
void yield()
|
||||
{
|
||||
detail::win32::Sleep(0);
|
||||
}
|
||||
|
||||
disable_interruption::disable_interruption():
|
||||
interruption_was_enabled(interruption_enabled())
|
||||
{
|
||||
if(interruption_was_enabled)
|
||||
{
|
||||
get_current_thread_data()->interruption_enabled=false;
|
||||
}
|
||||
}
|
||||
|
||||
disable_interruption::~disable_interruption()
|
||||
{
|
||||
if(get_current_thread_data())
|
||||
{
|
||||
get_current_thread_data()->interruption_enabled=interruption_was_enabled;
|
||||
}
|
||||
}
|
||||
|
||||
restore_interruption::restore_interruption(disable_interruption& d)
|
||||
{
|
||||
if(d.interruption_was_enabled)
|
||||
{
|
||||
get_current_thread_data()->interruption_enabled=true;
|
||||
}
|
||||
}
|
||||
|
||||
restore_interruption::~restore_interruption()
|
||||
{
|
||||
if(get_current_thread_data())
|
||||
{
|
||||
get_current_thread_data()->interruption_enabled=false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
void add_thread_exit_function(thread_exit_function_base* func)
|
||||
{
|
||||
detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
|
||||
thread_exit_callback_node* const new_node=
|
||||
heap_new<thread_exit_callback_node>(func,
|
||||
current_thread_data->thread_exit_callbacks);
|
||||
current_thread_data->thread_exit_callbacks=new_node;
|
||||
}
|
||||
|
||||
tss_data_node* find_tss_data(void const* key)
|
||||
{
|
||||
detail::thread_data_base* const current_thread_data(get_current_thread_data());
|
||||
if(current_thread_data)
|
||||
{
|
||||
detail::tss_data_node* current_node=current_thread_data->tss_data;
|
||||
while(current_node)
|
||||
{
|
||||
if(current_node->key==key)
|
||||
{
|
||||
return current_node;
|
||||
}
|
||||
current_node=current_node->next;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* get_tss_data(void const* key)
|
||||
{
|
||||
if(tss_data_node* const current_node=find_tss_data(key))
|
||||
{
|
||||
return current_node->value;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void set_tss_data(void const* key,boost::shared_ptr<tss_cleanup_function> func,void* tss_data,bool cleanup_existing)
|
||||
{
|
||||
if(tss_data_node* const current_node=find_tss_data(key))
|
||||
{
|
||||
if(cleanup_existing && current_node->func.get())
|
||||
{
|
||||
(*current_node->func)(current_node->value);
|
||||
}
|
||||
current_node->func=func;
|
||||
current_node->value=tss_data;
|
||||
}
|
||||
else
|
||||
{
|
||||
detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
|
||||
tss_data_node* const new_node=heap_new<tss_data_node>(key,func,tss_data,current_thread_data->tss_data);
|
||||
current_thread_data->tss_data=new_node;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extern "C" BOOST_THREAD_DECL void on_process_enter()
|
||||
{}
|
||||
|
||||
extern "C" BOOST_THREAD_DECL void on_thread_enter()
|
||||
{}
|
||||
|
||||
extern "C" BOOST_THREAD_DECL void on_process_exit()
|
||||
{
|
||||
boost::cleanup_tls_key();
|
||||
}
|
||||
|
||||
extern "C" BOOST_THREAD_DECL void on_thread_exit()
|
||||
{
|
||||
boost::run_thread_exit_callbacks();
|
||||
}
|
||||
|
||||
130
src/win32/timeconv.inl
Normal file
130
src/win32/timeconv.inl
Normal file
@@ -0,0 +1,130 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// boostinspect:nounnamed
|
||||
|
||||
namespace {
|
||||
const int MILLISECONDS_PER_SECOND = 1000;
|
||||
const int NANOSECONDS_PER_SECOND = 1000000000;
|
||||
const int NANOSECONDS_PER_MILLISECOND = 1000000;
|
||||
|
||||
const int MICROSECONDS_PER_SECOND = 1000000;
|
||||
const int NANOSECONDS_PER_MICROSECOND = 1000;
|
||||
|
||||
inline void to_time(int milliseconds, boost::xtime& xt)
|
||||
{
|
||||
int res = 0;
|
||||
res = boost::xtime_get(&xt, boost::TIME_UTC);
|
||||
assert(res == boost::TIME_UTC);
|
||||
|
||||
xt.sec += (milliseconds / MILLISECONDS_PER_SECOND);
|
||||
xt.nsec += ((milliseconds % MILLISECONDS_PER_SECOND) *
|
||||
NANOSECONDS_PER_MILLISECOND);
|
||||
|
||||
if (xt.nsec >= NANOSECONDS_PER_SECOND)
|
||||
{
|
||||
++xt.sec;
|
||||
xt.nsec -= NANOSECONDS_PER_SECOND;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
inline void to_timespec(const boost::xtime& xt, timespec& ts)
|
||||
{
|
||||
ts.tv_sec = static_cast<int>(xt.sec);
|
||||
ts.tv_nsec = static_cast<int>(xt.nsec);
|
||||
if(ts.tv_nsec >= NANOSECONDS_PER_SECOND)
|
||||
{
|
||||
ts.tv_sec += ts.tv_nsec / NANOSECONDS_PER_SECOND;
|
||||
ts.tv_nsec %= NANOSECONDS_PER_SECOND;
|
||||
}
|
||||
}
|
||||
|
||||
inline void to_time(int milliseconds, timespec& ts)
|
||||
{
|
||||
boost::xtime xt;
|
||||
to_time(milliseconds, xt);
|
||||
to_timespec(xt, ts);
|
||||
}
|
||||
|
||||
inline void to_timespec_duration(const boost::xtime& xt, timespec& ts)
|
||||
{
|
||||
boost::xtime cur;
|
||||
int res = 0;
|
||||
res = boost::xtime_get(&cur, boost::TIME_UTC);
|
||||
assert(res == boost::TIME_UTC);
|
||||
|
||||
if (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 >= NANOSECONDS_PER_SECOND)
|
||||
{
|
||||
ts.tv_sec += ts.tv_nsec / NANOSECONDS_PER_SECOND;
|
||||
ts.tv_nsec %= NANOSECONDS_PER_SECOND;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
inline void to_duration(boost::xtime xt, int& milliseconds)
|
||||
{
|
||||
boost::xtime cur;
|
||||
int res = 0;
|
||||
res = boost::xtime_get(&cur, boost::TIME_UTC);
|
||||
assert(res == boost::TIME_UTC);
|
||||
|
||||
if (boost::xtime_cmp(xt, cur) <= 0)
|
||||
milliseconds = 0;
|
||||
else
|
||||
{
|
||||
if (cur.nsec > xt.nsec)
|
||||
{
|
||||
xt.nsec += NANOSECONDS_PER_SECOND;
|
||||
--xt.sec;
|
||||
}
|
||||
milliseconds = (int)((xt.sec - cur.sec) * MILLISECONDS_PER_SECOND) +
|
||||
(((xt.nsec - cur.nsec) + (NANOSECONDS_PER_MILLISECOND/2)) /
|
||||
NANOSECONDS_PER_MILLISECOND);
|
||||
}
|
||||
}
|
||||
|
||||
inline void to_microduration(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_cmp(xt, cur) <= 0)
|
||||
microseconds = 0;
|
||||
else
|
||||
{
|
||||
if (cur.nsec > xt.nsec)
|
||||
{
|
||||
xt.nsec += NANOSECONDS_PER_SECOND;
|
||||
--xt.sec;
|
||||
}
|
||||
microseconds = (int)((xt.sec - cur.sec) * MICROSECONDS_PER_SECOND) +
|
||||
(((xt.nsec - cur.nsec) + (NANOSECONDS_PER_MICROSECOND/2)) /
|
||||
NANOSECONDS_PER_MICROSECOND);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Change Log:
|
||||
// 1 Jun 01 Initial creation.
|
||||
72
src/win32/tss_dll.cpp
Normal file
72
src/win32/tss_dll.cpp
Normal file
@@ -0,0 +1,72 @@
|
||||
// (C) Copyright Michael Glassford 2004.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_DLL)
|
||||
|
||||
#include <boost/thread/detail/tss_hooks.hpp>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
#if defined(__BORLANDC__)
|
||||
extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE /*hInstance*/, DWORD dwReason, LPVOID /*lpReserved*/)
|
||||
#elif defined(_WIN32_WCE)
|
||||
extern "C" BOOL WINAPI DllMain(HANDLE /*hInstance*/, DWORD dwReason, LPVOID /*lpReserved*/)
|
||||
#else
|
||||
extern "C" BOOL WINAPI DllMain(HINSTANCE /*hInstance*/, DWORD dwReason, LPVOID /*lpReserved*/)
|
||||
#endif
|
||||
{
|
||||
switch(dwReason)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
{
|
||||
on_process_enter();
|
||||
on_thread_enter();
|
||||
break;
|
||||
}
|
||||
|
||||
case DLL_THREAD_ATTACH:
|
||||
{
|
||||
on_thread_enter();
|
||||
break;
|
||||
}
|
||||
|
||||
case DLL_THREAD_DETACH:
|
||||
{
|
||||
on_thread_exit();
|
||||
break;
|
||||
}
|
||||
|
||||
case DLL_PROCESS_DETACH:
|
||||
{
|
||||
on_thread_exit();
|
||||
on_process_exit();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
extern "C" void tss_cleanup_implemented(void)
|
||||
{
|
||||
/*
|
||||
This function's sole purpose is to cause a link error in cases where
|
||||
automatic tss cleanup is not implemented by Boost.Threads as a
|
||||
reminder that user code is responsible for calling the necessary
|
||||
functions at the appropriate times (and for implementing an a
|
||||
tss_cleanup_implemented() function to eliminate the linker's
|
||||
missing symbol error).
|
||||
|
||||
If Boost.Threads later implements automatic tss cleanup in cases
|
||||
where it currently doesn't (which is the plan), the duplicate
|
||||
symbol error will warn the user that their custom solution is no
|
||||
longer needed and can be removed.
|
||||
*/
|
||||
}
|
||||
|
||||
#endif //defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_DLL)
|
||||
287
src/win32/tss_pe.cpp
Normal file
287
src/win32/tss_pe.cpp
Normal file
@@ -0,0 +1,287 @@
|
||||
// $Id$
|
||||
// (C) Copyright Aaron W. LaFramboise, Roland Schwarz, Michael Glassford 2004.
|
||||
// (C) Copyright 2007 Roland Schwarz
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
// (C) Copyright 2007 David Deakins
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_LIB)
|
||||
|
||||
#if defined(__MINGW32__) && !defined(_WIN64)
|
||||
|
||||
#include <boost/thread/detail/tss_hooks.hpp>
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
extern "C" void tss_cleanup_implemented(void) {}
|
||||
|
||||
namespace {
|
||||
void NTAPI on_tls_callback(void* h, DWORD dwReason, PVOID pv)
|
||||
{
|
||||
switch (dwReason)
|
||||
{
|
||||
case DLL_THREAD_DETACH:
|
||||
{
|
||||
on_thread_exit();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void on_after_ctors(void)
|
||||
{
|
||||
on_process_enter();
|
||||
}
|
||||
|
||||
void on_before_dtors(void)
|
||||
{
|
||||
on_thread_exit();
|
||||
}
|
||||
|
||||
void on_after_dtors(void)
|
||||
{
|
||||
on_process_exit();
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
void (* after_ctors )(void) __attribute__((section(".ctors"))) = on_after_ctors;
|
||||
void (* before_dtors)(void) __attribute__((section(".dtors"))) = on_before_dtors;
|
||||
void (* after_dtors )(void) __attribute__((section(".dtors.zzz"))) = on_after_dtors;
|
||||
|
||||
ULONG __tls_index__ = 0;
|
||||
char __tls_end__ __attribute__((section(".tls$zzz"))) = 0;
|
||||
char __tls_start__ __attribute__((section(".tls"))) = 0;
|
||||
|
||||
|
||||
PIMAGE_TLS_CALLBACK __crt_xl_start__ __attribute__ ((section(".CRT$XLA"))) = 0;
|
||||
PIMAGE_TLS_CALLBACK __crt_xl_tls_callback__ __attribute__ ((section(".CRT$XLB"))) = on_tls_callback;
|
||||
PIMAGE_TLS_CALLBACK __crt_xl_end__ __attribute__ ((section(".CRT$XLZ"))) = 0;
|
||||
}
|
||||
|
||||
extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata$T"))) =
|
||||
{
|
||||
(DWORD) &__tls_start__,
|
||||
(DWORD) &__tls_end__,
|
||||
(DWORD) &__tls_index__,
|
||||
(DWORD) (&__crt_xl_start__+1),
|
||||
(DWORD) 0,
|
||||
(DWORD) 0
|
||||
};
|
||||
|
||||
|
||||
#elif defined(_MSC_VER) && !defined(UNDER_CE)
|
||||
|
||||
#include <boost/thread/detail/tss_hooks.hpp>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
//Definitions required by implementation
|
||||
|
||||
#if (_MSC_VER < 1300) // 1300 == VC++ 7.0
|
||||
typedef void (__cdecl *_PVFV)(void);
|
||||
#define INIRETSUCCESS
|
||||
#define PVAPI void
|
||||
#else
|
||||
typedef int (__cdecl *_PVFV)(void);
|
||||
#define INIRETSUCCESS 0
|
||||
#define PVAPI int
|
||||
#endif
|
||||
|
||||
typedef void (NTAPI* _TLSCB)(HINSTANCE, DWORD, PVOID);
|
||||
|
||||
//Symbols for connection to the runtime environment
|
||||
|
||||
extern "C"
|
||||
{
|
||||
extern DWORD _tls_used; //the tls directory (located in .rdata segment)
|
||||
extern _TLSCB __xl_a[], __xl_z[]; //tls initializers */
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
//Forward declarations
|
||||
|
||||
static PVAPI on_tls_prepare(void);
|
||||
static PVAPI on_process_init(void);
|
||||
static PVAPI on_process_term(void);
|
||||
static void NTAPI on_tls_callback(HINSTANCE, DWORD, PVOID);
|
||||
|
||||
//The .CRT$Xxx information is taken from Codeguru:
|
||||
//http://www.codeguru.com/Cpp/misc/misc/threadsprocesses/article.php/c6945__2/
|
||||
|
||||
#if (_MSC_VER >= 1400)
|
||||
#pragma section(".CRT$XIU",long,read)
|
||||
#pragma section(".CRT$XCU",long,read)
|
||||
#pragma section(".CRT$XTU",long,read)
|
||||
#pragma section(".CRT$XLC",long,read)
|
||||
__declspec(allocate(".CRT$XLC")) _TLSCB __xl_ca=on_tls_callback;
|
||||
__declspec(allocate(".CRT$XIU"))_PVFV p_tls_prepare = on_tls_prepare;
|
||||
__declspec(allocate(".CRT$XCU"))_PVFV p_process_init = on_process_init;
|
||||
__declspec(allocate(".CRT$XTU"))_PVFV p_process_term = on_process_term;
|
||||
#else
|
||||
#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0
|
||||
# pragma data_seg(push, old_seg)
|
||||
#endif
|
||||
//Callback to run tls glue code first.
|
||||
//I don't think it is necessary to run it
|
||||
//at .CRT$XIB level, since we are only
|
||||
//interested in thread detachement. But
|
||||
//this could be changed easily if required.
|
||||
|
||||
#pragma data_seg(".CRT$XIU")
|
||||
static _PVFV p_tls_prepare = on_tls_prepare;
|
||||
#pragma data_seg()
|
||||
|
||||
//Callback after all global ctors.
|
||||
|
||||
#pragma data_seg(".CRT$XCU")
|
||||
static _PVFV p_process_init = on_process_init;
|
||||
#pragma data_seg()
|
||||
|
||||
//Callback for tls notifications.
|
||||
|
||||
#pragma data_seg(".CRT$XLB")
|
||||
_TLSCB p_thread_callback = on_tls_callback;
|
||||
#pragma data_seg()
|
||||
//Callback for termination.
|
||||
|
||||
#pragma data_seg(".CRT$XTU")
|
||||
static _PVFV p_process_term = on_process_term;
|
||||
#pragma data_seg()
|
||||
#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0
|
||||
# pragma data_seg(pop, old_seg)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4189)
|
||||
#endif
|
||||
|
||||
PVAPI on_tls_prepare(void)
|
||||
{
|
||||
//The following line has an important side effect:
|
||||
//if the TLS directory is not already there, it will
|
||||
//be created by the linker. In other words, it forces a tls
|
||||
//directory to be generated by the linker even when static tls
|
||||
//(i.e. __declspec(thread)) is not used.
|
||||
//The volatile should prevent the optimizer
|
||||
//from removing the reference.
|
||||
|
||||
DWORD volatile dw = _tls_used;
|
||||
|
||||
#if (_MSC_VER < 1300) // 1300 == VC++ 7.0
|
||||
_TLSCB* pfbegin = __xl_a;
|
||||
_TLSCB* pfend = __xl_z;
|
||||
_TLSCB* pfdst = pfbegin;
|
||||
//pfdst = (_TLSCB*)_tls_used.AddressOfCallBacks;
|
||||
|
||||
//The following loop will merge the address pointers
|
||||
//into a contiguous area, since the tlssup code seems
|
||||
//to require this (at least on MSVC 6)
|
||||
|
||||
while (pfbegin < pfend)
|
||||
{
|
||||
if (*pfbegin != 0)
|
||||
{
|
||||
*pfdst = *pfbegin;
|
||||
++pfdst;
|
||||
}
|
||||
++pfbegin;
|
||||
}
|
||||
|
||||
*pfdst = 0;
|
||||
#endif
|
||||
|
||||
return INIRETSUCCESS;
|
||||
}
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
PVAPI on_process_init(void)
|
||||
{
|
||||
//Schedule on_thread_exit() to be called for the main
|
||||
//thread before destructors of global objects have been
|
||||
//called.
|
||||
|
||||
//It will not be run when 'quick' exiting the
|
||||
//library; however, this is the standard behaviour
|
||||
//for destructors of global objects, so that
|
||||
//shouldn't be a problem.
|
||||
|
||||
atexit(on_thread_exit);
|
||||
|
||||
//Call Boost process entry callback here
|
||||
|
||||
on_process_enter();
|
||||
|
||||
return INIRETSUCCESS;
|
||||
}
|
||||
|
||||
PVAPI on_process_term(void)
|
||||
{
|
||||
on_process_exit();
|
||||
return INIRETSUCCESS;
|
||||
}
|
||||
|
||||
void NTAPI on_tls_callback(HINSTANCE /*h*/, DWORD dwReason, PVOID /*pv*/)
|
||||
{
|
||||
switch (dwReason)
|
||||
{
|
||||
case DLL_THREAD_DETACH:
|
||||
on_thread_exit();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL WINAPI dll_callback(HANDLE, DWORD dwReason, LPVOID)
|
||||
{
|
||||
switch (dwReason)
|
||||
{
|
||||
case DLL_THREAD_DETACH:
|
||||
on_thread_exit();
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
on_process_exit();
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} //namespace
|
||||
|
||||
extern "C"
|
||||
{
|
||||
extern BOOL (WINAPI * const _pRawDllMain)(HANDLE, DWORD, LPVOID)=&dll_callback;
|
||||
}
|
||||
|
||||
extern "C" void tss_cleanup_implemented(void)
|
||||
{
|
||||
/*
|
||||
This function's sole purpose is to cause a link error in cases where
|
||||
automatic tss cleanup is not implemented by Boost.Threads as a
|
||||
reminder that user code is responsible for calling the necessary
|
||||
functions at the appropriate times (and for implementing an a
|
||||
tss_cleanup_implemented() function to eliminate the linker's
|
||||
missing symbol error).
|
||||
|
||||
If Boost.Threads later implements automatic tss cleanup in cases
|
||||
where it currently doesn't (which is the plan), the duplicate
|
||||
symbol error will warn the user that their custom solution is no
|
||||
longer needed and can be removed.
|
||||
*/
|
||||
}
|
||||
#endif //defined(_MSC_VER) && !defined(UNDER_CE)
|
||||
|
||||
#endif //defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_LIB)
|
||||
@@ -1,4 +1,5 @@
|
||||
# (C) Copyright William E. Kempf 2001.
|
||||
# (C) Copyright 2007 Anthony Williams.
|
||||
# Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
#
|
||||
@@ -21,25 +22,40 @@ project
|
||||
: requirements <library>/boost/test//boost_unit_test_framework/<link>static
|
||||
<threading>multi
|
||||
;
|
||||
|
||||
|
||||
rule thread-run ( sources )
|
||||
{
|
||||
return
|
||||
[ run $(sources) ../build//boost_thread ]
|
||||
[ run $(sources) ../src/tss_null.cpp ../build//boost_thread/<link>static
|
||||
: : : : $(sources[1]:B)_lib ]
|
||||
;
|
||||
[ run $(sources) ../build//boost_thread ]
|
||||
[ run $(sources) ../src/tss_null.cpp ../build//boost_thread/<link>static
|
||||
: : : : $(sources[1]:B)_lib ]
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
test-suite "threads"
|
||||
: [ thread-run test_thread.cpp ]
|
||||
[ thread-run test_thread_id.cpp ]
|
||||
[ thread-run test_hardware_concurrency.cpp ]
|
||||
[ thread-run test_thread_move.cpp ]
|
||||
[ thread-run test_thread_launching.cpp ]
|
||||
[ thread-run test_thread_mf.cpp ]
|
||||
[ thread-run test_move_function.cpp ]
|
||||
[ thread-run test_mutex.cpp ]
|
||||
[ thread-run test_condition_notify_one.cpp ]
|
||||
[ thread-run test_condition_timed_wait_times_out.cpp ]
|
||||
[ thread-run test_condition_notify_all.cpp ]
|
||||
[ thread-run test_condition.cpp ]
|
||||
[ thread-run test_tss.cpp ]
|
||||
[ thread-run test_once.cpp ]
|
||||
[ thread-run test_xtime.cpp ]
|
||||
[ thread-run test_barrier.cpp ]
|
||||
# [ thread-run test_read_write_mutex.cpp ]
|
||||
[ thread-run test_barrier.cpp ]
|
||||
[ thread-run test_shared_mutex.cpp ]
|
||||
[ thread-run test_shared_mutex_part_2.cpp ]
|
||||
[ thread-run test_shared_mutex_timed_locks.cpp ]
|
||||
[ thread-run test_lock_concept.cpp ]
|
||||
[ thread-run test_generic_locks.cpp ]
|
||||
[ compile-fail no_implicit_move_from_lvalue_thread.cpp ]
|
||||
[ compile-fail no_implicit_assign_from_lvalue_thread.cpp ]
|
||||
;
|
||||
}
|
||||
|
||||
97
test/condition_test_common.hpp
Normal file
97
test/condition_test_common.hpp
Normal file
@@ -0,0 +1,97 @@
|
||||
#ifndef CONDITION_TEST_COMMON_HPP
|
||||
#define CONDITION_TEST_COMMON_HPP
|
||||
// Copyright (C) 2007 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
|
||||
unsigned const timeout_seconds=5;
|
||||
|
||||
struct wait_for_flag
|
||||
{
|
||||
boost::mutex mutex;
|
||||
boost::condition_variable cond_var;
|
||||
bool flag;
|
||||
unsigned woken;
|
||||
|
||||
wait_for_flag():
|
||||
flag(false),woken(0)
|
||||
{}
|
||||
|
||||
struct check_flag
|
||||
{
|
||||
bool const& flag;
|
||||
|
||||
check_flag(bool const& flag_):
|
||||
flag(flag_)
|
||||
{}
|
||||
|
||||
bool operator()() const
|
||||
{
|
||||
return flag;
|
||||
}
|
||||
private:
|
||||
void operator=(check_flag&);
|
||||
};
|
||||
|
||||
|
||||
void wait_without_predicate()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
while(!flag)
|
||||
{
|
||||
cond_var.wait(lock);
|
||||
}
|
||||
++woken;
|
||||
}
|
||||
|
||||
void wait_with_predicate()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
cond_var.wait(lock,check_flag(flag));
|
||||
if(flag)
|
||||
{
|
||||
++woken;
|
||||
}
|
||||
}
|
||||
|
||||
void timed_wait_without_predicate()
|
||||
{
|
||||
boost::system_time const timeout=boost::get_system_time()+boost::posix_time::seconds(timeout_seconds);
|
||||
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
while(!flag)
|
||||
{
|
||||
if(!cond_var.timed_wait(lock,timeout))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
++woken;
|
||||
}
|
||||
|
||||
void timed_wait_with_predicate()
|
||||
{
|
||||
boost::system_time const timeout=boost::get_system_time()+boost::posix_time::seconds(timeout_seconds);
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
if(cond_var.timed_wait(lock,timeout,check_flag(flag)) && flag)
|
||||
{
|
||||
++woken;
|
||||
}
|
||||
}
|
||||
void relative_timed_wait_with_predicate()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
if(cond_var.timed_wait(lock,boost::posix_time::seconds(timeout_seconds),check_flag(flag)) && flag)
|
||||
{
|
||||
++woken;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
15
test/no_implicit_assign_from_lvalue_thread.cpp
Normal file
15
test/no_implicit_assign_from_lvalue_thread.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
// Copyright (C) 2008 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
void do_nothing()
|
||||
{}
|
||||
|
||||
void test()
|
||||
{
|
||||
boost::thread t1(do_nothing);
|
||||
boost::thread t2;
|
||||
t2=t1;
|
||||
}
|
||||
14
test/no_implicit_move_from_lvalue_thread.cpp
Normal file
14
test/no_implicit_move_from_lvalue_thread.cpp
Normal file
@@ -0,0 +1,14 @@
|
||||
// Copyright (C) 2008 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
void do_nothing()
|
||||
{}
|
||||
|
||||
void test()
|
||||
{
|
||||
boost::thread t1(do_nothing);
|
||||
boost::thread t2(t1);
|
||||
}
|
||||
132
test/shared_mutex_locking_thread.hpp
Normal file
132
test/shared_mutex_locking_thread.hpp
Normal file
@@ -0,0 +1,132 @@
|
||||
#ifndef SHARED_MUTEX_LOCKING_THREAD_HPP
|
||||
#define SHARED_MUTEX_LOCKING_THREAD_HPP
|
||||
|
||||
// (C) Copyright 2008 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/thread/shared_mutex.hpp>
|
||||
|
||||
template<typename lock_type>
|
||||
class locking_thread
|
||||
{
|
||||
boost::shared_mutex& rw_mutex;
|
||||
unsigned& unblocked_count;
|
||||
boost::condition_variable& unblocked_condition;
|
||||
unsigned& simultaneous_running_count;
|
||||
unsigned& max_simultaneous_running;
|
||||
boost::mutex& unblocked_count_mutex;
|
||||
boost::mutex& finish_mutex;
|
||||
public:
|
||||
locking_thread(boost::shared_mutex& rw_mutex_,
|
||||
unsigned& unblocked_count_,
|
||||
boost::mutex& unblocked_count_mutex_,
|
||||
boost::condition_variable& unblocked_condition_,
|
||||
boost::mutex& finish_mutex_,
|
||||
unsigned& simultaneous_running_count_,
|
||||
unsigned& max_simultaneous_running_):
|
||||
rw_mutex(rw_mutex_),
|
||||
unblocked_count(unblocked_count_),
|
||||
unblocked_condition(unblocked_condition_),
|
||||
simultaneous_running_count(simultaneous_running_count_),
|
||||
max_simultaneous_running(max_simultaneous_running_),
|
||||
unblocked_count_mutex(unblocked_count_mutex_),
|
||||
finish_mutex(finish_mutex_)
|
||||
{}
|
||||
|
||||
void operator()()
|
||||
{
|
||||
// acquire lock
|
||||
lock_type lock(rw_mutex);
|
||||
|
||||
// increment count to show we're unblocked
|
||||
{
|
||||
boost::mutex::scoped_lock ublock(unblocked_count_mutex);
|
||||
++unblocked_count;
|
||||
unblocked_condition.notify_one();
|
||||
++simultaneous_running_count;
|
||||
if(simultaneous_running_count>max_simultaneous_running)
|
||||
{
|
||||
max_simultaneous_running=simultaneous_running_count;
|
||||
}
|
||||
}
|
||||
|
||||
// wait to finish
|
||||
boost::mutex::scoped_lock finish_lock(finish_mutex);
|
||||
{
|
||||
boost::mutex::scoped_lock ublock(unblocked_count_mutex);
|
||||
--simultaneous_running_count;
|
||||
}
|
||||
}
|
||||
private:
|
||||
void operator=(locking_thread&);
|
||||
};
|
||||
|
||||
class simple_writing_thread
|
||||
{
|
||||
boost::shared_mutex& rwm;
|
||||
boost::mutex& finish_mutex;
|
||||
boost::mutex& unblocked_mutex;
|
||||
unsigned& unblocked_count;
|
||||
|
||||
void operator=(simple_writing_thread&);
|
||||
|
||||
public:
|
||||
simple_writing_thread(boost::shared_mutex& rwm_,
|
||||
boost::mutex& finish_mutex_,
|
||||
boost::mutex& unblocked_mutex_,
|
||||
unsigned& unblocked_count_):
|
||||
rwm(rwm_),finish_mutex(finish_mutex_),
|
||||
unblocked_mutex(unblocked_mutex_),unblocked_count(unblocked_count_)
|
||||
{}
|
||||
|
||||
void operator()()
|
||||
{
|
||||
boost::unique_lock<boost::shared_mutex> lk(rwm);
|
||||
|
||||
{
|
||||
boost::mutex::scoped_lock ulk(unblocked_mutex);
|
||||
++unblocked_count;
|
||||
}
|
||||
|
||||
boost::mutex::scoped_lock flk(finish_mutex);
|
||||
}
|
||||
};
|
||||
|
||||
class simple_reading_thread
|
||||
{
|
||||
boost::shared_mutex& rwm;
|
||||
boost::mutex& finish_mutex;
|
||||
boost::mutex& unblocked_mutex;
|
||||
unsigned& unblocked_count;
|
||||
|
||||
void operator=(simple_reading_thread&);
|
||||
|
||||
public:
|
||||
simple_reading_thread(boost::shared_mutex& rwm_,
|
||||
boost::mutex& finish_mutex_,
|
||||
boost::mutex& unblocked_mutex_,
|
||||
unsigned& unblocked_count_):
|
||||
rwm(rwm_),finish_mutex(finish_mutex_),
|
||||
unblocked_mutex(unblocked_mutex_),unblocked_count(unblocked_count_)
|
||||
{}
|
||||
|
||||
void operator()()
|
||||
{
|
||||
boost::shared_lock<boost::shared_mutex> lk(rwm);
|
||||
|
||||
{
|
||||
boost::mutex::scoped_lock ulk(unblocked_mutex);
|
||||
++unblocked_count;
|
||||
}
|
||||
|
||||
boost::mutex::scoped_lock flk(finish_mutex);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <boost/thread/barrier.hpp>
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -38,12 +39,20 @@ void test_barrier()
|
||||
boost::thread_group g;
|
||||
global_parameter = 0;
|
||||
|
||||
for (int i = 0; i < N_THREADS; ++i)
|
||||
g.create_thread(&barrier_thread);
|
||||
|
||||
g.join_all();
|
||||
|
||||
BOOST_CHECK(global_parameter == 5);
|
||||
try
|
||||
{
|
||||
for (int i = 0; i < N_THREADS; ++i)
|
||||
g.create_thread(&barrier_thread);
|
||||
g.join_all();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
g.interrupt_all();
|
||||
g.join_all();
|
||||
throw;
|
||||
}
|
||||
|
||||
BOOST_CHECK_EQUAL(global_parameter,5);
|
||||
}
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
// Copyright (C) 2007 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -19,7 +20,7 @@ struct condition_test_data
|
||||
condition_test_data() : notified(0), awoken(0) { }
|
||||
|
||||
boost::mutex mutex;
|
||||
boost::condition condition;
|
||||
boost::condition_variable condition;
|
||||
int notified;
|
||||
int awoken;
|
||||
};
|
||||
@@ -42,6 +43,9 @@ struct cond_predicate
|
||||
|
||||
int& _var;
|
||||
int _val;
|
||||
private:
|
||||
void operator=(cond_predicate&);
|
||||
|
||||
};
|
||||
|
||||
void condition_test_waits(condition_test_data* data)
|
||||
@@ -82,56 +86,15 @@ void condition_test_waits(condition_test_data* data)
|
||||
BOOST_CHECK_EQUAL(data->notified, 4);
|
||||
data->awoken++;
|
||||
data->condition.notify_one();
|
||||
}
|
||||
|
||||
void do_test_condition_notify_one()
|
||||
{
|
||||
condition_test_data data;
|
||||
|
||||
boost::thread thread(bind(&condition_test_thread, &data));
|
||||
|
||||
{
|
||||
boost::mutex::scoped_lock lock(data.mutex);
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
data.notified++;
|
||||
data.condition.notify_one();
|
||||
}
|
||||
|
||||
thread.join();
|
||||
BOOST_CHECK_EQUAL(data.awoken, 1);
|
||||
}
|
||||
|
||||
void test_condition_notify_one()
|
||||
{
|
||||
timed_test(&do_test_condition_notify_one, 2, execution_monitor::use_mutex);
|
||||
}
|
||||
|
||||
void do_test_condition_notify_all()
|
||||
{
|
||||
const int NUMTHREADS = 5;
|
||||
boost::thread_group threads;
|
||||
condition_test_data data;
|
||||
|
||||
for (int i = 0; i < NUMTHREADS; ++i)
|
||||
threads.create_thread(bind(&condition_test_thread, &data));
|
||||
|
||||
{
|
||||
boost::mutex::scoped_lock lock(data.mutex);
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
data.notified++;
|
||||
data.condition.notify_all();
|
||||
}
|
||||
|
||||
threads.join_all();
|
||||
BOOST_CHECK_EQUAL(data.awoken, NUMTHREADS);
|
||||
}
|
||||
|
||||
void test_condition_notify_all()
|
||||
{
|
||||
// We should have already tested notify_one here, so
|
||||
// a timed test with the default execution_monitor::use_condition
|
||||
// should be OK, and gives the fastest performance
|
||||
timed_test(&do_test_condition_notify_all, 3);
|
||||
// Test predicate timed_wait with relative timeout
|
||||
cond_predicate pred_rel(data->notified, 5);
|
||||
BOOST_CHECK(data->condition.timed_wait(lock, boost::posix_time::seconds(10), pred_rel));
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
BOOST_CHECK(pred_rel());
|
||||
BOOST_CHECK_EQUAL(data->notified, 5);
|
||||
data->awoken++;
|
||||
data->condition.notify_one();
|
||||
}
|
||||
|
||||
void do_test_condition_waits()
|
||||
@@ -175,10 +138,19 @@ void do_test_condition_waits()
|
||||
data.condition.wait(lock);
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
BOOST_CHECK_EQUAL(data.awoken, 4);
|
||||
|
||||
|
||||
boost::thread::sleep(delay(1));
|
||||
data.notified++;
|
||||
data.condition.notify_one();
|
||||
while (data.awoken != 5)
|
||||
data.condition.wait(lock);
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
BOOST_CHECK_EQUAL(data.awoken, 5);
|
||||
}
|
||||
|
||||
thread.join();
|
||||
BOOST_CHECK_EQUAL(data.awoken, 4);
|
||||
BOOST_CHECK_EQUAL(data.awoken, 5);
|
||||
}
|
||||
|
||||
void test_condition_waits()
|
||||
@@ -189,14 +161,30 @@ void test_condition_waits()
|
||||
timed_test(&do_test_condition_waits, 12);
|
||||
}
|
||||
|
||||
void do_test_condition_wait_is_a_interruption_point()
|
||||
{
|
||||
condition_test_data data;
|
||||
|
||||
boost::thread thread(bind(&condition_test_thread, &data));
|
||||
|
||||
thread.interrupt();
|
||||
thread.join();
|
||||
BOOST_CHECK_EQUAL(data.awoken,0);
|
||||
}
|
||||
|
||||
|
||||
void test_condition_wait_is_a_interruption_point()
|
||||
{
|
||||
timed_test(&do_test_condition_wait_is_a_interruption_point, 1);
|
||||
}
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: condition test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(&test_condition_notify_one));
|
||||
test->add(BOOST_TEST_CASE(&test_condition_notify_all));
|
||||
test->add(BOOST_TEST_CASE(&test_condition_waits));
|
||||
test->add(BOOST_TEST_CASE(&test_condition_wait_is_a_interruption_point));
|
||||
|
||||
return test;
|
||||
}
|
||||
|
||||
222
test/test_condition_notify_all.cpp
Normal file
222
test/test_condition_notify_all.cpp
Normal file
@@ -0,0 +1,222 @@
|
||||
// Copyright (C) 2007 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include <libs/thread/test/util.inl>
|
||||
#include "condition_test_common.hpp"
|
||||
|
||||
unsigned const number_of_test_threads=5;
|
||||
|
||||
void do_test_condition_notify_all_wakes_from_wait()
|
||||
{
|
||||
wait_for_flag data;
|
||||
|
||||
boost::thread_group group;
|
||||
|
||||
try
|
||||
{
|
||||
for(unsigned i=0;i<number_of_test_threads;++i)
|
||||
{
|
||||
group.create_thread(bind(&wait_for_flag::wait_without_predicate, data));
|
||||
}
|
||||
|
||||
{
|
||||
boost::mutex::scoped_lock lock(data.mutex);
|
||||
data.flag=true;
|
||||
data.cond_var.notify_all();
|
||||
}
|
||||
|
||||
group.join_all();
|
||||
BOOST_CHECK_EQUAL(data.woken,number_of_test_threads);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
group.join_all();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
void do_test_condition_notify_all_wakes_from_wait_with_predicate()
|
||||
{
|
||||
wait_for_flag data;
|
||||
|
||||
boost::thread_group group;
|
||||
|
||||
try
|
||||
{
|
||||
for(unsigned i=0;i<number_of_test_threads;++i)
|
||||
{
|
||||
group.create_thread(bind(&wait_for_flag::wait_with_predicate, data));
|
||||
}
|
||||
|
||||
{
|
||||
boost::mutex::scoped_lock lock(data.mutex);
|
||||
data.flag=true;
|
||||
data.cond_var.notify_all();
|
||||
}
|
||||
|
||||
group.join_all();
|
||||
BOOST_CHECK_EQUAL(data.woken,number_of_test_threads);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
group.join_all();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
void do_test_condition_notify_all_wakes_from_timed_wait()
|
||||
{
|
||||
wait_for_flag data;
|
||||
|
||||
boost::thread_group group;
|
||||
|
||||
try
|
||||
{
|
||||
for(unsigned i=0;i<number_of_test_threads;++i)
|
||||
{
|
||||
group.create_thread(bind(&wait_for_flag::timed_wait_without_predicate, data));
|
||||
}
|
||||
|
||||
{
|
||||
boost::mutex::scoped_lock lock(data.mutex);
|
||||
data.flag=true;
|
||||
data.cond_var.notify_all();
|
||||
}
|
||||
|
||||
group.join_all();
|
||||
BOOST_CHECK_EQUAL(data.woken,number_of_test_threads);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
group.join_all();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
void do_test_condition_notify_all_wakes_from_timed_wait_with_predicate()
|
||||
{
|
||||
wait_for_flag data;
|
||||
|
||||
boost::thread_group group;
|
||||
|
||||
try
|
||||
{
|
||||
for(unsigned i=0;i<number_of_test_threads;++i)
|
||||
{
|
||||
group.create_thread(bind(&wait_for_flag::timed_wait_with_predicate, data));
|
||||
}
|
||||
|
||||
{
|
||||
boost::mutex::scoped_lock lock(data.mutex);
|
||||
data.flag=true;
|
||||
data.cond_var.notify_all();
|
||||
}
|
||||
|
||||
group.join_all();
|
||||
BOOST_CHECK_EQUAL(data.woken,number_of_test_threads);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
group.join_all();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
void do_test_condition_notify_all_wakes_from_relative_timed_wait_with_predicate()
|
||||
{
|
||||
wait_for_flag data;
|
||||
|
||||
boost::thread_group group;
|
||||
|
||||
try
|
||||
{
|
||||
for(unsigned i=0;i<number_of_test_threads;++i)
|
||||
{
|
||||
group.create_thread(bind(&wait_for_flag::relative_timed_wait_with_predicate, data));
|
||||
}
|
||||
|
||||
{
|
||||
boost::mutex::scoped_lock lock(data.mutex);
|
||||
data.flag=true;
|
||||
data.cond_var.notify_all();
|
||||
}
|
||||
|
||||
group.join_all();
|
||||
BOOST_CHECK_EQUAL(data.woken,number_of_test_threads);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
group.join_all();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
boost::mutex multiple_wake_mutex;
|
||||
boost::condition_variable multiple_wake_cond;
|
||||
unsigned multiple_wake_count=0;
|
||||
|
||||
void wait_for_condvar_and_increase_count()
|
||||
{
|
||||
boost::mutex::scoped_lock lk(multiple_wake_mutex);
|
||||
multiple_wake_cond.wait(lk);
|
||||
++multiple_wake_count;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void do_test_notify_all_following_notify_one_wakes_all_threads()
|
||||
{
|
||||
boost::thread thread1(wait_for_condvar_and_increase_count);
|
||||
boost::thread thread2(wait_for_condvar_and_increase_count);
|
||||
|
||||
boost::this_thread::sleep(boost::posix_time::milliseconds(200));
|
||||
multiple_wake_cond.notify_one();
|
||||
|
||||
boost::thread thread3(wait_for_condvar_and_increase_count);
|
||||
|
||||
boost::this_thread::sleep(boost::posix_time::milliseconds(200));
|
||||
multiple_wake_cond.notify_one();
|
||||
multiple_wake_cond.notify_all();
|
||||
boost::this_thread::sleep(boost::posix_time::milliseconds(200));
|
||||
|
||||
{
|
||||
boost::mutex::scoped_lock lk(multiple_wake_mutex);
|
||||
BOOST_CHECK(multiple_wake_count==3);
|
||||
}
|
||||
|
||||
thread1.join();
|
||||
thread2.join();
|
||||
thread3.join();
|
||||
}
|
||||
|
||||
void test_condition_notify_all()
|
||||
{
|
||||
timed_test(&do_test_condition_notify_all_wakes_from_wait, timeout_seconds);
|
||||
timed_test(&do_test_condition_notify_all_wakes_from_wait_with_predicate, timeout_seconds);
|
||||
timed_test(&do_test_condition_notify_all_wakes_from_timed_wait, timeout_seconds);
|
||||
timed_test(&do_test_condition_notify_all_wakes_from_timed_wait_with_predicate, timeout_seconds);
|
||||
timed_test(&do_test_condition_notify_all_wakes_from_relative_timed_wait_with_predicate, timeout_seconds);
|
||||
timed_test(&do_test_notify_all_following_notify_one_wakes_all_threads, timeout_seconds);
|
||||
}
|
||||
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: condition test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(&test_condition_notify_all));
|
||||
|
||||
return test;
|
||||
}
|
||||
155
test/test_condition_notify_one.cpp
Normal file
155
test/test_condition_notify_one.cpp
Normal file
@@ -0,0 +1,155 @@
|
||||
// Copyright (C) 2007 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include <libs/thread/test/util.inl>
|
||||
#include "condition_test_common.hpp"
|
||||
|
||||
void do_test_condition_notify_one_wakes_from_wait()
|
||||
{
|
||||
wait_for_flag data;
|
||||
|
||||
boost::thread thread(bind(&wait_for_flag::wait_without_predicate, data));
|
||||
|
||||
{
|
||||
boost::mutex::scoped_lock lock(data.mutex);
|
||||
data.flag=true;
|
||||
data.cond_var.notify_one();
|
||||
}
|
||||
|
||||
thread.join();
|
||||
BOOST_CHECK(data.woken);
|
||||
}
|
||||
|
||||
void do_test_condition_notify_one_wakes_from_wait_with_predicate()
|
||||
{
|
||||
wait_for_flag data;
|
||||
|
||||
boost::thread thread(bind(&wait_for_flag::wait_with_predicate, data));
|
||||
|
||||
{
|
||||
boost::mutex::scoped_lock lock(data.mutex);
|
||||
data.flag=true;
|
||||
data.cond_var.notify_one();
|
||||
}
|
||||
|
||||
thread.join();
|
||||
BOOST_CHECK(data.woken);
|
||||
}
|
||||
|
||||
void do_test_condition_notify_one_wakes_from_timed_wait()
|
||||
{
|
||||
wait_for_flag data;
|
||||
|
||||
boost::thread thread(bind(&wait_for_flag::timed_wait_without_predicate, data));
|
||||
|
||||
{
|
||||
boost::mutex::scoped_lock lock(data.mutex);
|
||||
data.flag=true;
|
||||
data.cond_var.notify_one();
|
||||
}
|
||||
|
||||
thread.join();
|
||||
BOOST_CHECK(data.woken);
|
||||
}
|
||||
|
||||
void do_test_condition_notify_one_wakes_from_timed_wait_with_predicate()
|
||||
{
|
||||
wait_for_flag data;
|
||||
|
||||
boost::thread thread(bind(&wait_for_flag::timed_wait_with_predicate, data));
|
||||
|
||||
{
|
||||
boost::mutex::scoped_lock lock(data.mutex);
|
||||
data.flag=true;
|
||||
data.cond_var.notify_one();
|
||||
}
|
||||
|
||||
thread.join();
|
||||
BOOST_CHECK(data.woken);
|
||||
}
|
||||
|
||||
void do_test_condition_notify_one_wakes_from_relative_timed_wait_with_predicate()
|
||||
{
|
||||
wait_for_flag data;
|
||||
|
||||
boost::thread thread(bind(&wait_for_flag::relative_timed_wait_with_predicate, data));
|
||||
|
||||
{
|
||||
boost::mutex::scoped_lock lock(data.mutex);
|
||||
data.flag=true;
|
||||
data.cond_var.notify_one();
|
||||
}
|
||||
|
||||
thread.join();
|
||||
BOOST_CHECK(data.woken);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
boost::mutex multiple_wake_mutex;
|
||||
boost::condition_variable multiple_wake_cond;
|
||||
unsigned multiple_wake_count=0;
|
||||
|
||||
void wait_for_condvar_and_increase_count()
|
||||
{
|
||||
boost::mutex::scoped_lock lk(multiple_wake_mutex);
|
||||
multiple_wake_cond.wait(lk);
|
||||
++multiple_wake_count;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void do_test_multiple_notify_one_calls_wakes_multiple_threads()
|
||||
{
|
||||
boost::thread thread1(wait_for_condvar_and_increase_count);
|
||||
boost::thread thread2(wait_for_condvar_and_increase_count);
|
||||
|
||||
boost::this_thread::sleep(boost::posix_time::milliseconds(200));
|
||||
multiple_wake_cond.notify_one();
|
||||
|
||||
boost::thread thread3(wait_for_condvar_and_increase_count);
|
||||
|
||||
boost::this_thread::sleep(boost::posix_time::milliseconds(200));
|
||||
multiple_wake_cond.notify_one();
|
||||
multiple_wake_cond.notify_one();
|
||||
boost::this_thread::sleep(boost::posix_time::milliseconds(200));
|
||||
|
||||
{
|
||||
boost::mutex::scoped_lock lk(multiple_wake_mutex);
|
||||
BOOST_CHECK(multiple_wake_count==3);
|
||||
}
|
||||
|
||||
thread1.join();
|
||||
thread2.join();
|
||||
thread3.join();
|
||||
}
|
||||
|
||||
void test_condition_notify_one()
|
||||
{
|
||||
timed_test(&do_test_condition_notify_one_wakes_from_wait, timeout_seconds, execution_monitor::use_mutex);
|
||||
timed_test(&do_test_condition_notify_one_wakes_from_wait_with_predicate, timeout_seconds, execution_monitor::use_mutex);
|
||||
timed_test(&do_test_condition_notify_one_wakes_from_timed_wait, timeout_seconds, execution_monitor::use_mutex);
|
||||
timed_test(&do_test_condition_notify_one_wakes_from_timed_wait_with_predicate, timeout_seconds, execution_monitor::use_mutex);
|
||||
timed_test(&do_test_condition_notify_one_wakes_from_relative_timed_wait_with_predicate, timeout_seconds, execution_monitor::use_mutex);
|
||||
timed_test(&do_test_multiple_notify_one_calls_wakes_multiple_threads, timeout_seconds, execution_monitor::use_mutex);
|
||||
}
|
||||
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: condition test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(&test_condition_notify_one));
|
||||
|
||||
return test;
|
||||
}
|
||||
173
test/test_condition_timed_wait_times_out.cpp
Normal file
173
test/test_condition_timed_wait_times_out.cpp
Normal file
@@ -0,0 +1,173 @@
|
||||
// Copyright (C) 2007-8 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/thread/condition.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include "util.inl"
|
||||
|
||||
bool fake_predicate()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned const timeout_seconds=2;
|
||||
unsigned const timeout_grace=1;
|
||||
boost::posix_time::milliseconds const timeout_resolution(100);
|
||||
|
||||
|
||||
void do_test_timed_wait_times_out()
|
||||
{
|
||||
boost::condition_variable cond;
|
||||
boost::mutex m;
|
||||
|
||||
boost::posix_time::seconds const delay(timeout_seconds);
|
||||
boost::mutex::scoped_lock lock(m);
|
||||
boost::system_time const start=boost::get_system_time();
|
||||
boost::system_time const timeout=start+delay;
|
||||
|
||||
while(cond.timed_wait(lock,timeout));
|
||||
|
||||
boost::system_time const end=boost::get_system_time();
|
||||
BOOST_CHECK((delay-timeout_resolution)<=(end-start));
|
||||
}
|
||||
|
||||
void do_test_timed_wait_with_predicate_times_out()
|
||||
{
|
||||
boost::condition_variable cond;
|
||||
boost::mutex m;
|
||||
|
||||
boost::posix_time::seconds const delay(timeout_seconds);
|
||||
boost::mutex::scoped_lock lock(m);
|
||||
boost::system_time const start=boost::get_system_time();
|
||||
boost::system_time const timeout=start+delay;
|
||||
|
||||
bool const res=cond.timed_wait(lock,timeout,fake_predicate);
|
||||
|
||||
boost::system_time const end=boost::get_system_time();
|
||||
BOOST_CHECK(!res);
|
||||
BOOST_CHECK((delay-timeout_resolution)<=(end-start));
|
||||
}
|
||||
|
||||
void do_test_relative_timed_wait_with_predicate_times_out()
|
||||
{
|
||||
boost::condition_variable cond;
|
||||
boost::mutex m;
|
||||
|
||||
boost::posix_time::seconds const delay(timeout_seconds);
|
||||
boost::mutex::scoped_lock lock(m);
|
||||
boost::system_time const start=boost::get_system_time();
|
||||
|
||||
bool const res=cond.timed_wait(lock,delay,fake_predicate);
|
||||
|
||||
boost::system_time const end=boost::get_system_time();
|
||||
BOOST_CHECK(!res);
|
||||
BOOST_CHECK((delay-timeout_resolution)<=(end-start));
|
||||
}
|
||||
|
||||
void do_test_timed_wait_relative_times_out()
|
||||
{
|
||||
boost::condition_variable cond;
|
||||
boost::mutex m;
|
||||
|
||||
boost::posix_time::seconds const delay(timeout_seconds);
|
||||
boost::mutex::scoped_lock lock(m);
|
||||
boost::system_time const start=boost::get_system_time();
|
||||
|
||||
while(cond.timed_wait(lock,delay));
|
||||
|
||||
boost::system_time const end=boost::get_system_time();
|
||||
BOOST_CHECK((delay-timeout_resolution)<=(end-start));
|
||||
}
|
||||
|
||||
void do_test_cv_any_timed_wait_times_out()
|
||||
{
|
||||
boost::condition_variable_any cond;
|
||||
boost::mutex m;
|
||||
|
||||
boost::posix_time::seconds const delay(timeout_seconds);
|
||||
boost::mutex::scoped_lock lock(m);
|
||||
boost::system_time const start=boost::get_system_time();
|
||||
boost::system_time const timeout=start+delay;
|
||||
|
||||
while(cond.timed_wait(lock,timeout));
|
||||
|
||||
boost::system_time const end=boost::get_system_time();
|
||||
BOOST_CHECK((delay-timeout_resolution)<=(end-start));
|
||||
}
|
||||
|
||||
void do_test_cv_any_timed_wait_with_predicate_times_out()
|
||||
{
|
||||
boost::condition_variable_any cond;
|
||||
boost::mutex m;
|
||||
|
||||
boost::posix_time::seconds const delay(timeout_seconds);
|
||||
boost::mutex::scoped_lock lock(m);
|
||||
boost::system_time const start=boost::get_system_time();
|
||||
boost::system_time const timeout=start+delay;
|
||||
|
||||
bool const res=cond.timed_wait(lock,timeout,fake_predicate);
|
||||
|
||||
boost::system_time const end=boost::get_system_time();
|
||||
BOOST_CHECK(!res);
|
||||
BOOST_CHECK((delay-timeout_resolution)<=(end-start));
|
||||
}
|
||||
|
||||
void do_test_cv_any_relative_timed_wait_with_predicate_times_out()
|
||||
{
|
||||
boost::condition_variable_any cond;
|
||||
boost::mutex m;
|
||||
|
||||
boost::posix_time::seconds const delay(timeout_seconds);
|
||||
boost::mutex::scoped_lock lock(m);
|
||||
boost::system_time const start=boost::get_system_time();
|
||||
|
||||
bool const res=cond.timed_wait(lock,delay,fake_predicate);
|
||||
|
||||
boost::system_time const end=boost::get_system_time();
|
||||
BOOST_CHECK(!res);
|
||||
BOOST_CHECK((delay-timeout_resolution)<=(end-start));
|
||||
}
|
||||
|
||||
void do_test_cv_any_timed_wait_relative_times_out()
|
||||
{
|
||||
boost::condition_variable_any cond;
|
||||
boost::mutex m;
|
||||
|
||||
boost::posix_time::seconds const delay(timeout_seconds);
|
||||
boost::mutex::scoped_lock lock(m);
|
||||
boost::system_time const start=boost::get_system_time();
|
||||
|
||||
while(cond.timed_wait(lock,delay));
|
||||
|
||||
boost::system_time const end=boost::get_system_time();
|
||||
BOOST_CHECK((delay-timeout_resolution)<=(end-start));
|
||||
}
|
||||
|
||||
|
||||
void test_timed_wait_times_out()
|
||||
{
|
||||
timed_test(&do_test_timed_wait_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
|
||||
timed_test(&do_test_timed_wait_with_predicate_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
|
||||
timed_test(&do_test_relative_timed_wait_with_predicate_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
|
||||
timed_test(&do_test_timed_wait_relative_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
|
||||
timed_test(&do_test_cv_any_timed_wait_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
|
||||
timed_test(&do_test_cv_any_timed_wait_with_predicate_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
|
||||
timed_test(&do_test_cv_any_relative_timed_wait_with_predicate_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
|
||||
timed_test(&do_test_cv_any_timed_wait_relative_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
|
||||
}
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: condition test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(&test_timed_wait_times_out));
|
||||
|
||||
return test;
|
||||
}
|
||||
523
test/test_generic_locks.cpp
Normal file
523
test/test_generic_locks.cpp
Normal file
@@ -0,0 +1,523 @@
|
||||
// (C) Copyright 2008 Anthony Williams
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
|
||||
void test_lock_two_uncontended()
|
||||
{
|
||||
boost::mutex m1,m2;
|
||||
|
||||
boost::mutex::scoped_lock l1(m1,boost::defer_lock),
|
||||
l2(m2,boost::defer_lock);
|
||||
|
||||
BOOST_CHECK(!l1.owns_lock());
|
||||
BOOST_CHECK(!l2.owns_lock());
|
||||
|
||||
boost::lock(l1,l2);
|
||||
|
||||
BOOST_CHECK(l1.owns_lock());
|
||||
BOOST_CHECK(l2.owns_lock());
|
||||
}
|
||||
|
||||
struct wait_data
|
||||
{
|
||||
boost::mutex m;
|
||||
bool flag;
|
||||
boost::condition_variable cond;
|
||||
|
||||
wait_data():
|
||||
flag(false)
|
||||
{}
|
||||
|
||||
void wait()
|
||||
{
|
||||
boost::mutex::scoped_lock l(m);
|
||||
while(!flag)
|
||||
{
|
||||
cond.wait(l);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Duration>
|
||||
bool timed_wait(Duration d)
|
||||
{
|
||||
boost::system_time const target=boost::get_system_time()+d;
|
||||
|
||||
boost::mutex::scoped_lock l(m);
|
||||
while(!flag)
|
||||
{
|
||||
if(!cond.timed_wait(l,target))
|
||||
{
|
||||
return flag;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void signal()
|
||||
{
|
||||
boost::mutex::scoped_lock l(m);
|
||||
flag=true;
|
||||
cond.notify_all();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void lock_mutexes_slowly(boost::mutex* m1,boost::mutex* m2,wait_data* locked,wait_data* quit)
|
||||
{
|
||||
boost::lock_guard<boost::mutex> l1(*m1);
|
||||
boost::this_thread::sleep(boost::posix_time::milliseconds(500));
|
||||
boost::lock_guard<boost::mutex> l2(*m2);
|
||||
locked->signal();
|
||||
quit->wait();
|
||||
}
|
||||
|
||||
void lock_pair(boost::mutex* m1,boost::mutex* m2)
|
||||
{
|
||||
boost::lock(*m1,*m2);
|
||||
boost::mutex::scoped_lock l1(*m1,boost::adopt_lock),
|
||||
l2(*m2,boost::adopt_lock);
|
||||
}
|
||||
|
||||
void test_lock_two_other_thread_locks_in_order()
|
||||
{
|
||||
boost::mutex m1,m2;
|
||||
wait_data locked;
|
||||
wait_data release;
|
||||
|
||||
boost::thread t(lock_mutexes_slowly,&m1,&m2,&locked,&release);
|
||||
boost::this_thread::sleep(boost::posix_time::milliseconds(10));
|
||||
|
||||
boost::thread t2(lock_pair,&m1,&m2);
|
||||
BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(1)));
|
||||
|
||||
release.signal();
|
||||
|
||||
BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(1)));
|
||||
|
||||
t.join();
|
||||
}
|
||||
|
||||
void test_lock_two_other_thread_locks_in_opposite_order()
|
||||
{
|
||||
boost::mutex m1,m2;
|
||||
wait_data locked;
|
||||
wait_data release;
|
||||
|
||||
boost::thread t(lock_mutexes_slowly,&m1,&m2,&locked,&release);
|
||||
boost::this_thread::sleep(boost::posix_time::milliseconds(10));
|
||||
|
||||
boost::thread t2(lock_pair,&m2,&m1);
|
||||
BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(1)));
|
||||
|
||||
release.signal();
|
||||
|
||||
BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(1)));
|
||||
|
||||
t.join();
|
||||
}
|
||||
|
||||
void test_lock_five_uncontended()
|
||||
{
|
||||
boost::mutex m1,m2,m3,m4,m5;
|
||||
|
||||
boost::mutex::scoped_lock l1(m1,boost::defer_lock),
|
||||
l2(m2,boost::defer_lock),
|
||||
l3(m3,boost::defer_lock),
|
||||
l4(m4,boost::defer_lock),
|
||||
l5(m5,boost::defer_lock);
|
||||
|
||||
BOOST_CHECK(!l1.owns_lock());
|
||||
BOOST_CHECK(!l2.owns_lock());
|
||||
BOOST_CHECK(!l3.owns_lock());
|
||||
BOOST_CHECK(!l4.owns_lock());
|
||||
BOOST_CHECK(!l5.owns_lock());
|
||||
|
||||
boost::lock(l1,l2,l3,l4,l5);
|
||||
|
||||
BOOST_CHECK(l1.owns_lock());
|
||||
BOOST_CHECK(l2.owns_lock());
|
||||
BOOST_CHECK(l3.owns_lock());
|
||||
BOOST_CHECK(l4.owns_lock());
|
||||
BOOST_CHECK(l5.owns_lock());
|
||||
}
|
||||
|
||||
void lock_five_mutexes_slowly(boost::mutex* m1,boost::mutex* m2,boost::mutex* m3,boost::mutex* m4,boost::mutex* m5,
|
||||
wait_data* locked,wait_data* quit)
|
||||
{
|
||||
boost::lock_guard<boost::mutex> l1(*m1);
|
||||
boost::this_thread::sleep(boost::posix_time::milliseconds(500));
|
||||
boost::lock_guard<boost::mutex> l2(*m2);
|
||||
boost::this_thread::sleep(boost::posix_time::milliseconds(500));
|
||||
boost::lock_guard<boost::mutex> l3(*m3);
|
||||
boost::this_thread::sleep(boost::posix_time::milliseconds(500));
|
||||
boost::lock_guard<boost::mutex> l4(*m4);
|
||||
boost::this_thread::sleep(boost::posix_time::milliseconds(500));
|
||||
boost::lock_guard<boost::mutex> l5(*m5);
|
||||
locked->signal();
|
||||
quit->wait();
|
||||
}
|
||||
|
||||
void lock_five(boost::mutex* m1,boost::mutex* m2,boost::mutex* m3,boost::mutex* m4,boost::mutex* m5)
|
||||
{
|
||||
boost::lock(*m1,*m2,*m3,*m4,*m5);
|
||||
m1->unlock();
|
||||
m2->unlock();
|
||||
m3->unlock();
|
||||
m4->unlock();
|
||||
m5->unlock();
|
||||
}
|
||||
|
||||
void test_lock_five_other_thread_locks_in_order()
|
||||
{
|
||||
boost::mutex m1,m2,m3,m4,m5;
|
||||
wait_data locked;
|
||||
wait_data release;
|
||||
|
||||
boost::thread t(lock_five_mutexes_slowly,&m1,&m2,&m3,&m4,&m5,&locked,&release);
|
||||
boost::this_thread::sleep(boost::posix_time::milliseconds(10));
|
||||
|
||||
boost::thread t2(lock_five,&m1,&m2,&m3,&m4,&m5);
|
||||
BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(3)));
|
||||
|
||||
release.signal();
|
||||
|
||||
BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(3)));
|
||||
|
||||
t.join();
|
||||
}
|
||||
|
||||
void test_lock_five_other_thread_locks_in_different_order()
|
||||
{
|
||||
boost::mutex m1,m2,m3,m4,m5;
|
||||
wait_data locked;
|
||||
wait_data release;
|
||||
|
||||
boost::thread t(lock_five_mutexes_slowly,&m1,&m2,&m3,&m4,&m5,&locked,&release);
|
||||
boost::this_thread::sleep(boost::posix_time::milliseconds(10));
|
||||
|
||||
boost::thread t2(lock_five,&m5,&m1,&m4,&m2,&m3);
|
||||
BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(3)));
|
||||
|
||||
release.signal();
|
||||
|
||||
BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(3)));
|
||||
|
||||
t.join();
|
||||
}
|
||||
|
||||
void lock_n(boost::mutex* mutexes,unsigned count)
|
||||
{
|
||||
boost::lock(mutexes,mutexes+count);
|
||||
for(unsigned i=0;i<count;++i)
|
||||
{
|
||||
mutexes[i].unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void test_lock_ten_other_thread_locks_in_different_order()
|
||||
{
|
||||
unsigned const num_mutexes=10;
|
||||
|
||||
boost::mutex mutexes[num_mutexes];
|
||||
wait_data locked;
|
||||
wait_data release;
|
||||
|
||||
boost::thread t(lock_five_mutexes_slowly,&mutexes[6],&mutexes[3],&mutexes[8],&mutexes[0],&mutexes[2],&locked,&release);
|
||||
boost::this_thread::sleep(boost::posix_time::milliseconds(10));
|
||||
|
||||
boost::thread t2(lock_n,mutexes,num_mutexes);
|
||||
BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(3)));
|
||||
|
||||
release.signal();
|
||||
|
||||
BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(3)));
|
||||
|
||||
t.join();
|
||||
}
|
||||
|
||||
struct dummy_mutex
|
||||
{
|
||||
bool is_locked;
|
||||
|
||||
dummy_mutex():
|
||||
is_locked(false)
|
||||
{}
|
||||
|
||||
void lock()
|
||||
{
|
||||
is_locked=true;
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
if(is_locked)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
is_locked=true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
is_locked=false;
|
||||
}
|
||||
};
|
||||
|
||||
namespace boost
|
||||
{
|
||||
template<>
|
||||
struct is_mutex_type<dummy_mutex>
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value = true);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
void test_lock_five_in_range()
|
||||
{
|
||||
unsigned const num_mutexes=5;
|
||||
dummy_mutex mutexes[num_mutexes];
|
||||
|
||||
boost::lock(mutexes,mutexes+num_mutexes);
|
||||
|
||||
for(unsigned i=0;i<num_mutexes;++i)
|
||||
{
|
||||
BOOST_CHECK(mutexes[i].is_locked);
|
||||
}
|
||||
}
|
||||
|
||||
void test_lock_ten_in_range()
|
||||
{
|
||||
unsigned const num_mutexes=10;
|
||||
dummy_mutex mutexes[num_mutexes];
|
||||
|
||||
boost::lock(mutexes,mutexes+num_mutexes);
|
||||
|
||||
for(unsigned i=0;i<num_mutexes;++i)
|
||||
{
|
||||
BOOST_CHECK(mutexes[i].is_locked);
|
||||
}
|
||||
}
|
||||
|
||||
void test_try_lock_two_uncontended()
|
||||
{
|
||||
dummy_mutex m1,m2;
|
||||
|
||||
int const res=boost::try_lock(m1,m2);
|
||||
|
||||
BOOST_CHECK(res==-1);
|
||||
BOOST_CHECK(m1.is_locked);
|
||||
BOOST_CHECK(m2.is_locked);
|
||||
}
|
||||
void test_try_lock_two_first_locked()
|
||||
{
|
||||
dummy_mutex m1,m2;
|
||||
m1.lock();
|
||||
|
||||
boost::unique_lock<dummy_mutex> l1(m1,boost::defer_lock),
|
||||
l2(m2,boost::defer_lock);
|
||||
|
||||
int const res=boost::try_lock(l1,l2);
|
||||
|
||||
BOOST_CHECK(res==0);
|
||||
BOOST_CHECK(m1.is_locked);
|
||||
BOOST_CHECK(!m2.is_locked);
|
||||
BOOST_CHECK(!l1.owns_lock());
|
||||
BOOST_CHECK(!l2.owns_lock());
|
||||
}
|
||||
void test_try_lock_two_second_locked()
|
||||
{
|
||||
dummy_mutex m1,m2;
|
||||
m2.lock();
|
||||
|
||||
boost::unique_lock<dummy_mutex> l1(m1,boost::defer_lock),
|
||||
l2(m2,boost::defer_lock);
|
||||
|
||||
int const res=boost::try_lock(l1,l2);
|
||||
|
||||
BOOST_CHECK(res==1);
|
||||
BOOST_CHECK(!m1.is_locked);
|
||||
BOOST_CHECK(m2.is_locked);
|
||||
BOOST_CHECK(!l1.owns_lock());
|
||||
BOOST_CHECK(!l2.owns_lock());
|
||||
}
|
||||
|
||||
void test_try_lock_three()
|
||||
{
|
||||
int const num_mutexes=3;
|
||||
|
||||
for(int i=-1;i<num_mutexes;++i)
|
||||
{
|
||||
dummy_mutex mutexes[num_mutexes];
|
||||
|
||||
if(i>=0)
|
||||
{
|
||||
mutexes[i].lock();
|
||||
}
|
||||
boost::unique_lock<dummy_mutex> l1(mutexes[0],boost::defer_lock),
|
||||
l2(mutexes[1],boost::defer_lock),
|
||||
l3(mutexes[2],boost::defer_lock);
|
||||
|
||||
int const res=boost::try_lock(l1,l2,l3);
|
||||
|
||||
BOOST_CHECK(res==i);
|
||||
for(int j=0;j<num_mutexes;++j)
|
||||
{
|
||||
if((i==j) || (i==-1))
|
||||
{
|
||||
BOOST_CHECK(mutexes[j].is_locked);
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_CHECK(!mutexes[j].is_locked);
|
||||
}
|
||||
}
|
||||
if(i==-1)
|
||||
{
|
||||
BOOST_CHECK(l1.owns_lock());
|
||||
BOOST_CHECK(l2.owns_lock());
|
||||
BOOST_CHECK(l3.owns_lock());
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_CHECK(!l1.owns_lock());
|
||||
BOOST_CHECK(!l2.owns_lock());
|
||||
BOOST_CHECK(!l3.owns_lock());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void test_try_lock_four()
|
||||
{
|
||||
int const num_mutexes=4;
|
||||
|
||||
for(int i=-1;i<num_mutexes;++i)
|
||||
{
|
||||
dummy_mutex mutexes[num_mutexes];
|
||||
|
||||
if(i>=0)
|
||||
{
|
||||
mutexes[i].lock();
|
||||
}
|
||||
boost::unique_lock<dummy_mutex> l1(mutexes[0],boost::defer_lock),
|
||||
l2(mutexes[1],boost::defer_lock),
|
||||
l3(mutexes[2],boost::defer_lock),
|
||||
l4(mutexes[3],boost::defer_lock);
|
||||
|
||||
int const res=boost::try_lock(l1,l2,l3,l4);
|
||||
|
||||
BOOST_CHECK(res==i);
|
||||
for(int j=0;j<num_mutexes;++j)
|
||||
{
|
||||
if((i==j) || (i==-1))
|
||||
{
|
||||
BOOST_CHECK(mutexes[j].is_locked);
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_CHECK(!mutexes[j].is_locked);
|
||||
}
|
||||
}
|
||||
if(i==-1)
|
||||
{
|
||||
BOOST_CHECK(l1.owns_lock());
|
||||
BOOST_CHECK(l2.owns_lock());
|
||||
BOOST_CHECK(l3.owns_lock());
|
||||
BOOST_CHECK(l4.owns_lock());
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_CHECK(!l1.owns_lock());
|
||||
BOOST_CHECK(!l2.owns_lock());
|
||||
BOOST_CHECK(!l3.owns_lock());
|
||||
BOOST_CHECK(!l4.owns_lock());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void test_try_lock_five()
|
||||
{
|
||||
int const num_mutexes=5;
|
||||
|
||||
for(int i=-1;i<num_mutexes;++i)
|
||||
{
|
||||
dummy_mutex mutexes[num_mutexes];
|
||||
|
||||
if(i>=0)
|
||||
{
|
||||
mutexes[i].lock();
|
||||
}
|
||||
boost::unique_lock<dummy_mutex> l1(mutexes[0],boost::defer_lock),
|
||||
l2(mutexes[1],boost::defer_lock),
|
||||
l3(mutexes[2],boost::defer_lock),
|
||||
l4(mutexes[3],boost::defer_lock),
|
||||
l5(mutexes[4],boost::defer_lock);
|
||||
|
||||
int const res=boost::try_lock(l1,l2,l3,l4,l5);
|
||||
|
||||
BOOST_CHECK(res==i);
|
||||
for(int j=0;j<num_mutexes;++j)
|
||||
{
|
||||
if((i==j) || (i==-1))
|
||||
{
|
||||
BOOST_CHECK(mutexes[j].is_locked);
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_CHECK(!mutexes[j].is_locked);
|
||||
}
|
||||
}
|
||||
if(i==-1)
|
||||
{
|
||||
BOOST_CHECK(l1.owns_lock());
|
||||
BOOST_CHECK(l2.owns_lock());
|
||||
BOOST_CHECK(l3.owns_lock());
|
||||
BOOST_CHECK(l4.owns_lock());
|
||||
BOOST_CHECK(l5.owns_lock());
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_CHECK(!l1.owns_lock());
|
||||
BOOST_CHECK(!l2.owns_lock());
|
||||
BOOST_CHECK(!l3.owns_lock());
|
||||
BOOST_CHECK(!l4.owns_lock());
|
||||
BOOST_CHECK(!l5.owns_lock());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: generic locks test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(&test_lock_two_uncontended));
|
||||
test->add(BOOST_TEST_CASE(&test_lock_two_other_thread_locks_in_order));
|
||||
test->add(BOOST_TEST_CASE(&test_lock_two_other_thread_locks_in_opposite_order));
|
||||
test->add(BOOST_TEST_CASE(&test_lock_five_uncontended));
|
||||
test->add(BOOST_TEST_CASE(&test_lock_five_other_thread_locks_in_order));
|
||||
test->add(BOOST_TEST_CASE(&test_lock_five_other_thread_locks_in_different_order));
|
||||
test->add(BOOST_TEST_CASE(&test_lock_five_in_range));
|
||||
test->add(BOOST_TEST_CASE(&test_lock_ten_in_range));
|
||||
test->add(BOOST_TEST_CASE(&test_lock_ten_other_thread_locks_in_different_order));
|
||||
test->add(BOOST_TEST_CASE(&test_try_lock_two_uncontended));
|
||||
test->add(BOOST_TEST_CASE(&test_try_lock_two_first_locked));
|
||||
test->add(BOOST_TEST_CASE(&test_try_lock_two_second_locked));
|
||||
test->add(BOOST_TEST_CASE(&test_try_lock_three));
|
||||
test->add(BOOST_TEST_CASE(&test_try_lock_four));
|
||||
test->add(BOOST_TEST_CASE(&test_try_lock_five));
|
||||
|
||||
return test;
|
||||
}
|
||||
21
test/test_hardware_concurrency.cpp
Normal file
21
test/test_hardware_concurrency.cpp
Normal file
@@ -0,0 +1,21 @@
|
||||
// Copyright (C) 2007 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
|
||||
void test_hardware_concurrency_is_non_zero()
|
||||
{
|
||||
BOOST_CHECK(boost::thread::hardware_concurrency()!=0);
|
||||
}
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: hardware concurrency test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(test_hardware_concurrency_is_non_zero));
|
||||
return test;
|
||||
}
|
||||
571
test/test_lock_concept.cpp
Normal file
571
test/test_lock_concept.cpp
Normal file
@@ -0,0 +1,571 @@
|
||||
// (C) Copyright 2006-8 Anthony Williams
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/test/test_case_template.hpp>
|
||||
#include <boost/mpl/vector.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/shared_mutex.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
|
||||
template<typename Mutex,typename Lock>
|
||||
struct test_initially_locked
|
||||
{
|
||||
void operator()() const
|
||||
{
|
||||
Mutex m;
|
||||
Lock lock(m);
|
||||
|
||||
BOOST_CHECK(lock);
|
||||
BOOST_CHECK(lock.owns_lock());
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Mutex,typename Lock>
|
||||
struct test_initially_unlocked_if_other_thread_has_lock
|
||||
{
|
||||
Mutex m;
|
||||
boost::mutex done_mutex;
|
||||
bool done;
|
||||
bool locked;
|
||||
boost::condition_variable done_cond;
|
||||
|
||||
test_initially_unlocked_if_other_thread_has_lock():
|
||||
done(false),locked(false)
|
||||
{}
|
||||
|
||||
void locking_thread()
|
||||
{
|
||||
Lock lock(m);
|
||||
|
||||
boost::lock_guard<boost::mutex> lk(done_mutex);
|
||||
locked=lock.owns_lock();
|
||||
done=true;
|
||||
done_cond.notify_one();
|
||||
}
|
||||
|
||||
bool is_done() const
|
||||
{
|
||||
return done;
|
||||
}
|
||||
|
||||
|
||||
void operator()()
|
||||
{
|
||||
Lock lock(m);
|
||||
|
||||
typedef test_initially_unlocked_if_other_thread_has_lock<Mutex,Lock> this_type;
|
||||
|
||||
boost::thread t(&this_type::locking_thread,this);
|
||||
|
||||
try
|
||||
{
|
||||
{
|
||||
boost::mutex::scoped_lock lk(done_mutex);
|
||||
BOOST_CHECK(done_cond.timed_wait(lk,boost::posix_time::seconds(2),
|
||||
boost::bind(&this_type::is_done,this)));
|
||||
BOOST_CHECK(!locked);
|
||||
}
|
||||
|
||||
lock.unlock();
|
||||
t.join();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
lock.unlock();
|
||||
t.join();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Mutex,typename Lock>
|
||||
struct test_initially_unlocked_with_try_lock_if_other_thread_has_unique_lock
|
||||
{
|
||||
Mutex m;
|
||||
boost::mutex done_mutex;
|
||||
bool done;
|
||||
bool locked;
|
||||
boost::condition_variable done_cond;
|
||||
|
||||
test_initially_unlocked_with_try_lock_if_other_thread_has_unique_lock():
|
||||
done(false),locked(false)
|
||||
{}
|
||||
|
||||
void locking_thread()
|
||||
{
|
||||
Lock lock(m,boost::try_to_lock);
|
||||
|
||||
boost::lock_guard<boost::mutex> lk(done_mutex);
|
||||
locked=lock.owns_lock();
|
||||
done=true;
|
||||
done_cond.notify_one();
|
||||
}
|
||||
|
||||
bool is_done() const
|
||||
{
|
||||
return done;
|
||||
}
|
||||
|
||||
|
||||
void operator()()
|
||||
{
|
||||
boost::unique_lock<Mutex> lock(m);
|
||||
|
||||
typedef test_initially_unlocked_with_try_lock_if_other_thread_has_unique_lock<Mutex,Lock> this_type;
|
||||
|
||||
boost::thread t(&this_type::locking_thread,this);
|
||||
|
||||
try
|
||||
{
|
||||
{
|
||||
boost::mutex::scoped_lock lk(done_mutex);
|
||||
BOOST_CHECK(done_cond.timed_wait(lk,boost::posix_time::seconds(2),
|
||||
boost::bind(&this_type::is_done,this)));
|
||||
BOOST_CHECK(!locked);
|
||||
}
|
||||
|
||||
lock.unlock();
|
||||
t.join();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
lock.unlock();
|
||||
t.join();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Mutex,typename Lock>
|
||||
struct test_initially_locked_if_other_thread_has_shared_lock
|
||||
{
|
||||
Mutex m;
|
||||
boost::mutex done_mutex;
|
||||
bool done;
|
||||
bool locked;
|
||||
boost::condition_variable done_cond;
|
||||
|
||||
test_initially_locked_if_other_thread_has_shared_lock():
|
||||
done(false),locked(false)
|
||||
{}
|
||||
|
||||
void locking_thread()
|
||||
{
|
||||
Lock lock(m);
|
||||
|
||||
boost::lock_guard<boost::mutex> lk(done_mutex);
|
||||
locked=lock.owns_lock();
|
||||
done=true;
|
||||
done_cond.notify_one();
|
||||
}
|
||||
|
||||
bool is_done() const
|
||||
{
|
||||
return done;
|
||||
}
|
||||
|
||||
|
||||
void operator()()
|
||||
{
|
||||
boost::shared_lock<Mutex> lock(m);
|
||||
|
||||
typedef test_initially_locked_if_other_thread_has_shared_lock<Mutex,Lock> this_type;
|
||||
|
||||
boost::thread t(&this_type::locking_thread,this);
|
||||
|
||||
try
|
||||
{
|
||||
{
|
||||
boost::mutex::scoped_lock lk(done_mutex);
|
||||
BOOST_CHECK(done_cond.timed_wait(lk,boost::posix_time::seconds(2),
|
||||
boost::bind(&this_type::is_done,this)));
|
||||
BOOST_CHECK(locked);
|
||||
}
|
||||
|
||||
lock.unlock();
|
||||
t.join();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
lock.unlock();
|
||||
t.join();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Mutex,typename Lock>
|
||||
struct test_initially_unlocked_with_defer_lock_parameter
|
||||
{
|
||||
void operator()() const
|
||||
{
|
||||
Mutex m;
|
||||
Lock lock(m,boost::defer_lock);
|
||||
|
||||
BOOST_CHECK(!lock);
|
||||
BOOST_CHECK(!lock.owns_lock());
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Mutex,typename Lock>
|
||||
struct test_initially_locked_with_adopt_lock_parameter
|
||||
{
|
||||
void operator()() const
|
||||
{
|
||||
Mutex m;
|
||||
m.lock();
|
||||
Lock lock(m,boost::adopt_lock);
|
||||
|
||||
BOOST_CHECK(lock);
|
||||
BOOST_CHECK(lock.owns_lock());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename Mutex,typename Lock>
|
||||
struct test_unlocked_after_unlock_called
|
||||
{
|
||||
void operator()() const
|
||||
{
|
||||
Mutex m;
|
||||
Lock lock(m);
|
||||
lock.unlock();
|
||||
BOOST_CHECK(!lock);
|
||||
BOOST_CHECK(!lock.owns_lock());
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Mutex,typename Lock>
|
||||
struct test_locked_after_lock_called
|
||||
{
|
||||
void operator()() const
|
||||
{
|
||||
Mutex m;
|
||||
Lock lock(m,boost::defer_lock);
|
||||
lock.lock();
|
||||
BOOST_CHECK(lock);
|
||||
BOOST_CHECK(lock.owns_lock());
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Mutex,typename Lock>
|
||||
struct test_locked_after_try_lock_called
|
||||
{
|
||||
void operator()() const
|
||||
{
|
||||
Mutex m;
|
||||
Lock lock(m,boost::defer_lock);
|
||||
lock.try_lock();
|
||||
BOOST_CHECK(lock);
|
||||
BOOST_CHECK(lock.owns_lock());
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Mutex,typename Lock>
|
||||
struct test_unlocked_after_try_lock_if_other_thread_has_lock
|
||||
{
|
||||
Mutex m;
|
||||
boost::mutex done_mutex;
|
||||
bool done;
|
||||
bool locked;
|
||||
boost::condition_variable done_cond;
|
||||
|
||||
test_unlocked_after_try_lock_if_other_thread_has_lock():
|
||||
done(false),locked(false)
|
||||
{}
|
||||
|
||||
void locking_thread()
|
||||
{
|
||||
Lock lock(m,boost::defer_lock);
|
||||
|
||||
boost::lock_guard<boost::mutex> lk(done_mutex);
|
||||
locked=lock.owns_lock();
|
||||
done=true;
|
||||
done_cond.notify_one();
|
||||
}
|
||||
|
||||
bool is_done() const
|
||||
{
|
||||
return done;
|
||||
}
|
||||
|
||||
|
||||
void operator()()
|
||||
{
|
||||
Lock lock(m);
|
||||
|
||||
typedef test_unlocked_after_try_lock_if_other_thread_has_lock<Mutex,Lock> this_type;
|
||||
|
||||
boost::thread t(&this_type::locking_thread,this);
|
||||
|
||||
try
|
||||
{
|
||||
{
|
||||
boost::mutex::scoped_lock lk(done_mutex);
|
||||
BOOST_CHECK(done_cond.timed_wait(lk,boost::posix_time::seconds(2),
|
||||
boost::bind(&this_type::is_done,this)));
|
||||
BOOST_CHECK(!locked);
|
||||
}
|
||||
|
||||
lock.unlock();
|
||||
t.join();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
lock.unlock();
|
||||
t.join();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Mutex,typename Lock>
|
||||
struct test_throws_if_lock_called_when_already_locked
|
||||
{
|
||||
void operator()() const
|
||||
{
|
||||
Mutex m;
|
||||
Lock lock(m);
|
||||
|
||||
BOOST_CHECK_THROW( lock.lock(), boost::lock_error );
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Mutex,typename Lock>
|
||||
struct test_throws_if_try_lock_called_when_already_locked
|
||||
{
|
||||
void operator()() const
|
||||
{
|
||||
Mutex m;
|
||||
Lock lock(m);
|
||||
|
||||
BOOST_CHECK_THROW( lock.try_lock(), boost::lock_error );
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Mutex,typename Lock>
|
||||
struct test_throws_if_unlock_called_when_already_unlocked
|
||||
{
|
||||
void operator()() const
|
||||
{
|
||||
Mutex m;
|
||||
Lock lock(m);
|
||||
lock.unlock();
|
||||
|
||||
BOOST_CHECK_THROW( lock.unlock(), boost::lock_error );
|
||||
}
|
||||
};
|
||||
template<typename Lock>
|
||||
struct test_default_constructed_has_no_mutex_and_unlocked
|
||||
{
|
||||
void operator()() const
|
||||
{
|
||||
Lock l;
|
||||
BOOST_CHECK(!l.mutex());
|
||||
BOOST_CHECK(!l.owns_lock());
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
template<typename Mutex,typename Lock>
|
||||
struct test_locks_can_be_swapped
|
||||
{
|
||||
void operator()() const
|
||||
{
|
||||
Mutex m1;
|
||||
Mutex m2;
|
||||
Mutex m3;
|
||||
|
||||
Lock l1(m1);
|
||||
Lock l2(m2);
|
||||
|
||||
BOOST_CHECK_EQUAL(l1.mutex(),&m1);
|
||||
BOOST_CHECK_EQUAL(l2.mutex(),&m2);
|
||||
|
||||
l1.swap(l2);
|
||||
|
||||
BOOST_CHECK_EQUAL(l1.mutex(),&m2);
|
||||
BOOST_CHECK_EQUAL(l2.mutex(),&m1);
|
||||
|
||||
swap(l1,l2);
|
||||
|
||||
BOOST_CHECK_EQUAL(l1.mutex(),&m1);
|
||||
BOOST_CHECK_EQUAL(l2.mutex(),&m2);
|
||||
|
||||
l1.swap(Lock(m3));
|
||||
|
||||
BOOST_CHECK_EQUAL(l1.mutex(),&m3);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Mutex,typename Lock>
|
||||
void test_lock_is_scoped_lock_concept_for_mutex()
|
||||
{
|
||||
test_default_constructed_has_no_mutex_and_unlocked<Lock>()();
|
||||
test_initially_locked<Mutex,Lock>()();
|
||||
test_initially_unlocked_with_defer_lock_parameter<Mutex,Lock>()();
|
||||
test_initially_locked_with_adopt_lock_parameter<Mutex,Lock>()();
|
||||
test_unlocked_after_unlock_called<Mutex,Lock>()();
|
||||
test_locked_after_lock_called<Mutex,Lock>()();
|
||||
test_throws_if_lock_called_when_already_locked<Mutex,Lock>()();
|
||||
test_throws_if_unlock_called_when_already_unlocked<Mutex,Lock>()();
|
||||
test_locks_can_be_swapped<Mutex,Lock>()();
|
||||
test_locked_after_try_lock_called<Mutex,Lock>()();
|
||||
test_throws_if_try_lock_called_when_already_locked<Mutex,Lock>()();
|
||||
test_unlocked_after_try_lock_if_other_thread_has_lock<Mutex,Lock>()();
|
||||
}
|
||||
|
||||
|
||||
BOOST_TEST_CASE_TEMPLATE_FUNCTION(test_scoped_lock_concept,Mutex)
|
||||
{
|
||||
typedef typename Mutex::scoped_lock Lock;
|
||||
|
||||
test_lock_is_scoped_lock_concept_for_mutex<Mutex,Lock>();
|
||||
}
|
||||
|
||||
BOOST_TEST_CASE_TEMPLATE_FUNCTION(test_unique_lock_is_scoped_lock,Mutex)
|
||||
{
|
||||
typedef boost::unique_lock<Mutex> Lock;
|
||||
|
||||
test_lock_is_scoped_lock_concept_for_mutex<Mutex,Lock>();
|
||||
}
|
||||
|
||||
BOOST_TEST_CASE_TEMPLATE_FUNCTION(test_scoped_try_lock_concept,Mutex)
|
||||
{
|
||||
typedef typename Mutex::scoped_try_lock Lock;
|
||||
|
||||
test_default_constructed_has_no_mutex_and_unlocked<Lock>()();
|
||||
test_initially_locked<Mutex,Lock>()();
|
||||
test_initially_unlocked_if_other_thread_has_lock<Mutex,Lock>()();
|
||||
test_initially_unlocked_with_defer_lock_parameter<Mutex,Lock>()();
|
||||
test_initially_locked_with_adopt_lock_parameter<Mutex,Lock>()();
|
||||
test_unlocked_after_unlock_called<Mutex,Lock>()();
|
||||
test_locked_after_lock_called<Mutex,Lock>()();
|
||||
test_locked_after_try_lock_called<Mutex,Lock>()();
|
||||
test_unlocked_after_try_lock_if_other_thread_has_lock<Mutex,Lock>()();
|
||||
test_throws_if_lock_called_when_already_locked<Mutex,Lock>()();
|
||||
test_throws_if_try_lock_called_when_already_locked<Mutex,Lock>()();
|
||||
test_throws_if_unlock_called_when_already_unlocked<Mutex,Lock>()();
|
||||
test_locks_can_be_swapped<Mutex,Lock>()();
|
||||
}
|
||||
|
||||
struct dummy_shared_mutex
|
||||
{
|
||||
bool locked;
|
||||
bool shared_locked;
|
||||
bool shared_unlocked;
|
||||
bool shared_timed_locked_relative;
|
||||
bool shared_timed_locked_absolute;
|
||||
bool timed_locked_relative;
|
||||
bool timed_locked_absolute;
|
||||
|
||||
dummy_shared_mutex():
|
||||
locked(false),shared_locked(false),shared_unlocked(false),
|
||||
shared_timed_locked_relative(false),
|
||||
shared_timed_locked_absolute(false),
|
||||
timed_locked_relative(false),
|
||||
timed_locked_absolute(false)
|
||||
{}
|
||||
|
||||
void lock()
|
||||
{
|
||||
locked=true;
|
||||
}
|
||||
|
||||
void lock_shared()
|
||||
{
|
||||
shared_locked=true;
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{}
|
||||
|
||||
void unlock_shared()
|
||||
{
|
||||
shared_unlocked=true;
|
||||
}
|
||||
|
||||
bool timed_lock_shared(boost::system_time)
|
||||
{
|
||||
shared_timed_locked_absolute=true;
|
||||
return false;
|
||||
}
|
||||
template<typename Duration>
|
||||
bool timed_lock_shared(Duration)
|
||||
{
|
||||
shared_timed_locked_relative=true;
|
||||
return false;
|
||||
}
|
||||
bool timed_lock(boost::system_time)
|
||||
{
|
||||
timed_locked_absolute=true;
|
||||
return false;
|
||||
}
|
||||
template<typename Duration>
|
||||
bool timed_lock(Duration)
|
||||
{
|
||||
timed_locked_relative=true;
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
void test_shared_lock()
|
||||
{
|
||||
typedef boost::shared_mutex Mutex;
|
||||
typedef boost::shared_lock<Mutex> Lock;
|
||||
|
||||
test_default_constructed_has_no_mutex_and_unlocked<Lock>()();
|
||||
test_initially_locked<Mutex,Lock>()();
|
||||
test_initially_unlocked_with_try_lock_if_other_thread_has_unique_lock<Mutex,Lock>()();
|
||||
test_initially_locked_if_other_thread_has_shared_lock<Mutex,Lock>()();
|
||||
test_initially_unlocked_with_defer_lock_parameter<Mutex,Lock>()();
|
||||
test_initially_locked_with_adopt_lock_parameter<Mutex,Lock>()();
|
||||
test_unlocked_after_unlock_called<Mutex,Lock>()();
|
||||
test_locked_after_lock_called<Mutex,Lock>()();
|
||||
test_locked_after_try_lock_called<Mutex,Lock>()();
|
||||
test_throws_if_lock_called_when_already_locked<Mutex,Lock>()();
|
||||
test_throws_if_try_lock_called_when_already_locked<Mutex,Lock>()();
|
||||
test_throws_if_unlock_called_when_already_unlocked<Mutex,Lock>()();
|
||||
test_locks_can_be_swapped<Mutex,Lock>()();
|
||||
|
||||
dummy_shared_mutex dummy;
|
||||
boost::shared_lock<dummy_shared_mutex> lk(dummy);
|
||||
BOOST_CHECK(dummy.shared_locked);
|
||||
lk.unlock();
|
||||
BOOST_CHECK(dummy.shared_unlocked);
|
||||
lk.timed_lock(boost::posix_time::milliseconds(5));
|
||||
BOOST_CHECK(dummy.shared_timed_locked_relative);
|
||||
lk.timed_lock(boost::get_system_time());
|
||||
BOOST_CHECK(dummy.shared_timed_locked_absolute);
|
||||
}
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: lock concept test suite");
|
||||
|
||||
typedef boost::mpl::vector<boost::mutex,boost::try_mutex,boost::timed_mutex,
|
||||
boost::recursive_mutex,boost::recursive_try_mutex,boost::recursive_timed_mutex> mutex_types_with_scoped_lock;
|
||||
|
||||
test->add(BOOST_TEST_CASE_TEMPLATE(test_scoped_lock_concept,mutex_types_with_scoped_lock));
|
||||
|
||||
typedef boost::mpl::vector<boost::try_mutex,boost::timed_mutex,
|
||||
boost::recursive_try_mutex,boost::recursive_timed_mutex> mutex_types_with_scoped_try_lock;
|
||||
|
||||
test->add(BOOST_TEST_CASE_TEMPLATE(test_scoped_try_lock_concept,mutex_types_with_scoped_try_lock));
|
||||
|
||||
typedef boost::mpl::vector<boost::mutex,boost::try_mutex,boost::timed_mutex,
|
||||
boost::recursive_mutex,boost::recursive_try_mutex,boost::recursive_timed_mutex,boost::shared_mutex> all_mutex_types;
|
||||
|
||||
test->add(BOOST_TEST_CASE_TEMPLATE(test_unique_lock_is_scoped_lock,all_mutex_types));
|
||||
test->add(BOOST_TEST_CASE(&test_shared_lock));
|
||||
|
||||
return test;
|
||||
}
|
||||
124
test/test_move_function.cpp
Normal file
124
test/test_move_function.cpp
Normal file
@@ -0,0 +1,124 @@
|
||||
// Copyright (C) 2007-8 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
void do_nothing()
|
||||
{}
|
||||
|
||||
void test_thread_move_from_lvalue_on_construction()
|
||||
{
|
||||
boost::thread src(do_nothing);
|
||||
boost::thread::id src_id=src.get_id();
|
||||
boost::thread dest(boost::move(src));
|
||||
boost::thread::id dest_id=dest.get_id();
|
||||
BOOST_CHECK(src_id==dest_id);
|
||||
BOOST_CHECK(src.get_id()==boost::thread::id());
|
||||
dest.join();
|
||||
}
|
||||
|
||||
void test_thread_move_from_lvalue_on_assignment()
|
||||
{
|
||||
boost::thread src(do_nothing);
|
||||
boost::thread::id src_id=src.get_id();
|
||||
boost::thread dest;
|
||||
dest=boost::move(src);
|
||||
boost::thread::id dest_id=dest.get_id();
|
||||
BOOST_CHECK(src_id==dest_id);
|
||||
BOOST_CHECK(src.get_id()==boost::thread::id());
|
||||
dest.join();
|
||||
}
|
||||
|
||||
boost::thread start_thread()
|
||||
{
|
||||
return boost::thread(do_nothing);
|
||||
}
|
||||
|
||||
void test_thread_move_from_rvalue_on_construction()
|
||||
{
|
||||
boost::thread x(start_thread());
|
||||
BOOST_CHECK(x.get_id()!=boost::thread::id());
|
||||
x.join();
|
||||
}
|
||||
|
||||
void test_thread_move_from_rvalue_using_explicit_move()
|
||||
{
|
||||
boost::thread x(boost::move(start_thread()));
|
||||
BOOST_CHECK(x.get_id()!=boost::thread::id());
|
||||
x.join();
|
||||
}
|
||||
|
||||
void test_unique_lock_move_from_lvalue_on_construction()
|
||||
{
|
||||
boost::mutex m;
|
||||
boost::unique_lock<boost::mutex> l(m);
|
||||
BOOST_CHECK(l.owns_lock());
|
||||
BOOST_CHECK(l.mutex()==&m);
|
||||
|
||||
boost::unique_lock<boost::mutex> l2(boost::move(l));
|
||||
BOOST_CHECK(!l.owns_lock());
|
||||
BOOST_CHECK(!l.mutex());
|
||||
BOOST_CHECK(l2.owns_lock());
|
||||
BOOST_CHECK(l2.mutex()==&m);
|
||||
}
|
||||
|
||||
boost::unique_lock<boost::mutex> get_lock(boost::mutex& m)
|
||||
{
|
||||
return boost::unique_lock<boost::mutex>(m);
|
||||
}
|
||||
|
||||
|
||||
void test_unique_lock_move_from_rvalue_on_construction()
|
||||
{
|
||||
boost::mutex m;
|
||||
boost::unique_lock<boost::mutex> l(get_lock(m));
|
||||
BOOST_CHECK(l.owns_lock());
|
||||
BOOST_CHECK(l.mutex()==&m);
|
||||
}
|
||||
|
||||
namespace user_test_ns
|
||||
{
|
||||
template<typename T>
|
||||
T move(T& t)
|
||||
{
|
||||
return t.move();
|
||||
}
|
||||
|
||||
bool move_called=false;
|
||||
|
||||
struct nc:
|
||||
public boost::shared_ptr<int>
|
||||
{
|
||||
nc move()
|
||||
{
|
||||
move_called=true;
|
||||
return nc();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void test_move_for_user_defined_type_unaffected()
|
||||
{
|
||||
user_test_ns::nc src;
|
||||
user_test_ns::nc dest=move(src);
|
||||
BOOST_CHECK(user_test_ns::move_called);
|
||||
}
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: thread move test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(test_thread_move_from_lvalue_on_construction));
|
||||
test->add(BOOST_TEST_CASE(test_thread_move_from_rvalue_on_construction));
|
||||
test->add(BOOST_TEST_CASE(test_thread_move_from_rvalue_using_explicit_move));
|
||||
test->add(BOOST_TEST_CASE(test_thread_move_from_lvalue_on_assignment));
|
||||
test->add(BOOST_TEST_CASE(test_unique_lock_move_from_lvalue_on_construction));
|
||||
test->add(BOOST_TEST_CASE(test_unique_lock_move_from_rvalue_on_construction));
|
||||
test->add(BOOST_TEST_CASE(test_move_for_user_defined_type_unaffected));
|
||||
return test;
|
||||
}
|
||||
@@ -7,8 +7,9 @@
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#include <boost/thread/condition.hpp>
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
@@ -29,7 +30,7 @@ struct test_lock
|
||||
|
||||
// Test the lock's constructors.
|
||||
{
|
||||
lock_type lock(mutex, false);
|
||||
lock_type lock(mutex, boost::defer_lock);
|
||||
BOOST_CHECK(!lock);
|
||||
}
|
||||
lock_type lock(mutex);
|
||||
@@ -69,10 +70,10 @@ struct test_trylock
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
}
|
||||
{
|
||||
try_lock_type lock(mutex, false);
|
||||
try_lock_type lock(mutex, boost::defer_lock);
|
||||
BOOST_CHECK(!lock);
|
||||
}
|
||||
try_lock_type lock(mutex, true);
|
||||
try_lock_type lock(mutex);
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
|
||||
// Construct and initialize an xtime for a fast time out.
|
||||
@@ -96,41 +97,131 @@ struct test_trylock
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Mutex>
|
||||
struct test_lock_times_out_if_other_thread_has_lock
|
||||
{
|
||||
typedef boost::unique_lock<Mutex> Lock;
|
||||
|
||||
Mutex m;
|
||||
boost::mutex done_mutex;
|
||||
bool done;
|
||||
bool locked;
|
||||
boost::condition_variable done_cond;
|
||||
|
||||
test_lock_times_out_if_other_thread_has_lock():
|
||||
done(false),locked(false)
|
||||
{}
|
||||
|
||||
void locking_thread()
|
||||
{
|
||||
Lock lock(m,boost::defer_lock);
|
||||
lock.timed_lock(boost::posix_time::milliseconds(50));
|
||||
|
||||
boost::lock_guard<boost::mutex> lk(done_mutex);
|
||||
locked=lock.owns_lock();
|
||||
done=true;
|
||||
done_cond.notify_one();
|
||||
}
|
||||
|
||||
void locking_thread_through_constructor()
|
||||
{
|
||||
Lock lock(m,boost::posix_time::milliseconds(50));
|
||||
|
||||
boost::lock_guard<boost::mutex> lk(done_mutex);
|
||||
locked=lock.owns_lock();
|
||||
done=true;
|
||||
done_cond.notify_one();
|
||||
}
|
||||
|
||||
bool is_done() const
|
||||
{
|
||||
return done;
|
||||
}
|
||||
|
||||
typedef test_lock_times_out_if_other_thread_has_lock<Mutex> this_type;
|
||||
|
||||
void do_test(void (this_type::*test_func)())
|
||||
{
|
||||
Lock lock(m);
|
||||
|
||||
locked=false;
|
||||
done=false;
|
||||
|
||||
boost::thread t(test_func,this);
|
||||
|
||||
try
|
||||
{
|
||||
{
|
||||
boost::mutex::scoped_lock lk(done_mutex);
|
||||
BOOST_CHECK(done_cond.timed_wait(lk,boost::posix_time::seconds(2),
|
||||
boost::bind(&this_type::is_done,this)));
|
||||
BOOST_CHECK(!locked);
|
||||
}
|
||||
|
||||
lock.unlock();
|
||||
t.join();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
lock.unlock();
|
||||
t.join();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void operator()()
|
||||
{
|
||||
do_test(&this_type::locking_thread);
|
||||
do_test(&this_type::locking_thread_through_constructor);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename M>
|
||||
struct test_timedlock
|
||||
{
|
||||
typedef M mutex_type;
|
||||
typedef typename M::scoped_timed_lock timed_lock_type;
|
||||
|
||||
static bool fake_predicate()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void operator()()
|
||||
{
|
||||
test_lock_times_out_if_other_thread_has_lock<mutex_type>()();
|
||||
|
||||
mutex_type mutex;
|
||||
boost::condition condition;
|
||||
|
||||
// Test the lock's constructors.
|
||||
{
|
||||
// Construct and initialize an xtime for a fast time out.
|
||||
boost::xtime xt = delay(0, 100);
|
||||
boost::system_time xt = boost::get_system_time()+boost::posix_time::milliseconds(100);
|
||||
|
||||
timed_lock_type lock(mutex, xt);
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
}
|
||||
{
|
||||
timed_lock_type lock(mutex, false);
|
||||
timed_lock_type lock(mutex, boost::defer_lock);
|
||||
BOOST_CHECK(!lock);
|
||||
}
|
||||
timed_lock_type lock(mutex, true);
|
||||
timed_lock_type lock(mutex);
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
|
||||
// Construct and initialize an xtime for a fast time out.
|
||||
boost::xtime xt = delay(0, 100);
|
||||
boost::system_time timeout = boost::get_system_time()+boost::posix_time::milliseconds(100);
|
||||
|
||||
// Test the lock and the mutex with condition variables.
|
||||
// No one is going to notify this condition variable. We expect to
|
||||
// time out.
|
||||
BOOST_CHECK(!condition.timed_wait(lock, xt));
|
||||
BOOST_CHECK(!condition.timed_wait(lock, timeout, fake_predicate));
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
BOOST_CHECK(in_range(xt));
|
||||
|
||||
boost::system_time now=boost::get_system_time();
|
||||
boost::posix_time::milliseconds const timeout_resolution(20);
|
||||
BOOST_CHECK((timeout-timeout_resolution)<now);
|
||||
|
||||
// Test the lock, unlock and timedlock methods.
|
||||
lock.unlock();
|
||||
@@ -139,9 +230,20 @@ struct test_timedlock
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
lock.unlock();
|
||||
BOOST_CHECK(!lock);
|
||||
xt = delay(0, 100);
|
||||
BOOST_CHECK(lock.timed_lock(xt));
|
||||
boost::system_time target = boost::get_system_time()+boost::posix_time::milliseconds(100);
|
||||
BOOST_CHECK(lock.timed_lock(target));
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
lock.unlock();
|
||||
BOOST_CHECK(!lock);
|
||||
|
||||
BOOST_CHECK(mutex.timed_lock(boost::posix_time::milliseconds(100)));
|
||||
mutex.unlock();
|
||||
|
||||
BOOST_CHECK(lock.timed_lock(boost::posix_time::milliseconds(100)));
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
lock.unlock();
|
||||
BOOST_CHECK(!lock);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
@@ -159,6 +261,7 @@ struct test_recursive_lock
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void do_test_mutex()
|
||||
{
|
||||
test_lock<boost::mutex>()();
|
||||
|
||||
@@ -1,52 +1,191 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/thread/once.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
// (C) Copyright 2006-7 Anthony Williams
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/once.hpp>
|
||||
|
||||
#include <libs/thread/test/util.inl>
|
||||
boost::once_flag flag=BOOST_ONCE_INIT;
|
||||
int var_to_init=0;
|
||||
boost::mutex m;
|
||||
|
||||
int once_value = 0;
|
||||
boost::once_flag once = BOOST_ONCE_INIT;
|
||||
|
||||
void init_once_value()
|
||||
void initialize_variable()
|
||||
{
|
||||
once_value++;
|
||||
// ensure that if multiple threads get in here, they are serialized, so we can see the effect
|
||||
boost::mutex::scoped_lock lock(m);
|
||||
++var_to_init;
|
||||
}
|
||||
|
||||
void test_once_thread()
|
||||
|
||||
void call_once_thread()
|
||||
{
|
||||
boost::call_once(init_once_value, once);
|
||||
unsigned const loop_count=100;
|
||||
int my_once_value=0;
|
||||
for(unsigned i=0;i<loop_count;++i)
|
||||
{
|
||||
boost::call_once(flag, initialize_variable);
|
||||
my_once_value=var_to_init;
|
||||
if(my_once_value!=1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
boost::mutex::scoped_lock lock(m);
|
||||
BOOST_CHECK_EQUAL(my_once_value, 1);
|
||||
}
|
||||
|
||||
void do_test_once()
|
||||
void test_call_once()
|
||||
{
|
||||
const int NUMTHREADS=5;
|
||||
boost::thread_group threads;
|
||||
for (int i=0; i<NUMTHREADS; ++i)
|
||||
threads.create_thread(&test_once_thread);
|
||||
threads.join_all();
|
||||
BOOST_CHECK_EQUAL(once_value, 1);
|
||||
unsigned const num_threads=20;
|
||||
boost::thread_group group;
|
||||
|
||||
try
|
||||
{
|
||||
for(unsigned i=0;i<num_threads;++i)
|
||||
{
|
||||
group.create_thread(&call_once_thread);
|
||||
}
|
||||
group.join_all();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
group.interrupt_all();
|
||||
group.join_all();
|
||||
throw;
|
||||
}
|
||||
|
||||
BOOST_CHECK_EQUAL(var_to_init,1);
|
||||
}
|
||||
|
||||
void test_once()
|
||||
int var_to_init_with_functor=0;
|
||||
|
||||
struct increment_value
|
||||
{
|
||||
timed_test(&do_test_once, 2);
|
||||
int* value;
|
||||
explicit increment_value(int* value_):
|
||||
value(value_)
|
||||
{}
|
||||
|
||||
void operator()() const
|
||||
{
|
||||
boost::mutex::scoped_lock lock(m);
|
||||
++(*value);
|
||||
}
|
||||
};
|
||||
|
||||
void call_once_with_functor()
|
||||
{
|
||||
unsigned const loop_count=100;
|
||||
int my_once_value=0;
|
||||
static boost::once_flag functor_flag=BOOST_ONCE_INIT;
|
||||
for(unsigned i=0;i<loop_count;++i)
|
||||
{
|
||||
boost::call_once(functor_flag, increment_value(&var_to_init_with_functor));
|
||||
my_once_value=var_to_init_with_functor;
|
||||
if(my_once_value!=1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
boost::mutex::scoped_lock lock(m);
|
||||
BOOST_CHECK_EQUAL(my_once_value, 1);
|
||||
}
|
||||
|
||||
void test_call_once_arbitrary_functor()
|
||||
{
|
||||
unsigned const num_threads=20;
|
||||
boost::thread_group group;
|
||||
|
||||
try
|
||||
{
|
||||
for(unsigned i=0;i<num_threads;++i)
|
||||
{
|
||||
group.create_thread(&call_once_with_functor);
|
||||
}
|
||||
group.join_all();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
group.interrupt_all();
|
||||
group.join_all();
|
||||
throw;
|
||||
}
|
||||
|
||||
BOOST_CHECK_EQUAL(var_to_init_with_functor,1);
|
||||
}
|
||||
|
||||
|
||||
struct throw_before_third_pass
|
||||
{
|
||||
struct my_exception
|
||||
{};
|
||||
|
||||
static unsigned pass_counter;
|
||||
|
||||
void operator()() const
|
||||
{
|
||||
boost::mutex::scoped_lock lock(m);
|
||||
++pass_counter;
|
||||
if(pass_counter<3)
|
||||
{
|
||||
throw my_exception();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
unsigned throw_before_third_pass::pass_counter=0;
|
||||
unsigned exception_counter=0;
|
||||
|
||||
void call_once_with_exception()
|
||||
{
|
||||
static boost::once_flag functor_flag=BOOST_ONCE_INIT;
|
||||
try
|
||||
{
|
||||
boost::call_once(functor_flag, throw_before_third_pass());
|
||||
}
|
||||
catch(throw_before_third_pass::my_exception)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(m);
|
||||
++exception_counter;
|
||||
}
|
||||
}
|
||||
|
||||
void test_call_once_retried_on_exception()
|
||||
{
|
||||
unsigned const num_threads=20;
|
||||
boost::thread_group group;
|
||||
|
||||
try
|
||||
{
|
||||
for(unsigned i=0;i<num_threads;++i)
|
||||
{
|
||||
group.create_thread(&call_once_with_exception);
|
||||
}
|
||||
group.join_all();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
group.interrupt_all();
|
||||
group.join_all();
|
||||
throw;
|
||||
}
|
||||
|
||||
BOOST_CHECK_EQUAL(throw_before_third_pass::pass_counter,3u);
|
||||
BOOST_CHECK_EQUAL(exception_counter,2u);
|
||||
}
|
||||
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: once test suite");
|
||||
BOOST_TEST_SUITE("Boost.Threads: call_once test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(test_once));
|
||||
test->add(BOOST_TEST_CASE(test_call_once));
|
||||
test->add(BOOST_TEST_CASE(test_call_once_arbitrary_functor));
|
||||
test->add(BOOST_TEST_CASE(test_call_once_retried_on_exception));
|
||||
|
||||
return test;
|
||||
}
|
||||
|
||||
285
test/test_shared_mutex.cpp
Normal file
285
test/test_shared_mutex.cpp
Normal file
@@ -0,0 +1,285 @@
|
||||
// (C) Copyright 2006-7 Anthony Williams
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include "util.inl"
|
||||
#include "shared_mutex_locking_thread.hpp"
|
||||
|
||||
#define CHECK_LOCKED_VALUE_EQUAL(mutex_name,value,expected_value) \
|
||||
{ \
|
||||
boost::mutex::scoped_lock lock(mutex_name); \
|
||||
BOOST_CHECK_EQUAL(value,expected_value); \
|
||||
}
|
||||
|
||||
void test_multiple_readers()
|
||||
{
|
||||
unsigned const number_of_threads=10;
|
||||
|
||||
boost::thread_group pool;
|
||||
|
||||
boost::shared_mutex rw_mutex;
|
||||
unsigned unblocked_count=0;
|
||||
unsigned simultaneous_running_count=0;
|
||||
unsigned max_simultaneous_running=0;
|
||||
boost::mutex unblocked_count_mutex;
|
||||
boost::condition_variable unblocked_condition;
|
||||
boost::mutex finish_mutex;
|
||||
boost::mutex::scoped_lock finish_lock(finish_mutex);
|
||||
|
||||
try
|
||||
{
|
||||
for(unsigned i=0;i<number_of_threads;++i)
|
||||
{
|
||||
pool.create_thread(locking_thread<boost::shared_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
|
||||
finish_mutex,simultaneous_running_count,max_simultaneous_running));
|
||||
}
|
||||
|
||||
{
|
||||
boost::mutex::scoped_lock lk(unblocked_count_mutex);
|
||||
while(unblocked_count<number_of_threads)
|
||||
{
|
||||
unblocked_condition.wait(lk);
|
||||
}
|
||||
}
|
||||
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,number_of_threads);
|
||||
|
||||
finish_lock.unlock();
|
||||
|
||||
pool.join_all();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
pool.interrupt_all();
|
||||
pool.join_all();
|
||||
throw;
|
||||
}
|
||||
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,number_of_threads);
|
||||
}
|
||||
|
||||
void test_only_one_writer_permitted()
|
||||
{
|
||||
unsigned const number_of_threads=10;
|
||||
|
||||
boost::thread_group pool;
|
||||
|
||||
boost::shared_mutex rw_mutex;
|
||||
unsigned unblocked_count=0;
|
||||
unsigned simultaneous_running_count=0;
|
||||
unsigned max_simultaneous_running=0;
|
||||
boost::mutex unblocked_count_mutex;
|
||||
boost::condition_variable unblocked_condition;
|
||||
boost::mutex finish_mutex;
|
||||
boost::mutex::scoped_lock finish_lock(finish_mutex);
|
||||
|
||||
try
|
||||
{
|
||||
for(unsigned i=0;i<number_of_threads;++i)
|
||||
{
|
||||
pool.create_thread(locking_thread<boost::unique_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
|
||||
finish_mutex,simultaneous_running_count,max_simultaneous_running));
|
||||
}
|
||||
|
||||
boost::thread::sleep(delay(2));
|
||||
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U);
|
||||
|
||||
finish_lock.unlock();
|
||||
|
||||
pool.join_all();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
pool.interrupt_all();
|
||||
pool.join_all();
|
||||
throw;
|
||||
}
|
||||
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,number_of_threads);
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,1u);
|
||||
}
|
||||
|
||||
void test_reader_blocks_writer()
|
||||
{
|
||||
boost::thread_group pool;
|
||||
|
||||
boost::shared_mutex rw_mutex;
|
||||
unsigned unblocked_count=0;
|
||||
unsigned simultaneous_running_count=0;
|
||||
unsigned max_simultaneous_running=0;
|
||||
boost::mutex unblocked_count_mutex;
|
||||
boost::condition_variable unblocked_condition;
|
||||
boost::mutex finish_mutex;
|
||||
boost::mutex::scoped_lock finish_lock(finish_mutex);
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
pool.create_thread(locking_thread<boost::shared_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
|
||||
finish_mutex,simultaneous_running_count,max_simultaneous_running));
|
||||
{
|
||||
boost::mutex::scoped_lock lk(unblocked_count_mutex);
|
||||
while(unblocked_count<1)
|
||||
{
|
||||
unblocked_condition.wait(lk);
|
||||
}
|
||||
}
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U);
|
||||
pool.create_thread(locking_thread<boost::unique_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
|
||||
finish_mutex,simultaneous_running_count,max_simultaneous_running));
|
||||
boost::thread::sleep(delay(1));
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U);
|
||||
|
||||
finish_lock.unlock();
|
||||
|
||||
pool.join_all();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
pool.interrupt_all();
|
||||
pool.join_all();
|
||||
throw;
|
||||
}
|
||||
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,2U);
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,1u);
|
||||
}
|
||||
|
||||
void test_unlocking_writer_unblocks_all_readers()
|
||||
{
|
||||
boost::thread_group pool;
|
||||
|
||||
boost::shared_mutex rw_mutex;
|
||||
boost::unique_lock<boost::shared_mutex> write_lock(rw_mutex);
|
||||
unsigned unblocked_count=0;
|
||||
unsigned simultaneous_running_count=0;
|
||||
unsigned max_simultaneous_running=0;
|
||||
boost::mutex unblocked_count_mutex;
|
||||
boost::condition_variable unblocked_condition;
|
||||
boost::mutex finish_mutex;
|
||||
boost::mutex::scoped_lock finish_lock(finish_mutex);
|
||||
|
||||
unsigned const reader_count=10;
|
||||
|
||||
try
|
||||
{
|
||||
for(unsigned i=0;i<reader_count;++i)
|
||||
{
|
||||
pool.create_thread(locking_thread<boost::shared_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
|
||||
finish_mutex,simultaneous_running_count,max_simultaneous_running));
|
||||
}
|
||||
boost::thread::sleep(delay(1));
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,0U);
|
||||
|
||||
write_lock.unlock();
|
||||
|
||||
{
|
||||
boost::mutex::scoped_lock lk(unblocked_count_mutex);
|
||||
while(unblocked_count<reader_count)
|
||||
{
|
||||
unblocked_condition.wait(lk);
|
||||
}
|
||||
}
|
||||
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count);
|
||||
|
||||
finish_lock.unlock();
|
||||
pool.join_all();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
pool.interrupt_all();
|
||||
pool.join_all();
|
||||
throw;
|
||||
}
|
||||
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,reader_count);
|
||||
}
|
||||
|
||||
void test_unlocking_last_reader_only_unblocks_one_writer()
|
||||
{
|
||||
boost::thread_group pool;
|
||||
|
||||
boost::shared_mutex rw_mutex;
|
||||
unsigned unblocked_count=0;
|
||||
unsigned simultaneous_running_readers=0;
|
||||
unsigned max_simultaneous_readers=0;
|
||||
unsigned simultaneous_running_writers=0;
|
||||
unsigned max_simultaneous_writers=0;
|
||||
boost::mutex unblocked_count_mutex;
|
||||
boost::condition_variable unblocked_condition;
|
||||
boost::mutex finish_reading_mutex;
|
||||
boost::mutex::scoped_lock finish_reading_lock(finish_reading_mutex);
|
||||
boost::mutex finish_writing_mutex;
|
||||
boost::mutex::scoped_lock finish_writing_lock(finish_writing_mutex);
|
||||
|
||||
unsigned const reader_count=10;
|
||||
unsigned const writer_count=10;
|
||||
|
||||
try
|
||||
{
|
||||
for(unsigned i=0;i<reader_count;++i)
|
||||
{
|
||||
pool.create_thread(locking_thread<boost::shared_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
|
||||
finish_reading_mutex,simultaneous_running_readers,max_simultaneous_readers));
|
||||
}
|
||||
boost::thread::sleep(delay(1));
|
||||
for(unsigned i=0;i<writer_count;++i)
|
||||
{
|
||||
pool.create_thread(locking_thread<boost::unique_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
|
||||
finish_writing_mutex,simultaneous_running_writers,max_simultaneous_writers));
|
||||
}
|
||||
{
|
||||
boost::mutex::scoped_lock lk(unblocked_count_mutex);
|
||||
while(unblocked_count<reader_count)
|
||||
{
|
||||
unblocked_condition.wait(lk);
|
||||
}
|
||||
}
|
||||
boost::thread::sleep(delay(1));
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count);
|
||||
|
||||
finish_reading_lock.unlock();
|
||||
|
||||
{
|
||||
boost::mutex::scoped_lock lk(unblocked_count_mutex);
|
||||
while(unblocked_count<(reader_count+1))
|
||||
{
|
||||
unblocked_condition.wait(lk);
|
||||
}
|
||||
}
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+1);
|
||||
|
||||
finish_writing_lock.unlock();
|
||||
pool.join_all();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
pool.interrupt_all();
|
||||
pool.join_all();
|
||||
throw;
|
||||
}
|
||||
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+writer_count);
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_readers,reader_count);
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_writers,1u);
|
||||
}
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: shared_mutex test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(&test_multiple_readers));
|
||||
test->add(BOOST_TEST_CASE(&test_only_one_writer_permitted));
|
||||
test->add(BOOST_TEST_CASE(&test_reader_blocks_writer));
|
||||
test->add(BOOST_TEST_CASE(&test_unlocking_writer_unblocks_all_readers));
|
||||
test->add(BOOST_TEST_CASE(&test_unlocking_last_reader_only_unblocks_one_writer));
|
||||
|
||||
return test;
|
||||
}
|
||||
290
test/test_shared_mutex_part_2.cpp
Normal file
290
test/test_shared_mutex_part_2.cpp
Normal file
@@ -0,0 +1,290 @@
|
||||
// (C) Copyright 2006-7 Anthony Williams
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include "util.inl"
|
||||
#include "shared_mutex_locking_thread.hpp"
|
||||
|
||||
#define CHECK_LOCKED_VALUE_EQUAL(mutex_name,value,expected_value) \
|
||||
{ \
|
||||
boost::mutex::scoped_lock lock(mutex_name); \
|
||||
BOOST_CHECK_EQUAL(value,expected_value); \
|
||||
}
|
||||
|
||||
class simple_upgrade_thread
|
||||
{
|
||||
boost::shared_mutex& rwm;
|
||||
boost::mutex& finish_mutex;
|
||||
boost::mutex& unblocked_mutex;
|
||||
unsigned& unblocked_count;
|
||||
|
||||
void operator=(simple_upgrade_thread&);
|
||||
|
||||
public:
|
||||
simple_upgrade_thread(boost::shared_mutex& rwm_,
|
||||
boost::mutex& finish_mutex_,
|
||||
boost::mutex& unblocked_mutex_,
|
||||
unsigned& unblocked_count_):
|
||||
rwm(rwm_),finish_mutex(finish_mutex_),
|
||||
unblocked_mutex(unblocked_mutex_),unblocked_count(unblocked_count_)
|
||||
{}
|
||||
|
||||
void operator()()
|
||||
{
|
||||
boost::upgrade_lock<boost::shared_mutex> lk(rwm);
|
||||
|
||||
{
|
||||
boost::mutex::scoped_lock ulk(unblocked_mutex);
|
||||
++unblocked_count;
|
||||
}
|
||||
|
||||
boost::mutex::scoped_lock flk(finish_mutex);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void test_only_one_upgrade_lock_permitted()
|
||||
{
|
||||
unsigned const number_of_threads=10;
|
||||
|
||||
boost::thread_group pool;
|
||||
|
||||
boost::shared_mutex rw_mutex;
|
||||
unsigned unblocked_count=0;
|
||||
unsigned simultaneous_running_count=0;
|
||||
unsigned max_simultaneous_running=0;
|
||||
boost::mutex unblocked_count_mutex;
|
||||
boost::condition_variable unblocked_condition;
|
||||
boost::mutex finish_mutex;
|
||||
boost::mutex::scoped_lock finish_lock(finish_mutex);
|
||||
|
||||
try
|
||||
{
|
||||
for(unsigned i=0;i<number_of_threads;++i)
|
||||
{
|
||||
pool.create_thread(locking_thread<boost::upgrade_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
|
||||
finish_mutex,simultaneous_running_count,max_simultaneous_running));
|
||||
}
|
||||
|
||||
boost::thread::sleep(delay(1));
|
||||
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U);
|
||||
|
||||
finish_lock.unlock();
|
||||
|
||||
pool.join_all();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
pool.interrupt_all();
|
||||
pool.join_all();
|
||||
throw;
|
||||
}
|
||||
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,number_of_threads);
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,1u);
|
||||
}
|
||||
|
||||
void test_can_lock_upgrade_if_currently_locked_shared()
|
||||
{
|
||||
boost::thread_group pool;
|
||||
|
||||
boost::shared_mutex rw_mutex;
|
||||
unsigned unblocked_count=0;
|
||||
unsigned simultaneous_running_count=0;
|
||||
unsigned max_simultaneous_running=0;
|
||||
boost::mutex unblocked_count_mutex;
|
||||
boost::condition_variable unblocked_condition;
|
||||
boost::mutex finish_mutex;
|
||||
boost::mutex::scoped_lock finish_lock(finish_mutex);
|
||||
|
||||
unsigned const reader_count=10;
|
||||
|
||||
try
|
||||
{
|
||||
for(unsigned i=0;i<reader_count;++i)
|
||||
{
|
||||
pool.create_thread(locking_thread<boost::shared_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
|
||||
finish_mutex,simultaneous_running_count,max_simultaneous_running));
|
||||
}
|
||||
boost::thread::sleep(delay(1));
|
||||
pool.create_thread(locking_thread<boost::upgrade_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
|
||||
finish_mutex,simultaneous_running_count,max_simultaneous_running));
|
||||
{
|
||||
boost::mutex::scoped_lock lk(unblocked_count_mutex);
|
||||
while(unblocked_count<(reader_count+1))
|
||||
{
|
||||
unblocked_condition.wait(lk);
|
||||
}
|
||||
}
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+1);
|
||||
|
||||
finish_lock.unlock();
|
||||
pool.join_all();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
pool.interrupt_all();
|
||||
pool.join_all();
|
||||
throw;
|
||||
}
|
||||
|
||||
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+1);
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,reader_count+1);
|
||||
}
|
||||
|
||||
void test_if_other_thread_has_write_lock_try_lock_shared_returns_false()
|
||||
{
|
||||
|
||||
boost::shared_mutex rw_mutex;
|
||||
boost::mutex finish_mutex;
|
||||
boost::mutex unblocked_mutex;
|
||||
unsigned unblocked_count=0;
|
||||
boost::mutex::scoped_lock finish_lock(finish_mutex);
|
||||
boost::thread writer(simple_writing_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
|
||||
boost::this_thread::sleep(boost::posix_time::seconds(1));
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
|
||||
|
||||
bool const try_succeeded=rw_mutex.try_lock_shared();
|
||||
BOOST_CHECK(!try_succeeded);
|
||||
if(try_succeeded)
|
||||
{
|
||||
rw_mutex.unlock_shared();
|
||||
}
|
||||
|
||||
finish_lock.unlock();
|
||||
writer.join();
|
||||
}
|
||||
|
||||
void test_if_other_thread_has_write_lock_try_lock_upgrade_returns_false()
|
||||
{
|
||||
|
||||
boost::shared_mutex rw_mutex;
|
||||
boost::mutex finish_mutex;
|
||||
boost::mutex unblocked_mutex;
|
||||
unsigned unblocked_count=0;
|
||||
boost::mutex::scoped_lock finish_lock(finish_mutex);
|
||||
boost::thread writer(simple_writing_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
|
||||
boost::this_thread::sleep(boost::posix_time::seconds(1));
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
|
||||
|
||||
bool const try_succeeded=rw_mutex.try_lock_upgrade();
|
||||
BOOST_CHECK(!try_succeeded);
|
||||
if(try_succeeded)
|
||||
{
|
||||
rw_mutex.unlock_upgrade();
|
||||
}
|
||||
|
||||
finish_lock.unlock();
|
||||
writer.join();
|
||||
}
|
||||
|
||||
void test_if_no_thread_has_lock_try_lock_shared_returns_true()
|
||||
{
|
||||
boost::shared_mutex rw_mutex;
|
||||
bool const try_succeeded=rw_mutex.try_lock_shared();
|
||||
BOOST_CHECK(try_succeeded);
|
||||
if(try_succeeded)
|
||||
{
|
||||
rw_mutex.unlock_shared();
|
||||
}
|
||||
}
|
||||
|
||||
void test_if_no_thread_has_lock_try_lock_upgrade_returns_true()
|
||||
{
|
||||
boost::shared_mutex rw_mutex;
|
||||
bool const try_succeeded=rw_mutex.try_lock_upgrade();
|
||||
BOOST_CHECK(try_succeeded);
|
||||
if(try_succeeded)
|
||||
{
|
||||
rw_mutex.unlock_upgrade();
|
||||
}
|
||||
}
|
||||
|
||||
void test_if_other_thread_has_shared_lock_try_lock_shared_returns_true()
|
||||
{
|
||||
|
||||
boost::shared_mutex rw_mutex;
|
||||
boost::mutex finish_mutex;
|
||||
boost::mutex unblocked_mutex;
|
||||
unsigned unblocked_count=0;
|
||||
boost::mutex::scoped_lock finish_lock(finish_mutex);
|
||||
boost::thread writer(simple_reading_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
|
||||
boost::thread::sleep(delay(1));
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
|
||||
|
||||
bool const try_succeeded=rw_mutex.try_lock_shared();
|
||||
BOOST_CHECK(try_succeeded);
|
||||
if(try_succeeded)
|
||||
{
|
||||
rw_mutex.unlock_shared();
|
||||
}
|
||||
|
||||
finish_lock.unlock();
|
||||
writer.join();
|
||||
}
|
||||
|
||||
void test_if_other_thread_has_shared_lock_try_lock_upgrade_returns_true()
|
||||
{
|
||||
|
||||
boost::shared_mutex rw_mutex;
|
||||
boost::mutex finish_mutex;
|
||||
boost::mutex unblocked_mutex;
|
||||
unsigned unblocked_count=0;
|
||||
boost::mutex::scoped_lock finish_lock(finish_mutex);
|
||||
boost::thread writer(simple_reading_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
|
||||
boost::thread::sleep(delay(1));
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
|
||||
|
||||
bool const try_succeeded=rw_mutex.try_lock_upgrade();
|
||||
BOOST_CHECK(try_succeeded);
|
||||
if(try_succeeded)
|
||||
{
|
||||
rw_mutex.unlock_upgrade();
|
||||
}
|
||||
|
||||
finish_lock.unlock();
|
||||
writer.join();
|
||||
}
|
||||
|
||||
void test_if_other_thread_has_upgrade_lock_try_lock_upgrade_returns_false()
|
||||
{
|
||||
|
||||
boost::shared_mutex rw_mutex;
|
||||
boost::mutex finish_mutex;
|
||||
boost::mutex unblocked_mutex;
|
||||
unsigned unblocked_count=0;
|
||||
boost::mutex::scoped_lock finish_lock(finish_mutex);
|
||||
boost::thread writer(simple_upgrade_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
|
||||
boost::this_thread::sleep(boost::posix_time::seconds(1));
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
|
||||
|
||||
bool const try_succeeded=rw_mutex.try_lock_upgrade();
|
||||
BOOST_CHECK(!try_succeeded);
|
||||
if(try_succeeded)
|
||||
{
|
||||
rw_mutex.unlock_upgrade();
|
||||
}
|
||||
|
||||
finish_lock.unlock();
|
||||
writer.join();
|
||||
}
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: shared_mutex test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(&test_only_one_upgrade_lock_permitted));
|
||||
test->add(BOOST_TEST_CASE(&test_can_lock_upgrade_if_currently_locked_shared));
|
||||
test->add(BOOST_TEST_CASE(&test_if_other_thread_has_write_lock_try_lock_shared_returns_false));
|
||||
test->add(BOOST_TEST_CASE(&test_if_no_thread_has_lock_try_lock_shared_returns_true));
|
||||
test->add(BOOST_TEST_CASE(&test_if_other_thread_has_shared_lock_try_lock_shared_returns_true));
|
||||
|
||||
return test;
|
||||
}
|
||||
268
test/test_shared_mutex_timed_locks.cpp
Normal file
268
test/test_shared_mutex_timed_locks.cpp
Normal file
@@ -0,0 +1,268 @@
|
||||
// (C) Copyright 2006-7 Anthony Williams
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include "util.inl"
|
||||
#include "shared_mutex_locking_thread.hpp"
|
||||
|
||||
#define CHECK_LOCKED_VALUE_EQUAL(mutex_name,value,expected_value) \
|
||||
{ \
|
||||
boost::mutex::scoped_lock lock(mutex_name); \
|
||||
BOOST_CHECK_EQUAL(value,expected_value); \
|
||||
}
|
||||
|
||||
|
||||
void test_timed_lock_shared_times_out_if_write_lock_held()
|
||||
{
|
||||
boost::shared_mutex rw_mutex;
|
||||
boost::mutex finish_mutex;
|
||||
boost::mutex unblocked_mutex;
|
||||
unsigned unblocked_count=0;
|
||||
boost::mutex::scoped_lock finish_lock(finish_mutex);
|
||||
boost::thread writer(simple_writing_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
|
||||
boost::thread::sleep(delay(1));
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
|
||||
|
||||
boost::system_time const start=boost::get_system_time();
|
||||
boost::system_time const timeout=start+boost::posix_time::milliseconds(500);
|
||||
boost::posix_time::milliseconds const timeout_resolution(50);
|
||||
bool timed_lock_succeeded=rw_mutex.timed_lock_shared(timeout);
|
||||
BOOST_CHECK((timeout-timeout_resolution)<boost::get_system_time());
|
||||
BOOST_CHECK(!timed_lock_succeeded);
|
||||
if(timed_lock_succeeded)
|
||||
{
|
||||
rw_mutex.unlock_shared();
|
||||
}
|
||||
|
||||
boost::posix_time::milliseconds const wait_duration(500);
|
||||
boost::system_time const timeout2=boost::get_system_time()+wait_duration;
|
||||
timed_lock_succeeded=rw_mutex.timed_lock_shared(wait_duration);
|
||||
BOOST_CHECK((timeout2-timeout_resolution)<boost::get_system_time());
|
||||
BOOST_CHECK(!timed_lock_succeeded);
|
||||
if(timed_lock_succeeded)
|
||||
{
|
||||
rw_mutex.unlock_shared();
|
||||
}
|
||||
|
||||
finish_lock.unlock();
|
||||
writer.join();
|
||||
}
|
||||
|
||||
void test_timed_lock_shared_succeeds_if_no_lock_held()
|
||||
{
|
||||
boost::shared_mutex rw_mutex;
|
||||
boost::mutex finish_mutex;
|
||||
boost::mutex unblocked_mutex;
|
||||
|
||||
boost::system_time const start=boost::get_system_time();
|
||||
boost::system_time const timeout=start+boost::posix_time::milliseconds(500);
|
||||
boost::posix_time::milliseconds const timeout_resolution(50);
|
||||
bool timed_lock_succeeded=rw_mutex.timed_lock_shared(timeout);
|
||||
BOOST_CHECK(boost::get_system_time()<timeout);
|
||||
BOOST_CHECK(timed_lock_succeeded);
|
||||
if(timed_lock_succeeded)
|
||||
{
|
||||
rw_mutex.unlock_shared();
|
||||
}
|
||||
|
||||
boost::posix_time::milliseconds const wait_duration(500);
|
||||
boost::system_time const timeout2=boost::get_system_time()+wait_duration;
|
||||
timed_lock_succeeded=rw_mutex.timed_lock_shared(wait_duration);
|
||||
BOOST_CHECK(boost::get_system_time()<timeout2);
|
||||
BOOST_CHECK(timed_lock_succeeded);
|
||||
if(timed_lock_succeeded)
|
||||
{
|
||||
rw_mutex.unlock_shared();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void test_timed_lock_shared_succeeds_if_read_lock_held()
|
||||
{
|
||||
boost::shared_mutex rw_mutex;
|
||||
boost::mutex finish_mutex;
|
||||
boost::mutex unblocked_mutex;
|
||||
unsigned unblocked_count=0;
|
||||
boost::mutex::scoped_lock finish_lock(finish_mutex);
|
||||
boost::thread reader(simple_reading_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
|
||||
boost::thread::sleep(delay(1));
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
|
||||
|
||||
boost::system_time const start=boost::get_system_time();
|
||||
boost::system_time const timeout=start+boost::posix_time::milliseconds(500);
|
||||
boost::posix_time::milliseconds const timeout_resolution(50);
|
||||
bool timed_lock_succeeded=rw_mutex.timed_lock_shared(timeout);
|
||||
BOOST_CHECK(boost::get_system_time()<timeout);
|
||||
BOOST_CHECK(timed_lock_succeeded);
|
||||
if(timed_lock_succeeded)
|
||||
{
|
||||
rw_mutex.unlock_shared();
|
||||
}
|
||||
|
||||
boost::posix_time::milliseconds const wait_duration(500);
|
||||
boost::system_time const timeout2=boost::get_system_time()+wait_duration;
|
||||
timed_lock_succeeded=rw_mutex.timed_lock_shared(wait_duration);
|
||||
BOOST_CHECK(boost::get_system_time()<timeout2);
|
||||
BOOST_CHECK(timed_lock_succeeded);
|
||||
if(timed_lock_succeeded)
|
||||
{
|
||||
rw_mutex.unlock_shared();
|
||||
}
|
||||
|
||||
finish_lock.unlock();
|
||||
reader.join();
|
||||
}
|
||||
|
||||
void test_timed_lock_times_out_if_write_lock_held()
|
||||
{
|
||||
boost::shared_mutex rw_mutex;
|
||||
boost::mutex finish_mutex;
|
||||
boost::mutex unblocked_mutex;
|
||||
unsigned unblocked_count=0;
|
||||
boost::mutex::scoped_lock finish_lock(finish_mutex);
|
||||
boost::thread writer(simple_writing_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
|
||||
boost::thread::sleep(delay(1));
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
|
||||
|
||||
boost::system_time const start=boost::get_system_time();
|
||||
boost::system_time const timeout=start+boost::posix_time::milliseconds(500);
|
||||
boost::posix_time::milliseconds const timeout_resolution(50);
|
||||
bool timed_lock_succeeded=rw_mutex.timed_lock(timeout);
|
||||
BOOST_CHECK((timeout-timeout_resolution)<boost::get_system_time());
|
||||
BOOST_CHECK(!timed_lock_succeeded);
|
||||
if(timed_lock_succeeded)
|
||||
{
|
||||
rw_mutex.unlock();
|
||||
}
|
||||
|
||||
boost::posix_time::milliseconds const wait_duration(500);
|
||||
boost::system_time const timeout2=boost::get_system_time()+wait_duration;
|
||||
timed_lock_succeeded=rw_mutex.timed_lock(wait_duration);
|
||||
BOOST_CHECK((timeout2-timeout_resolution)<boost::get_system_time());
|
||||
BOOST_CHECK(!timed_lock_succeeded);
|
||||
if(timed_lock_succeeded)
|
||||
{
|
||||
rw_mutex.unlock();
|
||||
}
|
||||
|
||||
finish_lock.unlock();
|
||||
writer.join();
|
||||
}
|
||||
|
||||
void test_timed_lock_succeeds_if_no_lock_held()
|
||||
{
|
||||
boost::shared_mutex rw_mutex;
|
||||
boost::mutex finish_mutex;
|
||||
boost::mutex unblocked_mutex;
|
||||
|
||||
boost::system_time const start=boost::get_system_time();
|
||||
boost::system_time const timeout=start+boost::posix_time::milliseconds(500);
|
||||
boost::posix_time::milliseconds const timeout_resolution(50);
|
||||
bool timed_lock_succeeded=rw_mutex.timed_lock(timeout);
|
||||
BOOST_CHECK(boost::get_system_time()<timeout);
|
||||
BOOST_CHECK(timed_lock_succeeded);
|
||||
if(timed_lock_succeeded)
|
||||
{
|
||||
rw_mutex.unlock();
|
||||
}
|
||||
|
||||
boost::posix_time::milliseconds const wait_duration(500);
|
||||
boost::system_time const timeout2=boost::get_system_time()+wait_duration;
|
||||
timed_lock_succeeded=rw_mutex.timed_lock(wait_duration);
|
||||
BOOST_CHECK(boost::get_system_time()<timeout2);
|
||||
BOOST_CHECK(timed_lock_succeeded);
|
||||
if(timed_lock_succeeded)
|
||||
{
|
||||
rw_mutex.unlock();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void test_timed_lock_times_out_if_read_lock_held()
|
||||
{
|
||||
boost::shared_mutex rw_mutex;
|
||||
boost::mutex finish_mutex;
|
||||
boost::mutex unblocked_mutex;
|
||||
unsigned unblocked_count=0;
|
||||
boost::mutex::scoped_lock finish_lock(finish_mutex);
|
||||
boost::thread reader(simple_reading_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
|
||||
boost::thread::sleep(delay(1));
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
|
||||
|
||||
boost::system_time const start=boost::get_system_time();
|
||||
boost::system_time const timeout=start+boost::posix_time::milliseconds(500);
|
||||
boost::posix_time::milliseconds const timeout_resolution(50);
|
||||
bool timed_lock_succeeded=rw_mutex.timed_lock(timeout);
|
||||
BOOST_CHECK((timeout-timeout_resolution)<boost::get_system_time());
|
||||
BOOST_CHECK(!timed_lock_succeeded);
|
||||
if(timed_lock_succeeded)
|
||||
{
|
||||
rw_mutex.unlock();
|
||||
}
|
||||
|
||||
boost::posix_time::milliseconds const wait_duration(500);
|
||||
boost::system_time const timeout2=boost::get_system_time()+wait_duration;
|
||||
timed_lock_succeeded=rw_mutex.timed_lock(wait_duration);
|
||||
BOOST_CHECK((timeout2-timeout_resolution)<boost::get_system_time());
|
||||
BOOST_CHECK(!timed_lock_succeeded);
|
||||
if(timed_lock_succeeded)
|
||||
{
|
||||
rw_mutex.unlock();
|
||||
}
|
||||
|
||||
finish_lock.unlock();
|
||||
reader.join();
|
||||
}
|
||||
|
||||
void test_timed_lock_times_out_but_read_lock_succeeds_if_read_lock_held()
|
||||
{
|
||||
boost::shared_mutex rw_mutex;
|
||||
boost::mutex finish_mutex;
|
||||
boost::mutex unblocked_mutex;
|
||||
unsigned unblocked_count=0;
|
||||
boost::mutex::scoped_lock finish_lock(finish_mutex);
|
||||
boost::thread reader(simple_reading_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
|
||||
boost::this_thread::sleep(boost::posix_time::seconds(1));
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
|
||||
|
||||
boost::system_time const start=boost::get_system_time();
|
||||
boost::system_time const timeout=start+boost::posix_time::milliseconds(500);
|
||||
bool timed_lock_succeeded=rw_mutex.timed_lock(timeout);
|
||||
BOOST_CHECK(!timed_lock_succeeded);
|
||||
if(timed_lock_succeeded)
|
||||
{
|
||||
rw_mutex.unlock();
|
||||
}
|
||||
|
||||
boost::posix_time::milliseconds const wait_duration(500);
|
||||
timed_lock_succeeded=rw_mutex.timed_lock_shared(wait_duration);
|
||||
BOOST_CHECK(timed_lock_succeeded);
|
||||
if(timed_lock_succeeded)
|
||||
{
|
||||
rw_mutex.unlock_shared();
|
||||
}
|
||||
|
||||
finish_lock.unlock();
|
||||
reader.join();
|
||||
}
|
||||
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: shared_mutex test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(&test_timed_lock_shared_times_out_if_write_lock_held));
|
||||
test->add(BOOST_TEST_CASE(&test_timed_lock_shared_succeeds_if_no_lock_held));
|
||||
test->add(BOOST_TEST_CASE(&test_timed_lock_shared_succeeds_if_read_lock_held));
|
||||
test->add(BOOST_TEST_CASE(&test_timed_lock_times_out_if_write_lock_held));
|
||||
test->add(BOOST_TEST_CASE(&test_timed_lock_times_out_if_read_lock_held));
|
||||
test->add(BOOST_TEST_CASE(&test_timed_lock_succeeds_if_no_lock_held));
|
||||
test->add(BOOST_TEST_CASE(&test_timed_lock_times_out_but_read_lock_succeeds_if_read_lock_held));
|
||||
|
||||
return test;
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
// Copyright (C) 2008 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -8,6 +9,9 @@
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/ref.hpp>
|
||||
#include <boost/utility.hpp>
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
@@ -21,12 +25,16 @@ void simple_thread()
|
||||
test_value = 999;
|
||||
}
|
||||
|
||||
void comparison_thread(boost::thread* parent)
|
||||
void comparison_thread(boost::thread::id parent)
|
||||
{
|
||||
boost::thread thrd;
|
||||
BOOST_CHECK(thrd != *parent);
|
||||
boost::thread thrd2;
|
||||
BOOST_CHECK(thrd == thrd2);
|
||||
boost::thread::id const my_id=boost::this_thread::get_id();
|
||||
|
||||
BOOST_CHECK(my_id != parent);
|
||||
boost::thread::id const my_id2=boost::this_thread::get_id();
|
||||
BOOST_CHECK(my_id == my_id2);
|
||||
|
||||
boost::thread::id const no_thread_id=boost::thread::id();
|
||||
BOOST_CHECK(my_id != no_thread_id);
|
||||
}
|
||||
|
||||
void test_sleep()
|
||||
@@ -52,18 +60,162 @@ void test_creation()
|
||||
timed_test(&do_test_creation, 1);
|
||||
}
|
||||
|
||||
void do_test_comparison()
|
||||
void do_test_id_comparison()
|
||||
{
|
||||
boost::thread self;
|
||||
boost::thread thrd(bind(&comparison_thread, &self));
|
||||
boost::thread::id const self=boost::this_thread::get_id();
|
||||
boost::thread thrd(boost::bind(&comparison_thread, self));
|
||||
thrd.join();
|
||||
}
|
||||
|
||||
void test_comparison()
|
||||
void test_id_comparison()
|
||||
{
|
||||
timed_test(&do_test_comparison, 1);
|
||||
timed_test(&do_test_id_comparison, 1);
|
||||
}
|
||||
|
||||
void interruption_point_thread(boost::mutex* m,bool* failed)
|
||||
{
|
||||
boost::mutex::scoped_lock lk(*m);
|
||||
boost::this_thread::interruption_point();
|
||||
*failed=true;
|
||||
}
|
||||
|
||||
void do_test_thread_interrupts_at_interruption_point()
|
||||
{
|
||||
boost::mutex m;
|
||||
bool failed=false;
|
||||
boost::mutex::scoped_lock lk(m);
|
||||
boost::thread thrd(boost::bind(&interruption_point_thread,&m,&failed));
|
||||
thrd.interrupt();
|
||||
lk.unlock();
|
||||
thrd.join();
|
||||
BOOST_CHECK(!failed);
|
||||
}
|
||||
|
||||
void test_thread_interrupts_at_interruption_point()
|
||||
{
|
||||
timed_test(&do_test_thread_interrupts_at_interruption_point, 1);
|
||||
}
|
||||
|
||||
void disabled_interruption_point_thread(boost::mutex* m,bool* failed)
|
||||
{
|
||||
boost::mutex::scoped_lock lk(*m);
|
||||
boost::this_thread::disable_interruption dc;
|
||||
boost::this_thread::interruption_point();
|
||||
*failed=false;
|
||||
}
|
||||
|
||||
void do_test_thread_no_interrupt_if_interrupts_disabled_at_interruption_point()
|
||||
{
|
||||
boost::mutex m;
|
||||
bool failed=true;
|
||||
boost::mutex::scoped_lock lk(m);
|
||||
boost::thread thrd(boost::bind(&disabled_interruption_point_thread,&m,&failed));
|
||||
thrd.interrupt();
|
||||
lk.unlock();
|
||||
thrd.join();
|
||||
BOOST_CHECK(!failed);
|
||||
}
|
||||
|
||||
void test_thread_no_interrupt_if_interrupts_disabled_at_interruption_point()
|
||||
{
|
||||
timed_test(&do_test_thread_no_interrupt_if_interrupts_disabled_at_interruption_point, 1);
|
||||
}
|
||||
|
||||
struct non_copyable_functor:
|
||||
boost::noncopyable
|
||||
{
|
||||
unsigned value;
|
||||
|
||||
non_copyable_functor():
|
||||
value(0)
|
||||
{}
|
||||
|
||||
void operator()()
|
||||
{
|
||||
value=999;
|
||||
}
|
||||
};
|
||||
|
||||
void do_test_creation_through_reference_wrapper()
|
||||
{
|
||||
non_copyable_functor f;
|
||||
|
||||
boost::thread thrd(boost::ref(f));
|
||||
thrd.join();
|
||||
BOOST_CHECK_EQUAL(f.value, 999u);
|
||||
}
|
||||
|
||||
void test_creation_through_reference_wrapper()
|
||||
{
|
||||
timed_test(&do_test_creation_through_reference_wrapper, 1);
|
||||
}
|
||||
|
||||
struct long_running_thread
|
||||
{
|
||||
boost::condition_variable cond;
|
||||
boost::mutex mut;
|
||||
bool done;
|
||||
|
||||
long_running_thread():
|
||||
done(false)
|
||||
{}
|
||||
|
||||
void operator()()
|
||||
{
|
||||
boost::mutex::scoped_lock lk(mut);
|
||||
while(!done)
|
||||
{
|
||||
cond.wait(lk);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void do_test_timed_join()
|
||||
{
|
||||
long_running_thread f;
|
||||
boost::thread thrd(boost::ref(f));
|
||||
BOOST_CHECK(thrd.joinable());
|
||||
boost::system_time xt=delay(3);
|
||||
bool const joined=thrd.timed_join(xt);
|
||||
BOOST_CHECK(in_range(boost::get_xtime(xt), 2));
|
||||
BOOST_CHECK(!joined);
|
||||
BOOST_CHECK(thrd.joinable());
|
||||
{
|
||||
boost::mutex::scoped_lock lk(f.mut);
|
||||
f.done=true;
|
||||
f.cond.notify_one();
|
||||
}
|
||||
|
||||
xt=delay(3);
|
||||
bool const joined2=thrd.timed_join(xt);
|
||||
boost::system_time const now=boost::get_system_time();
|
||||
BOOST_CHECK(xt>now);
|
||||
BOOST_CHECK(joined2);
|
||||
BOOST_CHECK(!thrd.joinable());
|
||||
}
|
||||
|
||||
void test_timed_join()
|
||||
{
|
||||
timed_test(&do_test_timed_join, 10);
|
||||
}
|
||||
|
||||
void test_swap()
|
||||
{
|
||||
boost::thread t(simple_thread);
|
||||
boost::thread t2(simple_thread);
|
||||
boost::thread::id id1=t.get_id();
|
||||
boost::thread::id id2=t2.get_id();
|
||||
|
||||
t.swap(t2);
|
||||
BOOST_CHECK(t.get_id()==id2);
|
||||
BOOST_CHECK(t2.get_id()==id1);
|
||||
|
||||
swap(t,t2);
|
||||
BOOST_CHECK(t.get_id()==id1);
|
||||
BOOST_CHECK(t2.get_id()==id2);
|
||||
}
|
||||
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
@@ -71,7 +223,12 @@ boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
|
||||
test->add(BOOST_TEST_CASE(test_sleep));
|
||||
test->add(BOOST_TEST_CASE(test_creation));
|
||||
test->add(BOOST_TEST_CASE(test_comparison));
|
||||
test->add(BOOST_TEST_CASE(test_id_comparison));
|
||||
test->add(BOOST_TEST_CASE(test_thread_interrupts_at_interruption_point));
|
||||
test->add(BOOST_TEST_CASE(test_thread_no_interrupt_if_interrupts_disabled_at_interruption_point));
|
||||
test->add(BOOST_TEST_CASE(test_creation_through_reference_wrapper));
|
||||
test->add(BOOST_TEST_CASE(test_timed_join));
|
||||
test->add(BOOST_TEST_CASE(test_swap));
|
||||
|
||||
return test;
|
||||
}
|
||||
|
||||
149
test/test_thread_id.cpp
Normal file
149
test/test_thread_id.cpp
Normal file
@@ -0,0 +1,149 @@
|
||||
// Copyright (C) 2007 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
void do_nothing()
|
||||
{}
|
||||
|
||||
void test_thread_id_for_default_constructed_thread_is_default_constructed_id()
|
||||
{
|
||||
boost::thread t;
|
||||
BOOST_CHECK(t.get_id()==boost::thread::id());
|
||||
}
|
||||
|
||||
void test_thread_id_for_running_thread_is_not_default_constructed_id()
|
||||
{
|
||||
boost::thread t(do_nothing);
|
||||
BOOST_CHECK(t.get_id()!=boost::thread::id());
|
||||
t.join();
|
||||
}
|
||||
|
||||
void test_different_threads_have_different_ids()
|
||||
{
|
||||
boost::thread t(do_nothing);
|
||||
boost::thread t2(do_nothing);
|
||||
BOOST_CHECK(t.get_id()!=t2.get_id());
|
||||
t.join();
|
||||
t2.join();
|
||||
}
|
||||
|
||||
void test_thread_ids_have_a_total_order()
|
||||
{
|
||||
boost::thread t(do_nothing);
|
||||
boost::thread t2(do_nothing);
|
||||
boost::thread t3(do_nothing);
|
||||
BOOST_CHECK(t.get_id()!=t2.get_id());
|
||||
BOOST_CHECK(t.get_id()!=t3.get_id());
|
||||
BOOST_CHECK(t2.get_id()!=t3.get_id());
|
||||
|
||||
BOOST_CHECK((t.get_id()<t2.get_id()) != (t2.get_id()<t.get_id()));
|
||||
BOOST_CHECK((t.get_id()<t3.get_id()) != (t3.get_id()<t.get_id()));
|
||||
BOOST_CHECK((t2.get_id()<t3.get_id()) != (t3.get_id()<t2.get_id()));
|
||||
|
||||
BOOST_CHECK((t.get_id()>t2.get_id()) != (t2.get_id()>t.get_id()));
|
||||
BOOST_CHECK((t.get_id()>t3.get_id()) != (t3.get_id()>t.get_id()));
|
||||
BOOST_CHECK((t2.get_id()>t3.get_id()) != (t3.get_id()>t2.get_id()));
|
||||
|
||||
BOOST_CHECK((t.get_id()<t2.get_id()) == (t2.get_id()>t.get_id()));
|
||||
BOOST_CHECK((t2.get_id()<t.get_id()) == (t.get_id()>t2.get_id()));
|
||||
BOOST_CHECK((t.get_id()<t3.get_id()) == (t3.get_id()>t.get_id()));
|
||||
BOOST_CHECK((t3.get_id()<t.get_id()) == (t.get_id()>t3.get_id()));
|
||||
BOOST_CHECK((t2.get_id()<t3.get_id()) == (t3.get_id()>t2.get_id()));
|
||||
BOOST_CHECK((t3.get_id()<t2.get_id()) == (t2.get_id()>t3.get_id()));
|
||||
|
||||
BOOST_CHECK((t.get_id()<t2.get_id()) == (t2.get_id()>=t.get_id()));
|
||||
BOOST_CHECK((t2.get_id()<t.get_id()) == (t.get_id()>=t2.get_id()));
|
||||
BOOST_CHECK((t.get_id()<t3.get_id()) == (t3.get_id()>=t.get_id()));
|
||||
BOOST_CHECK((t3.get_id()<t.get_id()) == (t.get_id()>=t3.get_id()));
|
||||
BOOST_CHECK((t2.get_id()<t3.get_id()) == (t3.get_id()>=t2.get_id()));
|
||||
BOOST_CHECK((t3.get_id()<t2.get_id()) == (t2.get_id()>=t3.get_id()));
|
||||
|
||||
BOOST_CHECK((t.get_id()<=t2.get_id()) == (t2.get_id()>t.get_id()));
|
||||
BOOST_CHECK((t2.get_id()<=t.get_id()) == (t.get_id()>t2.get_id()));
|
||||
BOOST_CHECK((t.get_id()<=t3.get_id()) == (t3.get_id()>t.get_id()));
|
||||
BOOST_CHECK((t3.get_id()<=t.get_id()) == (t.get_id()>t3.get_id()));
|
||||
BOOST_CHECK((t2.get_id()<=t3.get_id()) == (t3.get_id()>t2.get_id()));
|
||||
BOOST_CHECK((t3.get_id()<=t2.get_id()) == (t2.get_id()>t3.get_id()));
|
||||
|
||||
if((t.get_id()<t2.get_id()) && (t2.get_id()<t3.get_id()))
|
||||
{
|
||||
BOOST_CHECK(t.get_id()<t3.get_id());
|
||||
}
|
||||
else if((t.get_id()<t3.get_id()) && (t3.get_id()<t2.get_id()))
|
||||
{
|
||||
BOOST_CHECK(t.get_id()<t2.get_id());
|
||||
}
|
||||
else if((t2.get_id()<t3.get_id()) && (t3.get_id()<t.get_id()))
|
||||
{
|
||||
BOOST_CHECK(t2.get_id()<t.get_id());
|
||||
}
|
||||
else if((t2.get_id()<t.get_id()) && (t.get_id()<t3.get_id()))
|
||||
{
|
||||
BOOST_CHECK(t2.get_id()<t3.get_id());
|
||||
}
|
||||
else if((t3.get_id()<t.get_id()) && (t.get_id()<t2.get_id()))
|
||||
{
|
||||
BOOST_CHECK(t3.get_id()<t2.get_id());
|
||||
}
|
||||
else if((t3.get_id()<t2.get_id()) && (t2.get_id()<t.get_id()))
|
||||
{
|
||||
BOOST_CHECK(t3.get_id()<t.get_id());
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_CHECK(false);
|
||||
}
|
||||
|
||||
boost::thread::id default_id;
|
||||
|
||||
BOOST_CHECK(default_id < t.get_id());
|
||||
BOOST_CHECK(default_id < t2.get_id());
|
||||
BOOST_CHECK(default_id < t3.get_id());
|
||||
|
||||
BOOST_CHECK(default_id <= t.get_id());
|
||||
BOOST_CHECK(default_id <= t2.get_id());
|
||||
BOOST_CHECK(default_id <= t3.get_id());
|
||||
|
||||
BOOST_CHECK(!(default_id > t.get_id()));
|
||||
BOOST_CHECK(!(default_id > t2.get_id()));
|
||||
BOOST_CHECK(!(default_id > t3.get_id()));
|
||||
|
||||
BOOST_CHECK(!(default_id >= t.get_id()));
|
||||
BOOST_CHECK(!(default_id >= t2.get_id()));
|
||||
BOOST_CHECK(!(default_id >= t3.get_id()));
|
||||
|
||||
t.join();
|
||||
t2.join();
|
||||
t3.join();
|
||||
}
|
||||
|
||||
void get_thread_id(boost::thread::id* id)
|
||||
{
|
||||
*id=boost::this_thread::get_id();
|
||||
}
|
||||
|
||||
void test_thread_id_of_running_thread_returned_by_this_thread_get_id()
|
||||
{
|
||||
boost::thread::id id;
|
||||
boost::thread t(boost::bind(get_thread_id,&id));
|
||||
boost::thread::id t_id=t.get_id();
|
||||
t.join();
|
||||
BOOST_CHECK(id==t_id);
|
||||
}
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: thread move test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(test_thread_id_for_default_constructed_thread_is_default_constructed_id));
|
||||
test->add(BOOST_TEST_CASE(test_thread_id_for_running_thread_is_not_default_constructed_id));
|
||||
test->add(BOOST_TEST_CASE(test_different_threads_have_different_ids));
|
||||
test->add(BOOST_TEST_CASE(test_thread_ids_have_a_total_order));
|
||||
test->add(BOOST_TEST_CASE(test_thread_id_of_running_thread_returned_by_this_thread_get_id));
|
||||
return test;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user