mirror of
https://github.com/boostorg/thread.git
synced 2026-02-17 02:02:08 +00:00
Compare commits
474 Commits
boost-1.25
...
svn-branch
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c484c376d3 | ||
|
|
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 | ||
|
|
58d5110e61 | ||
|
|
76e53c7bc5 | ||
|
|
cfb08be1a8 | ||
|
|
b5bbb7fb1c | ||
|
|
a76c33f8cc | ||
|
|
810306b8f3 | ||
|
|
6c22bdb3bd | ||
|
|
6a0d3e98bc | ||
|
|
3809321037 | ||
|
|
eef695bdf0 | ||
|
|
ab01ab1e4d | ||
|
|
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 | ||
|
|
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 | ||
|
|
2918732481 | ||
|
|
5a4d5ddb9d | ||
|
|
55afcf678d | ||
|
|
16c7cf9b5e | ||
|
|
432bd29c1c | ||
|
|
a87914ef23 | ||
|
|
041530a953 | ||
|
|
9d4c55161a | ||
|
|
a706d1df00 | ||
|
|
b15b2e666f | ||
|
|
5d4678364e | ||
|
|
9590526430 | ||
|
|
1c6dfda83c | ||
|
|
a8be12940e | ||
|
|
4b5046366b | ||
|
|
a0fff90c26 | ||
|
|
a8daedac5e | ||
|
|
5fa26fb3ac | ||
|
|
ea3e297175 | ||
|
|
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 | ||
|
|
720ccdb474 | ||
|
|
a556ff6560 | ||
|
|
33c0af8253 | ||
|
|
86072f95ac | ||
|
|
c7b96bcd7d | ||
|
|
572c18302f | ||
|
|
efd1bdec23 | ||
|
|
ba86f9ff13 | ||
|
|
56b07cb5c0 | ||
|
|
358e32e98f | ||
|
|
01297016bd | ||
|
|
64b5b67661 | ||
|
|
b6f0ec7fd9 | ||
|
|
e9c0b5e0c5 | ||
|
|
4a005ea288 | ||
|
|
9658b69af4 | ||
|
|
e3c9446e29 | ||
|
|
aa240e61d9 | ||
|
|
2954e932ce | ||
|
|
5be79cc858 | ||
|
|
4a9d97d22d | ||
|
|
f4f3433854 | ||
|
|
26bffa3740 | ||
|
|
69e52a9882 | ||
|
|
cc8de48849 | ||
|
|
9d7c119f94 | ||
|
|
6ba9fd1b60 | ||
|
|
fb6250eb94 | ||
|
|
bc73368c96 | ||
|
|
3068f0c62c | ||
|
|
8e00803c83 | ||
|
|
087b69b629 | ||
|
|
3b237267fb | ||
|
|
b9dbb1ed45 | ||
|
|
41d3b29ec0 | ||
|
|
05ceb8b1e2 | ||
|
|
80d3925b8d | ||
|
|
2cd6cbeacc | ||
|
|
6382846f6c | ||
|
|
349d0fd74b | ||
|
|
9c88855bf4 | ||
|
|
f0e6cdfcb5 | ||
|
|
af9864a1b5 | ||
|
|
8ac145e667 | ||
|
|
39f7afc7d0 | ||
|
|
113b974bb7 | ||
|
|
c747a6ff4e | ||
|
|
107d11cfd5 | ||
|
|
a4d2cd94b9 | ||
|
|
3d9fb84fc9 | ||
|
|
e500bc075e | ||
|
|
25e8fa0e11 | ||
|
|
5f27fb2607 | ||
|
|
d977cedb78 | ||
|
|
454b58cdf0 | ||
|
|
82a632b0f9 | ||
|
|
43cbe3f1f8 | ||
|
|
d027cec8a6 | ||
|
|
e53c2c52ee | ||
|
|
5ff0ecc12d | ||
|
|
9c1f421ccb | ||
|
|
66850bc057 | ||
|
|
33da34b4bf | ||
|
|
792cd49310 | ||
|
|
37fdb5e2b0 | ||
|
|
88cd251db7 | ||
|
|
4038d18fc8 | ||
|
|
59bf92a183 | ||
|
|
57879155d2 | ||
|
|
96d43cebc0 | ||
|
|
8e13857b29 | ||
|
|
8c6e454697 | ||
|
|
4c7c7df89b | ||
|
|
515e6d8635 | ||
|
|
bbd941e2df | ||
|
|
3edba1bf19 | ||
|
|
4ad99d8242 | ||
|
|
c0aeaecc14 | ||
|
|
792be9e687 | ||
|
|
fd65337f43 | ||
|
|
9de9726e6f | ||
|
|
522037ca4a | ||
|
|
8fc3d1f718 | ||
|
|
cebaf27ee8 | ||
|
|
b62503f274 | ||
|
|
af50c640ab | ||
|
|
b5c5fbe0f5 | ||
|
|
b88ae8105e | ||
|
|
9ad04bb65e | ||
|
|
13bbaab1c4 | ||
|
|
09ca8d1728 | ||
|
|
9797a93d86 | ||
|
|
d29dae72de | ||
|
|
59fba2bff6 | ||
|
|
0350d4c501 | ||
|
|
d3e4a90e70 | ||
|
|
8ebb19fd18 | ||
|
|
02ddc33e6c | ||
|
|
410e8efeba | ||
|
|
e9f8e0bad9 | ||
|
|
f69e0313dc | ||
|
|
baa9b396d9 | ||
|
|
a82b0c516d | ||
|
|
43e2192aa2 | ||
|
|
4cd6453cac | ||
|
|
921d4c24c2 | ||
|
|
4fc7653b12 | ||
|
|
9d0e39a7c2 | ||
|
|
7aa979cf5b | ||
|
|
0aa50614d7 | ||
|
|
6f402c7362 | ||
|
|
2bf43a124d | ||
|
|
3573c53eda | ||
|
|
4546ec4ef7 | ||
|
|
2f7337aaf6 | ||
|
|
046698bcc2 | ||
|
|
06d7bf21d5 | ||
|
|
e7b9ccdf10 | ||
|
|
1e15b043a0 | ||
|
|
6c5f3d76e2 | ||
|
|
8679d6f6af | ||
|
|
f1c7d0f354 | ||
|
|
261e413500 | ||
|
|
094e41d7a7 | ||
|
|
e20299c8ee | ||
|
|
f8962b7ad2 | ||
|
|
c34f829c3e | ||
|
|
46264e4a4a | ||
|
|
096df68ea6 | ||
|
|
35f2055a1e | ||
|
|
e1353eefb3 | ||
|
|
4911a532bf | ||
|
|
96362e03aa | ||
|
|
049b4e09fe | ||
|
|
828c0e28af | ||
|
|
15a638edc0 | ||
|
|
fc8f1b1075 | ||
|
|
318a8e38c9 | ||
|
|
f0dbb02a9f | ||
|
|
649b777b76 | ||
|
|
6fad43670a | ||
|
|
e24b16229e | ||
|
|
21b4b81810 | ||
|
|
1096b1e28e | ||
|
|
03458fedef | ||
|
|
c1a2004344 | ||
|
|
2adb13a209 | ||
|
|
dba194ddb9 | ||
|
|
8179f041e6 | ||
|
|
a13c7a4d84 | ||
|
|
bbf92bb971 | ||
|
|
b33f413635 | ||
|
|
58ffb2bc16 | ||
|
|
0ed112631c | ||
|
|
9cfe8e9422 | ||
|
|
7d3fe72970 | ||
|
|
ac422138fa | ||
|
|
bf8746454a | ||
|
|
b61aa5b4ba | ||
|
|
c2bcd08168 | ||
|
|
48593b8868 | ||
|
|
83d4dc1831 | ||
|
|
0696f3cc41 | ||
|
|
515590495a | ||
|
|
7221bca909 | ||
|
|
ed64a8cd12 | ||
|
|
cbd30d22ff | ||
|
|
0c74dbd436 | ||
|
|
49356cc931 | ||
|
|
ceee6e8b17 | ||
|
|
61ab2754d2 | ||
|
|
2de3df61e8 | ||
|
|
b84d7aa06d | ||
|
|
ed48f900a3 | ||
|
|
d197a49707 | ||
|
|
b8ccaa3bf6 | ||
|
|
507a684b21 | ||
|
|
c969c9387a | ||
|
|
1709db4953 | ||
|
|
4d1c9ba316 | ||
|
|
45b0396355 | ||
|
|
1df2169e48 | ||
|
|
2c056b3621 | ||
|
|
680119006c | ||
|
|
c4ac4b7538 | ||
|
|
ff5d3b49ca | ||
|
|
e101c878f0 | ||
|
|
125193dcfa | ||
|
|
77efa9810d | ||
|
|
7f03d1917b | ||
|
|
55b4ca9350 | ||
|
|
7196a0f9d2 | ||
|
|
2caabde5ca | ||
|
|
137d7663c1 | ||
|
|
508b71a921 | ||
|
|
5d90820005 | ||
|
|
84727e90b1 | ||
|
|
9a1e3d3320 | ||
|
|
d33e0c8ee1 | ||
|
|
3332649480 | ||
|
|
c918b66199 | ||
|
|
dbbf56e17a | ||
|
|
c77500c15a | ||
|
|
75084aaa96 | ||
|
|
35714c8f1c | ||
|
|
3699cc97a6 | ||
|
|
5a7377acda | ||
|
|
6aaee629b5 | ||
|
|
b465fe569c | ||
|
|
5e6f72a688 | ||
|
|
51f80f6c15 | ||
|
|
45c314e594 | ||
|
|
cfce0892e0 | ||
|
|
05d1abf030 | ||
|
|
6c24a2626b | ||
|
|
870c75bd12 | ||
|
|
5fdd771708 | ||
|
|
06f39ac409 | ||
|
|
c92b0a2fb7 | ||
|
|
8a8d0e05ca | ||
|
|
74bae2baac | ||
|
|
4ba48676bd | ||
|
|
78480e7951 | ||
|
|
4cb9c412e8 | ||
|
|
75c83fed96 | ||
|
|
391de20ae0 | ||
|
|
1e2a9e8971 | ||
|
|
43cbd3a283 | ||
|
|
31cf6b5e64 | ||
|
|
99109ab78b | ||
|
|
a80d5f159d | ||
|
|
7ba4fc4aed | ||
|
|
9fb31e9868 | ||
|
|
3a2246de5b | ||
|
|
e7c4e2fa57 | ||
|
|
724ab285f0 | ||
|
|
d60e66fb00 | ||
|
|
97cdaca028 | ||
|
|
3044c8f905 | ||
|
|
2775a2a945 | ||
|
|
c43c1febba | ||
|
|
ceb6471d57 | ||
|
|
b99cc044f3 | ||
|
|
d91429dcec | ||
|
|
b1d1f7d8f1 | ||
|
|
86b608cf41 | ||
|
|
f263f75751 | ||
|
|
24bec05b86 | ||
|
|
ce1a5e9359 | ||
|
|
311525bc06 | ||
|
|
ecdfd96529 | ||
|
|
5aab32bc1a | ||
|
|
e152a1c6f2 | ||
|
|
e84fde78ec | ||
|
|
6ec4652bcf | ||
|
|
a5239c820b | ||
|
|
41b001b22c | ||
|
|
34e903b8b0 | ||
|
|
2b67e953fd | ||
|
|
aa0d3adf1d | ||
|
|
a1f57a8a80 | ||
|
|
6bc82a8580 | ||
|
|
c4c2e5d3a2 | ||
|
|
dd7d4b2173 |
@@ -1,49 +0,0 @@
|
|||||||
# (C) Copyright William E. Kempf 2001. Permission to copy, use, modify, sell and
|
|
||||||
# distribute this software is granted provided this copyright notice appears
|
|
||||||
# in all copies. This software is provided "as is" without express or implied
|
|
||||||
# warranty, and with no claim as to its suitability for any purpose.
|
|
||||||
#
|
|
||||||
# Boost.Threads build and test Jamfile
|
|
||||||
#
|
|
||||||
# Declares the following targets:
|
|
||||||
# 1. libboost_thread, a static link library.
|
|
||||||
# 1a. On Win32, a dynamic link library libboost_threadmon,
|
|
||||||
# which must be used in conjunction with libboost_thread.
|
|
||||||
|
|
||||||
# declare the location of this subproject relative to the root
|
|
||||||
subproject libs/thread/build ;
|
|
||||||
|
|
||||||
#######################
|
|
||||||
|
|
||||||
#
|
|
||||||
# Declare the Boost.Threads static link library.
|
|
||||||
#
|
|
||||||
|
|
||||||
# For Win32 we need to build a special DLL, libboost_threadmon, to handle
|
|
||||||
# TSS destruction.
|
|
||||||
if $(NT)
|
|
||||||
{
|
|
||||||
if $(PTW32)
|
|
||||||
{
|
|
||||||
PTW32_REQUIREMENTS = <define>BOOST_HAS_PTHREADS <define>PtW32NoCatchWarn ;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dll libboost_threadmon : ../src/threadmon.cpp
|
|
||||||
# requirements
|
|
||||||
: <include>$(BOOST_ROOT)
|
|
||||||
<threading>multi
|
|
||||||
: debug release ;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Base names of the source files for libboost_thread
|
|
||||||
CPP_SOURCES =
|
|
||||||
condition mutex recursive_mutex thread tss xtime once exceptions ;
|
|
||||||
|
|
||||||
lib libboost_thread : ../src/$(CPP_SOURCES).cpp
|
|
||||||
# requirements
|
|
||||||
: <include>$(BOOST_ROOT)
|
|
||||||
$(PTW32_REQUIREMENTS)
|
|
||||||
<threading>multi
|
|
||||||
: debug release ;
|
|
||||||
208
build/Jamfile.v2
Normal file
208
build/Jamfile.v2
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
# $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 <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
|
||||||
|
;
|
||||||
|
|
||||||
|
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
|
||||||
|
: thread_sources
|
||||||
|
: <conditional>@requirements
|
||||||
|
:
|
||||||
|
: <link>shared:<define>BOOST_THREAD_USE_DLL=1
|
||||||
|
<link>static:<define>BOOST_THREAD_USE_LIB=1
|
||||||
|
<conditional>@usage-requirements
|
||||||
|
;
|
||||||
55
doc/Jamfile.v2
Normal file
55
doc/Jamfile.v2
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
# (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)
|
||||||
|
|
||||||
|
path-constant boost-images : ../../../doc/src/images ;
|
||||||
|
|
||||||
|
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)/
|
||||||
|
;
|
||||||
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content=
|
|
||||||
"text/html; charset=windows-1252">
|
|
||||||
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
|
|
||||||
<meta name="ProgId" content="FrontPage.Editor.Document">
|
|
||||||
|
|
||||||
<title>Boost.Threads Acknowledgements</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body bgcolor="#FFFFFF" text="#000000">
|
|
||||||
<table summary="header" border="0" cellpadding="7" cellspacing="0"
|
|
||||||
width="100%">
|
|
||||||
<tr>
|
|
||||||
<td valign="top" width="300">
|
|
||||||
<h3><img src="../../../c++boost.gif" alt="C++ Boost" width=
|
|
||||||
"277" height="86"></h3>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td valign="top">
|
|
||||||
<h1 align="center">Boost.Threads</h1>
|
|
||||||
|
|
||||||
<h2 align="center">Acknowledgements</h2>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<h2>Acknowledgments</h2>
|
|
||||||
|
|
||||||
<p><a href="../../../people/william_kempf.htm">William E. Kempf</a> was
|
|
||||||
the architect, designer, and implementor of <b>Boost.Threads</b>.</p>
|
|
||||||
|
|
||||||
<p>Important contributions were also made by Jeremy Siek (lots of input
|
|
||||||
on the design and on the implementation), Alexander Terekhov (lots of
|
|
||||||
input on the Win32 implementation, especially in regards to
|
|
||||||
boost::condition, as well as a lot of explanation of POSIX behavior),
|
|
||||||
Greg Colvin (lots of input on the design), and Paul Mclachlan, Thomas
|
|
||||||
Matelich and Iain Hanson (for help in trying to get the build to work
|
|
||||||
on other platforms).</p>
|
|
||||||
|
|
||||||
<p>The documentation was written by William E. Kempf. Beman Dawes
|
|
||||||
provided additional documentation material and editing.</p>
|
|
||||||
|
|
||||||
<p>Discussions on the boost.org mailing list were essential in the
|
|
||||||
development of <b>Boost.Threads</b>. As of August 1, 2001, participants
|
|
||||||
included Alan Griffiths, Albrecht Fritzsche, Aleksey Gurtovoy,
|
|
||||||
Alexander Terekhov, Andrew Green, Andy Sawyer, Asger Alstrup Nielsen,
|
|
||||||
Beman Dawes, Bill Klein, Bill Rutiser, Bill Wade, Branko Èibej,
|
|
||||||
Brent Verner, Craig Henderson, Csaba Szepesvari, Dale Peakall, Damian
|
|
||||||
Dixon, Dan Nuffer, Darryl Green, Daryle Walker, David Abrahams, David
|
|
||||||
Allan Finch, Dejan Jelovic, Dietmar Kuehl, Doug Gregor, Douglas Gregor,
|
|
||||||
Duncan Harris, Ed Brey, Eric Swanson, Eugene Karpachov, Fabrice
|
|
||||||
Truillot, Frank Gerlach, Gary Powell, Gernot Neppert, Geurt Vos, Ghazi
|
|
||||||
Ramadan, Greg Colvin, Gregory Seidman, HYS, Iain Hanson, Ian Bruntlett,
|
|
||||||
J Panzer, Jeff Garland, Jeff Paquette, Jens Maurer, Jeremy Siek, Jesse
|
|
||||||
Jones, Joe Gottman, John (EBo) David, John Bandela, John Maddock, John
|
|
||||||
Max Skaller, John Panzer, Jon Jagger , Karl Nelson, Kevlin Henney, KG
|
|
||||||
Chandrasekhar, Levente Farkas, Lie-Quan Lee, Lois Goldthwaite, Luis
|
|
||||||
Pedro Coelho, Marc Girod, Mark A. Borgerding, Mark Rodgers, Marshall
|
|
||||||
Clow, Matthew Austern, Matthew Hurd, Michael D. Crawford, Michael H.
|
|
||||||
Cox , Mike Haller, Miki Jovanovic, Nathan Myers, Paul Moore, Pavel
|
|
||||||
Cisler, Peter Dimov, Petr Kocmid, Philip Nash, Rainer Deyke, Reid
|
|
||||||
Sweatman, Ross Smith, Scott McCaskill, Shalom Reich , Steve Cleary,
|
|
||||||
Steven Kirk, Thomas Holenstein, Thomas Matelich, Trevor Perrin,
|
|
||||||
Valentin Bonnard, Vesa Karvonen, Wayne Miller, and William Kempf.</p>
|
|
||||||
|
|
||||||
<p>Apologies for anyone inadvertently missed.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p>Revised
|
|
||||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->05 November, 2001<!--webbot bot="Timestamp" endspan i-checksum="39359" --></p>
|
|
||||||
|
|
||||||
<p>© <i>Copyright <a href="mailto:williamkempf@hotmail.com">
|
|
||||||
William E. Kempf</a> 2001</i></p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
16
doc/acknowledgements.qbk
Normal file
16
doc/acknowledgements.qbk
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
[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]
|
||||||
65
doc/barrier.qbk
Normal file
65
doc/barrier.qbk
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
[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]
|
||||||
@@ -1,222 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content=
|
|
||||||
"text/html; charset=windows-1252">
|
|
||||||
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
|
|
||||||
<meta name="ProgId" content="FrontPage.Editor.Document">
|
|
||||||
|
|
||||||
<title>Boost.Threads Bibliography</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body bgcolor="#FFFFFF" text="#000000">
|
|
||||||
<table summary="header" border="0" cellpadding="7" cellspacing="0"
|
|
||||||
width="100%">
|
|
||||||
<tr>
|
|
||||||
<td valign="top" width="300">
|
|
||||||
<h3><img src="../../../c++boost.gif" alt="C++ Boost" width=
|
|
||||||
"277" height="86"></h3>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td valign="top">
|
|
||||||
<h1 align="center">Boost.Threads</h1>
|
|
||||||
|
|
||||||
<h2 align="center">Bibliography</h2>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<h2>Bibliography</h2>
|
|
||||||
|
|
||||||
<table summary="Bibliography" border="0" cellpadding="5" width="777">
|
|
||||||
<tr>
|
|
||||||
<td width="102" valign="top" align="left"><b>[<a name=
|
|
||||||
"Andrews-83">Andrews 83</a>]</b></td>
|
|
||||||
|
|
||||||
<td width="645">
|
|
||||||
Gregory R. Andrews, Fred B. Schneider, <cite>Concepts and
|
|
||||||
Notations for Concurrent Programming</cite>, ACM Computing
|
|
||||||
Surveys, Vol. 15, No. 1, March, 1983. <a href=
|
|
||||||
"http://www.acm.org/pubs/citations/journals/surveys/1983-15-1/p3-andrews/">
|
|
||||||
http://www.acm.org/pubs/citations/journals/surveys/1983-15-1/p3-andrews/</a>
|
|
||||||
|
|
||||||
|
|
||||||
<p>Good general background reading. Includes descriptions
|
|
||||||
of Path Expressions, Message Passing, and Remote Procedure
|
|
||||||
Call in addition to the basics.</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td width="102" valign="top" align="left"><b>[<a name=
|
|
||||||
"Boost">Boost</a>]</b></td>
|
|
||||||
|
|
||||||
<td width="645">
|
|
||||||
The <cite>Boost</cite> world-wide web site. <a href=
|
|
||||||
"http://www.boost.org">http://www.boost.org</a>
|
|
||||||
|
|
||||||
<p>Boost.Threads is one of many Boost libraries. The Boost
|
|
||||||
web site includes a great deal of documentation and general
|
|
||||||
information which applies to all Boost libraries. Current
|
|
||||||
copies of the libraries including documentation and test
|
|
||||||
programs may be downloaded from the web site.</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td width="102" valign="top" align="left"><b>[<a name=
|
|
||||||
"Brinch-Hansen-73">Brinch Hansen 73</a>]</b></td>
|
|
||||||
|
|
||||||
<td width="645">
|
|
||||||
Per Brinch Hansen, <cite>Concurrent Programming
|
|
||||||
Concepts</cite>, ACM Computing Surveys, Vol. 5, No. 4,
|
|
||||||
December, 1973. <a href=
|
|
||||||
"http://www.acm.org/pubs/articles/journals/surveys/1973-5-4/p223-hansen/p223-hansen.pdf">
|
|
||||||
http://www.acm.org/pubs/articles/journals/surveys/1973-5-4/p223-hansen/</a>
|
|
||||||
|
|
||||||
|
|
||||||
<p>"This paper describes the evolution of language
|
|
||||||
features for multiprogramming from event queues and
|
|
||||||
semaphores to critical regions and monitors." Includes
|
|
||||||
analysis of why <i>events</i> are considered error-prone.
|
|
||||||
Also noteworthy because of an introductory quotation from
|
|
||||||
Christopher Alexander; Brinch Hansen was years ahead of
|
|
||||||
others in recognizing pattern concepts applied to software
|
|
||||||
too.</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td width="102" valign="top" align="left"><b>]<a name=
|
|
||||||
"Butenhof-97">Butenhof 97</a>]</b></td>
|
|
||||||
|
|
||||||
<td width="645">
|
|
||||||
<p>David R. Butenhof, <cite>Programming with POSIX
|
|
||||||
Threads</cite>, Addison-Wesley 1997, ISBN 0-201-63392-2 <a
|
|
||||||
href="http://cseng.aw.com/book/0,3828,0201633922,00.html">
|
|
||||||
http://cseng.aw.com/book/0,3828,0201633922,00.html</a></p>
|
|
||||||
|
|
||||||
<p>This is a very readable explanation of threads and how
|
|
||||||
to use them. Many of the insights given apply to all
|
|
||||||
multi-threaded programming, not just POSIX Threads.</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td width="102" valign="top" align="left"><b>[<a name=
|
|
||||||
"Hoare-74">Hoare 74</a>]</b></td>
|
|
||||||
|
|
||||||
<td width="645">
|
|
||||||
<p>C.A.R Hoare, <cite>Monitors: An Operating System
|
|
||||||
Structuring Concept</cite>, Communications of the ACM, Vol.
|
|
||||||
17, No. 10. October 1974, pp. 549-557 <a href=
|
|
||||||
"http://www.acm.org/classics/feb96/">
|
|
||||||
http://www.acm.org/classics/feb96/</a></p>
|
|
||||||
|
|
||||||
<p>Hoare and Brinch Hansen's work on Monitors is the
|
|
||||||
basis for reliable multi-threading patterns. This is one of
|
|
||||||
the most often referenced papers in all of computer
|
|
||||||
science, and with good reason.</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td width="102" valign="top" align="left"><b>[<a name=
|
|
||||||
"ISO-98">ISO 98</a>]</b></td>
|
|
||||||
|
|
||||||
<td width="645">
|
|
||||||
<p>ISO/IEC 14882:1998(E) <cite>Programming Language
|
|
||||||
C++</cite> <a href="http://www.ansi.org">
|
|
||||||
http://www.ansi.org</a></p>
|
|
||||||
|
|
||||||
<p>This is the official C++ Standards document. Available
|
|
||||||
from the ANSI (American National Standards Institute)
|
|
||||||
Electronic Standards Store.</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td width="102" valign="top" align="left"><b>[<a name=
|
|
||||||
"McDowell-89">McDowell 89</a>]</b></td>
|
|
||||||
|
|
||||||
<td width="645">
|
|
||||||
Charles E McDowell, David P. Helmbold, <cite>Debugging
|
|
||||||
Concurrent Programs</cite>, ACM Computing Surveys, Vol. 21,
|
|
||||||
No. 2, December, 1989. <a href=
|
|
||||||
"http://www.acm.org/pubs/citations/journals/surveys/1989-21-4/p593-mcdowell/">
|
|
||||||
http://www.acm.org/pubs/citations/journals/surveys/1989-21-4/p593-mcdowell/</a>
|
|
||||||
|
|
||||||
|
|
||||||
<p>Identifies many of the unique failure modes and
|
|
||||||
debugging difficulties associated with concurrent
|
|
||||||
programs.</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td width="102" valign="top" align="left"><b>[<a name=
|
|
||||||
"Schmidt">Schmidt</a>]</b> </td>
|
|
||||||
|
|
||||||
<td width="645">
|
|
||||||
<p>Douglas C. Schmidt and Irfan Pyarali, <cite>Strategies
|
|
||||||
for Implementing POSIX Condition Variables on Win32</cite>,
|
|
||||||
Department of Computer Science, Washington University, St.
|
|
||||||
Louis, Missouri. <a href=
|
|
||||||
"http://www.cs.wustl.edu/~schmidt/win32-cv-1.html">
|
|
||||||
http://www.cs.wustl.edu/~schmidt/win32-cv-1.html</a></p>
|
|
||||||
|
|
||||||
<p>Rationale for understanding Boost.Threads condition
|
|
||||||
variables. Note that Alexander Terekhov found some bugs in
|
|
||||||
the implementation given in this article, so pthreads-win32
|
|
||||||
and Boost.Threads are even more complicated yet.</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td width="102" valign="top" align="left"><b>[<a name=
|
|
||||||
"Schmidt-00">Schmidt 00</a>]</b> </td>
|
|
||||||
|
|
||||||
<td width="645">
|
|
||||||
<p>Douglas C. Schmidt, Michael Stal, Hans Rohnert and Frank
|
|
||||||
Buschmann, <cite>Pattern-Oriented Software Architecture
|
|
||||||
Volume 2 - Patterns for Concurrent and Networked
|
|
||||||
Objects</cite>, Wiley 2000, ISBN 0-471-60695-2 <a href=
|
|
||||||
"http://www.wiley.com/Corporate/Website/Objects/Products/0,9049,104671,00.html">
|
|
||||||
http://www.wiley.com/Corporate/Website/Objects/Products/0,9049,104671,00.html</a></p>
|
|
||||||
|
|
||||||
<p>This is a very good explanation of how to apply several
|
|
||||||
patterns useful for concurrent programming. Among the
|
|
||||||
patterns documented is the Monitor Pattern mentioned
|
|
||||||
frequently in the <b>Boost.Threads</b> documentation.</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td width="102" valign="top" align="left"><b>[<a name=
|
|
||||||
"Stroustrup-00">Stroustrup 00</a>]</b></td>
|
|
||||||
|
|
||||||
<td width="645">
|
|
||||||
Bjarne Stroustrup, <cite>The C++ Programming
|
|
||||||
Language</cite>, Special Edition, Addison-Wesley 2000, ISBN
|
|
||||||
0-201-70073-5 <a href=
|
|
||||||
"http://cseng.aw.com/book/0,3828,0201700735,00.html">
|
|
||||||
http://cseng.aw.com/book/0,3828,0201700735,00.html</a>
|
|
||||||
|
|
||||||
<p>The first book a C++ programmer should own. Note that
|
|
||||||
the 3rd edition (and subsequent editions like the Special
|
|
||||||
Edition) has been rewritten to cover the ISO standard
|
|
||||||
language and library.</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<p>Note: The URL's above are provided in plain text form so that
|
|
||||||
they will be visible on printed copies of this document.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p>Revised
|
|
||||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %b %Y" startspan -->05 Nov 2001<!--webbot bot="Timestamp" endspan i-checksum="15246" --></p>
|
|
||||||
|
|
||||||
<p>© Copyright Beman Dawes, 2001</p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
@@ -1,132 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content=
|
|
||||||
"text/html; charset=iso-8859-1">
|
|
||||||
<meta name="keywords" content=
|
|
||||||
"threads, Boost.Threads, thread library, C++">
|
|
||||||
<link rel="stylesheet" type="text/css" href="styles.css">
|
|
||||||
|
|
||||||
<title>Boost.Threads, call_once</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body bgcolor="#FFFFFF" link="#0000FF" vlink="#800080">
|
|
||||||
<table summary="header" border="0" cellpadding="7" cellspacing="0"
|
|
||||||
width="100%">
|
|
||||||
<tr>
|
|
||||||
<td valign="top" width="300">
|
|
||||||
<h3><img src="../../../c++boost.gif" alt="C++ Boost" width=
|
|
||||||
"277" height="86"></h3>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td valign="top">
|
|
||||||
<h1 align="center">Boost.Threads</h1>
|
|
||||||
|
|
||||||
<h2 align="center">call_once</h2>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p><a href="#Introduction">Introduction</a><br>
|
|
||||||
<a href="#Header">Header</a><br>
|
|
||||||
<a href="#Synopsis">Synopsis</a><br>
|
|
||||||
<a href="#Members">Members</a><br>
|
|
||||||
<a href="#Example">Example</a></p>
|
|
||||||
|
|
||||||
<h2><a name="Introduction">Introduction</a></h2>
|
|
||||||
|
|
||||||
<p>The <code>call_once</code> routine and <code>once_flag</code> type
|
|
||||||
can be used to run a routine exactly once. This can be used to
|
|
||||||
initialize data in a <a href="definitions.html#Thread-safe">
|
|
||||||
thread-safe</a> manner.</p>
|
|
||||||
|
|
||||||
<h2><a name="Header">Header</a></h2>
|
|
||||||
<pre>
|
|
||||||
#include <a href=
|
|
||||||
"../../../boost/thread/once.hpp"><boost/thread/once.hpp></a>
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h2><a name="Synopsis">Synopsis</a></h2>
|
|
||||||
<pre>
|
|
||||||
namespace boost {
|
|
||||||
|
|
||||||
typedef <i>[implementation defined]</i> once_flag;
|
|
||||||
const once_flag once_init = <i>[implementation defined]</i>;
|
|
||||||
void call_once(void (*func)(), once_flag& flag);
|
|
||||||
|
|
||||||
} // namespace boost
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h2><a name="Reference">Reference</a></h2>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>once_flag</h3>
|
|
||||||
|
|
||||||
<p>This implementation defined type is used as a flag to insure a
|
|
||||||
routine is called only once. Instances of this type should be
|
|
||||||
statically initialized to <code>once_init</code>.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>once_init</h3>
|
|
||||||
|
|
||||||
<p>This is a constant value used to initialize <code>once_flag</code>
|
|
||||||
instances to indicate that the logically associated routine has not
|
|
||||||
been run yet.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>call_once</h3>
|
|
||||||
<pre>
|
|
||||||
void call_once(void (*func)(), once_flag& flag);
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Requires:</b> The function <code>func</code> shall not throw
|
|
||||||
exceptions.</p>
|
|
||||||
|
|
||||||
<p><b>Effects:</b> As if (in an atomic fashion)</p>
|
|
||||||
<code> if (flag == once_init)<br>
|
|
||||||
func();</code>
|
|
||||||
|
|
||||||
<p><b>Postcondition:</b> <code>flag</code> != <code>
|
|
||||||
once_init</code></p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h2><a name="Example">Example Usage</a></h2>
|
|
||||||
<pre>
|
|
||||||
#include <a href=
|
|
||||||
"../../../boost/thread/thread.hpp"><boost/thread/thread.hpp></a>
|
|
||||||
#include <a href=
|
|
||||||
"../../../boost/thread/tss.hpp"><boost/thread/once.hpp></a>
|
|
||||||
#include <cassert>
|
|
||||||
|
|
||||||
int value=0;
|
|
||||||
boost::once_flag once = boost::once_init;
|
|
||||||
|
|
||||||
void init()
|
|
||||||
{
|
|
||||||
++value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void thread_proc()
|
|
||||||
{
|
|
||||||
boost::call_once(&init, once);
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
|
||||||
{
|
|
||||||
boost::thread_group threads;
|
|
||||||
for (int i=0; i<5; ++i)
|
|
||||||
threads.create_thread(&thread_proc);
|
|
||||||
threads.join_all();
|
|
||||||
assert(value == 1);
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p>Revised
|
|
||||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->05 November, 2001<!--webbot bot="Timestamp" endspan i-checksum="39359" --></p>
|
|
||||||
|
|
||||||
<p><i>© Copyright <a href="mailto:williamkempf@hotmail.com">
|
|
||||||
William E. Kempf</a> 2001 all rights reserved.</i></p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
57
doc/changes.qbk
Normal file
57
doc/changes.qbk
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
[section:changes 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.
|
||||||
|
|
||||||
|
[endsect]
|
||||||
@@ -1,338 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content=
|
|
||||||
"text/html; charset=iso-8859-1">
|
|
||||||
<meta name="keywords" content="threads, BTL, thread library, C++">
|
|
||||||
<link rel="stylesheet" type="text/css" href="styles.css">
|
|
||||||
|
|
||||||
<title>Boost.Threads, condition</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body bgcolor="#ffffff" link="#0000ff" vlink="#800080" text="#000000">
|
|
||||||
<table summary="header" border="0" cellpadding="7" cellspacing="0"
|
|
||||||
width="100%">
|
|
||||||
<tr>
|
|
||||||
<td valign="top" width="300">
|
|
||||||
<h3><img height="86" alt="C++ Boost" src=
|
|
||||||
"../../../c++boost.gif" width="277"></h3>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td valign="top">
|
|
||||||
<h1 align="center">Boost.Threads</h1>
|
|
||||||
|
|
||||||
<h2 align="center">condition</h2>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p><a href="#Introduction">Introduction</a><br>
|
|
||||||
<a href="#Header">Header</a><br>
|
|
||||||
<a href="#Synopsis">Synopsis</a><br>
|
|
||||||
<a href="#Members">Members</a><br>
|
|
||||||
<a href="#Example">Example</a></p>
|
|
||||||
|
|
||||||
<h2><a name="Introduction">Introduction</a></h2>
|
|
||||||
|
|
||||||
<p>An object of class <code>condition</code> is a synchronization
|
|
||||||
primitive used to cause a thread to wait until a particular shared-data
|
|
||||||
condition (or time) is met. A <code>condition</code> object is always
|
|
||||||
used in conjunction with a mutex object modeling a <a href=
|
|
||||||
"mutex_concept.html">Mutex Concept</a>. The mutex must be locked prior
|
|
||||||
to waiting on the <code>condition</code>, which is ensured by passing a
|
|
||||||
lock object modeling a <a href="lock_concept.html">Lock Concept</a> to
|
|
||||||
the <code>condition</code> object's <code>wait</code> functions.
|
|
||||||
While the thread is waiting on the <code>condition</code> object, the
|
|
||||||
mutex associated with the lock is unlocked. When the thread returns
|
|
||||||
from a call to one of the <code>condition</code> object's <code>
|
|
||||||
wait</code> functions, the mutex is again locked. The tricky
|
|
||||||
lock/unlock/lock sequence is performed automatically by the <code>
|
|
||||||
condition</code> object's <code>wait</code> functions.</p>
|
|
||||||
|
|
||||||
<p>The <code>condition</code> type is often used to implement the <i>
|
|
||||||
Monitor Object</i> and other important patterns. See <a href=
|
|
||||||
"bibliography.html#Schmidt-00">[Schmidt-00]</a> and <a href=
|
|
||||||
"bibliography.html#Hoare-74">[Hoare 74]</a>. Monitors are one of the
|
|
||||||
most important patterns for creating reliable multithreaded
|
|
||||||
programs.</p>
|
|
||||||
|
|
||||||
<p>See <a href="definitions.html">Formal Definitions</a> for
|
|
||||||
definitions of thread states <a href="definitions.html#state">
|
|
||||||
blocked</a> and <a href="definitions.html#state">ready</a>. Note that
|
|
||||||
"waiting" is a synonym for blocked.</p>
|
|
||||||
|
|
||||||
<h2><a name="Header">Header</a></h2>
|
|
||||||
<pre>
|
|
||||||
#include <a href=
|
|
||||||
"../../../boost/thread/condition.hpp"><boost/thread/condition.hpp></a>
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h2><a name="Synopsis">Synopsis</a></h2>
|
|
||||||
<pre>
|
|
||||||
namespace boost {
|
|
||||||
|
|
||||||
class condition : private <a href=
|
|
||||||
"../../utility/utility.htm#Class noncopyable">boost::noncopyable</a> // Exposition only.
|
|
||||||
// Class condition meets the <a href=
|
|
||||||
"overview.html#NonCopyable">NonCopyable</a> requirement.
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
condition();
|
|
||||||
~condition();
|
|
||||||
|
|
||||||
void notify_one();
|
|
||||||
void notify_all();
|
|
||||||
template <typename <a href="scoped_lock.html">ScopedLock</a>>
|
|
||||||
void wait(<a href="scoped_lock.html">ScopedLock</a>& lock);
|
|
||||||
template <typename <a href="scoped_lock.html">ScopedLock</a>, typename <a
|
|
||||||
href="http://www.sgi.com/tech/stl/Predicate.html">Predicate</a>>
|
|
||||||
void wait(<a href="scoped_lock.html">ScopedLock</a>& lock, <a href=
|
|
||||||
"http://www.sgi.com/tech/stl/Predicate.html">Predicate</a> pred);
|
|
||||||
template <typename <a href="scoped_lock.html">ScopedLock</a>>
|
|
||||||
bool timed_wait(<a href=
|
|
||||||
"scoped_lock.html">ScopedLock</a>& lock, const xtime& xt);
|
|
||||||
template <typename <a href="scoped_lock.html">ScopedLock</a>, typename <a
|
|
||||||
href="http://www.sgi.com/tech/stl/Predicate.html">Predicate</a>>
|
|
||||||
bool timed_wait(<a href=
|
|
||||||
"scoped_lock.html">ScopedLock</a>& lock, const xtime& xt, <a href=
|
|
||||||
"http://www.sgi.com/tech/stl/Predicate.html">Predicate</a> pred);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace boost
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h2><a name="Members">Members</a></h2>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>Constructor</h3>
|
|
||||||
<pre>
|
|
||||||
condition();
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Effects:</b> Constructs a <code>condition</code>.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>Destructor</h3>
|
|
||||||
<pre>
|
|
||||||
~condition();
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Effects:</b> Destroys <code>*this</code>.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>notify_one</h3>
|
|
||||||
<pre>
|
|
||||||
void notify_one();
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Effects:</b> If there is a thread waiting on <code>*this</code>,
|
|
||||||
change that thread's state to ready. Otherwise there is no
|
|
||||||
effect.</p>
|
|
||||||
|
|
||||||
<p><b>Notes:</b> If more that one thread is waiting on the condition,
|
|
||||||
it is unspecified which is made ready.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>notify_all</h3>
|
|
||||||
<pre>
|
|
||||||
void notify_all();
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Effects:</b> Change the state of all threads waiting on <code>
|
|
||||||
*this</code> to ready. If there are no waiting threads, <code>
|
|
||||||
notify_all()</code> has no effect.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>wait</h3>
|
|
||||||
<pre>
|
|
||||||
template <typename ScopedLock>
|
|
||||||
void wait(ScopedLock& lock);
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Requires:</b> ScopedLock meets the <a href=
|
|
||||||
"lock_concept.html#ScopedLock">ScopedLock</a> requirements.</p>
|
|
||||||
|
|
||||||
<p><b>Effects:</b> Releases the lock on the <a href=
|
|
||||||
"mutex_concept.html">mutex model</a> associated with <code>lock</code>,
|
|
||||||
blocks the current thread of execution until readied by a call to
|
|
||||||
<code>this->notify_one()</code> or <code>
|
|
||||||
this->notify_all()</code>, and then reacquires the lock. All effects
|
|
||||||
occur in an atomic fashion.</p>
|
|
||||||
|
|
||||||
<p><b>Throws:</b> <code><a href="lock_error.html">lock_error</a></code>
|
|
||||||
if <code>!lock.locked()</code></p>
|
|
||||||
|
|
||||||
<p><b>Danger:</b> This version should always be used within a loop
|
|
||||||
checking that the state logically associated with the <code>
|
|
||||||
condition</code> has become true. Without the loop, race conditions can
|
|
||||||
ensue due to possible "spurious wake ups". The second version
|
|
||||||
encapsulates this loop idiom internally and is generally the preferred
|
|
||||||
method.</p>
|
|
||||||
<pre>
|
|
||||||
template <typename ScopedLock, typename Pr>
|
|
||||||
void wait(ScopedLock& lock, Pr pred);
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Requires:</b> ScopedLock meets the <a href=
|
|
||||||
"lock_concept.html#ScopedLock">ScopedLock</a> requirements, return from
|
|
||||||
<code>pred()</code> convertible to bool.</p>
|
|
||||||
|
|
||||||
<p><b>Effects:</b> As if:</p>
|
|
||||||
<code> while (!pred()) wait(lock)</code>
|
|
||||||
|
|
||||||
<p><b>Throws:</b> <code><a href="lock_error.html">lock_error</a></code>
|
|
||||||
if <code>!lock.locked()</code></p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>timed_wait</h3>
|
|
||||||
<pre>
|
|
||||||
template <typename ScopedLock>
|
|
||||||
bool timed_wait(ScopedLock& lock, const <a href=
|
|
||||||
"xtime.html">xtime</a>& xt);
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Requires:</b> ScopedLock meets the <a href=
|
|
||||||
"lock_concept.html#ScopedLock">ScopedLock</a>
|
|
||||||
requirements.</p>
|
|
||||||
|
|
||||||
<p><b>Effects:</b> Releases the lock on the <a href=
|
|
||||||
"mutex_concept.html">mutex model</a> associated with the <code>
|
|
||||||
lock</code>, blocks the current thread of execution until readied by a
|
|
||||||
call to <code>this->notify_one()</code> or <code>
|
|
||||||
this->notify_all()</code>, or until <code>xt</code>, and then
|
|
||||||
reacquires the lock. All effects occur in an atomic fashion.</p>
|
|
||||||
|
|
||||||
<p><b>Throws:</b> <code><a href="lock_error.html">lock_error</a></code>
|
|
||||||
if <code>!lock.locked()</code></p>
|
|
||||||
|
|
||||||
<p><b>Danger:</b> This version should always be used within a loop
|
|
||||||
checking that the state logically associated with the <code>
|
|
||||||
condition</code> has become true. Without the loop, race conditions can
|
|
||||||
ensue due to "spurious wake ups". The second version
|
|
||||||
encapsulates this loop idiom internally and is generally the preferred
|
|
||||||
method.</p>
|
|
||||||
|
|
||||||
<p><b>Returns:</b> <code>false</code> if <code>xt</code> is reached,
|
|
||||||
otherwise <code>true</code>.</p>
|
|
||||||
<pre>
|
|
||||||
template <typename ScopedLock, typename Pr>
|
|
||||||
bool timed_wait(ScopedLock& lock, const <a href=
|
|
||||||
"xtime.html">xtime</a>& xt, Pr pred);
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Requires:</b> ScopedLock meets the <a href=
|
|
||||||
"lock_concept.html#ScopedLock">ScopedLock</a> requirements,
|
|
||||||
return from <code>pred()</code> convertible to bool.</p>
|
|
||||||
|
|
||||||
<p><b>Effects:</b> As if:</p>
|
|
||||||
<code> while (!pred())<br>
|
|
||||||
{<br>
|
|
||||||
if (!timed_wait(lock, xt))<br>
|
|
||||||
return
|
|
||||||
false;<br>
|
|
||||||
}</code>
|
|
||||||
|
|
||||||
<p><b>Throws:</b> <code><a href="lock_error.html">lock_error</a></code>
|
|
||||||
if <code>!lock.locked()</code></p>
|
|
||||||
|
|
||||||
<p><b>Returns:</b> <code>false</code> if <code>xt</code> is reached,
|
|
||||||
otherwise <code>true</code>.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h2><a name="Example">Example Usage</a></h2>
|
|
||||||
<pre>
|
|
||||||
#include <iostream>
|
|
||||||
#include <vector>
|
|
||||||
#include <a href="../../../boost/utility.hpp"><boost/utility.hpp></a>
|
|
||||||
#include <a href=
|
|
||||||
"../../../boost/thread/condition.hpp"><boost/thread/condition.hpp></a>
|
|
||||||
#include <a href=
|
|
||||||
"../../../boost/thread/thread.hpp"><boost/thread/thread.hpp></a>
|
|
||||||
|
|
||||||
class bounded_buffer : private boost::noncopyable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef boost::mutex::scoped_lock lock;
|
|
||||||
|
|
||||||
bounded_buffer(int n) : begin(0), end(0), buffered(0), circular_buf(n) { }
|
|
||||||
|
|
||||||
void send (int m) {
|
|
||||||
lock lk(monitor);
|
|
||||||
while (buffered == circular_buf.size())
|
|
||||||
buffer_not_full.wait(lk);
|
|
||||||
circular_buf[end] = m;
|
|
||||||
end = (end+1) % circular_buf.size();
|
|
||||||
++buffered;
|
|
||||||
buffer_not_empty.notify_one();
|
|
||||||
}
|
|
||||||
int receive() {
|
|
||||||
lock lk(monitor);
|
|
||||||
while (buffered == 0)
|
|
||||||
buffer_not_empty.wait(lk);
|
|
||||||
int i = circular_buf[begin];
|
|
||||||
begin = (begin+1) % circular_buf.size();
|
|
||||||
--buffered;
|
|
||||||
buffer_not_full.notify_one();
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
int begin, end, buffered;
|
|
||||||
std::vector<int> circular_buf;
|
|
||||||
boost::condition buffer_not_full, buffer_not_empty;
|
|
||||||
boost::mutex monitor;
|
|
||||||
};
|
|
||||||
|
|
||||||
bounded_buffer buf(2);
|
|
||||||
|
|
||||||
void sender() {
|
|
||||||
int n = 0;
|
|
||||||
while (n < 100) {
|
|
||||||
buf.send(n);
|
|
||||||
std::cout << "sent: " << n << std::endl;
|
|
||||||
++n;
|
|
||||||
}
|
|
||||||
buf.send(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void receiver() {
|
|
||||||
int n;
|
|
||||||
do {
|
|
||||||
n = buf.receive();
|
|
||||||
std::cout << "received: " << n << std::endl;
|
|
||||||
} while (n != -1); // -1 indicates end of buffer
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int, char*[])
|
|
||||||
{
|
|
||||||
boost::thread thrd1(&sender);
|
|
||||||
boost::thread thrd2(&receiver);
|
|
||||||
thrd1.join();
|
|
||||||
thrd2.join();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>Typical output (dependent on scheduling policies) is:</p>
|
|
||||||
<pre>
|
|
||||||
sent: 0
|
|
||||||
sent: 1
|
|
||||||
received: 0
|
|
||||||
received: 1
|
|
||||||
sent: 2
|
|
||||||
sent: 3
|
|
||||||
received: 2
|
|
||||||
received: 3
|
|
||||||
sent: 4
|
|
||||||
received: 4
|
|
||||||
</pre>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p>Revised
|
|
||||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->05 November, 2001<!--webbot bot="Timestamp" endspan i-checksum="39359" --></p>
|
|
||||||
|
|
||||||
<p><i>© Copyright <a href="mailto:williamkempf@hotmail.com">
|
|
||||||
William E. Kempf</a> 2001 all rights reserved.</i></p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
494
doc/condition_variables.qbk
Normal file
494
doc/condition_variables.qbk
Normal file
@@ -0,0 +1,494 @@
|
|||||||
|
[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`]
|
||||||
|
|
||||||
|
namespace boost
|
||||||
|
{
|
||||||
|
class condition_variable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
condition_variable();
|
||||||
|
~condition_variable();
|
||||||
|
|
||||||
|
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`]
|
||||||
|
|
||||||
|
namespace boost
|
||||||
|
{
|
||||||
|
class condition_variable_any
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
condition_variable_any();
|
||||||
|
~condition_variable_any();
|
||||||
|
|
||||||
|
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`]
|
||||||
|
|
||||||
|
typedef condition_variable_any condition;
|
||||||
|
|
||||||
|
The typedef `condition` is provided for backwards compatibility with previous boost releases.
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
@@ -1,97 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content=
|
|
||||||
"text/html; charset=iso-8859-1">
|
|
||||||
<meta name="keywords" content="threads, BTL, thread library, C++">
|
|
||||||
|
|
||||||
<title>Boost.Threads, Configuration Information</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body bgcolor="#FFFFFF" link="#0000FF" vlink="#800080">
|
|
||||||
<table summary="header" border="0" cellpadding="7" cellspacing="0"
|
|
||||||
width="100%">
|
|
||||||
<tr>
|
|
||||||
<td valign="top" width="300">
|
|
||||||
<h3><img src="../../../c++boost.gif" alt="C++ Boost" width=
|
|
||||||
"277" height="86"></h3>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td valign="top">
|
|
||||||
<h1 align="center">Boost.Threads</h1>
|
|
||||||
|
|
||||||
<h2 align="center">Configuration Information</h2>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p><b>Boost.Threads</b> uses several configuration macros in <a href=
|
|
||||||
"../../config/config.htm"><boost/config.hpp></a>. These macros
|
|
||||||
are documented here. Most of the macros are of interest only to
|
|
||||||
developers attempting to provide new implementations of <b>
|
|
||||||
Boost.Threads</b>. The one exception to this is BOOST_HAS_THREADS.</p>
|
|
||||||
|
|
||||||
<table summary="macros" cellspacing="10" width="100%">
|
|
||||||
<tr>
|
|
||||||
<td valign="top"><b>Macro</b> </td>
|
|
||||||
|
|
||||||
<td valign="top"><b>Meaning</b> </td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td valign="top">BOOST_HAS_THREADS</td>
|
|
||||||
|
|
||||||
<td valign="top">Indicates that threading support is available.
|
|
||||||
This means both that there is a platform specific
|
|
||||||
implementation for <b>Boost.Threads</b> and that threading
|
|
||||||
support has been enabled in a platform specific manner. For
|
|
||||||
instance, on the Win32 platform there's an implementation
|
|
||||||
for <b>Boost.Threads</b> but unless the program is compiled
|
|
||||||
against one of the multi-threading runtimes (often determined
|
|
||||||
by the compiler predefining the macro _MT) the
|
|
||||||
BOOST_HAS_THREADS macro remains undefined.</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td valign="top">BOOST_HAS_WINTHREADS</td>
|
|
||||||
|
|
||||||
<td valign="top">Indicates that the platform has the Microsoft
|
|
||||||
Win32 threading libraries, and that they should be used to
|
|
||||||
implement <b>Boost.Threads</b>.</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td valign="top">BOOST_HAS_PTHREADS</td>
|
|
||||||
|
|
||||||
<td valign="top">Indicates that the platform has the POSIX
|
|
||||||
pthreads libraries, and that they should be used to implement
|
|
||||||
<b>Boost.Threads</b>.</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td valign="top">BOOST_HAS_FTIME</td>
|
|
||||||
|
|
||||||
<td valign="top">Indicates that the implementation should use
|
|
||||||
GetSystemTimeAsFileTime() and the FILETIME type to calculate
|
|
||||||
the current time. This is an implementation detail used by
|
|
||||||
boost::detail::getcurtime().</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td valign="top">BOOST_HAS_GETTTIMEOFDAY</td>
|
|
||||||
|
|
||||||
<td valign="top">Indicates that the implementation should use
|
|
||||||
gettimeofday() to calculate the current time. This is an
|
|
||||||
implementation detail used by boost::detail::getcurtime().</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p>Revised
|
|
||||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->05 November, 2001<!--webbot bot="Timestamp" endspan i-checksum="39359" --></p>
|
|
||||||
|
|
||||||
<p><i>© Copyright <a href="mailto:williamkempf@hotmail.com">
|
|
||||||
William E. Kempf</a> 2001 all rights reserved.</i></p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
@@ -1,348 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Language" content="en-us">
|
|
||||||
<meta http-equiv="Content-Type" content=
|
|
||||||
"text/html; charset=windows-1252">
|
|
||||||
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
|
|
||||||
<meta name="ProgId" content="FrontPage.Editor.Document">
|
|
||||||
|
|
||||||
<title>Boost.Threads Definitions</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body bgcolor="#FFFFFF">
|
|
||||||
<table summary="header" border="0" cellpadding="7" cellspacing="0"
|
|
||||||
width="100%">
|
|
||||||
<tr>
|
|
||||||
<td valign="top" width="300">
|
|
||||||
<h3><img src="../../../c++boost.gif" alt="C++ Boost" width=
|
|
||||||
"277" height="86"></h3>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td valign="top">
|
|
||||||
<h1 align="center">Boost.Threads</h1>
|
|
||||||
|
|
||||||
<h2 align="center">Definitions</h2>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<h2>Introduction</h2>
|
|
||||||
|
|
||||||
<p>The definitions are given in terms of the <a href=
|
|
||||||
"bibliography.html#ISO-98">C++ Standard</a>. References to the standard
|
|
||||||
are in the form [1.2.3/4], which represents the section number, with
|
|
||||||
the paragraph number following the "/".</p>
|
|
||||||
|
|
||||||
<p>Because the definitions are written in something akin to
|
|
||||||
"standardese", they can be difficult to understand. The
|
|
||||||
intent isn't to confuse, but rather to clarify the additional
|
|
||||||
requirements Boost.Threads places on a C++ implementation as defined by
|
|
||||||
the C++ Standard.</p>
|
|
||||||
|
|
||||||
<h2>Definitions</h2>
|
|
||||||
|
|
||||||
<h3>Thread</h3>
|
|
||||||
|
|
||||||
<p>Thread is short for "thread of execution". A thread of
|
|
||||||
execution is an execution environment [1.9/7] within the execution
|
|
||||||
environment of a C++ program [1.9]. The main() function [3.6.1] of the
|
|
||||||
program is the initial function of the initial thread. A program in a
|
|
||||||
multi-threading environment always has an initial thread even if the
|
|
||||||
program explicitly creates no additional threads.</p>
|
|
||||||
|
|
||||||
<p>Unless otherwise specified, each thread shares all aspects of its
|
|
||||||
execution environment with other threads in the program. Shared aspects
|
|
||||||
of the execution environment include, but are not limited to, the
|
|
||||||
following:</p>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li>Static storage duration (static, extern) objects [3.7.1].</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li>Dynamic storage duration (heap) objects [3.7.3]. Thus each
|
|
||||||
memory allocation will return a unique addresses, regardless of the
|
|
||||||
thread making the allocation request.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li>Automatic storage duration (stack) objects [3.7.2] accessed via
|
|
||||||
pointer or reference from another thread.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li>Resources provided by the operating system. For example,
|
|
||||||
files.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li>The program itself. In other words, each thread is executing
|
|
||||||
some function of the same program, not a totally different
|
|
||||||
program.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<p>Each thread has its own:</p>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li>Registers and current execution sequence (program counter)
|
|
||||||
[1.9/5].</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li>Automatic storage duration (stack) objects [3.7.2].</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<h3><a name="Thread-safe">Thread-safe</a></h3>
|
|
||||||
|
|
||||||
<p>A program is thread-safe if it has no <a href="#Race condition">race
|
|
||||||
conditions</a>, does not <a href="#Deadlock">deadlock</a>, and has no
|
|
||||||
<a href="#Priority failure">priority failures</a>.</p>
|
|
||||||
|
|
||||||
<p>Note that thread-safety does not necessarily imply efficiency, and
|
|
||||||
than while some thread-safety violations can be determined statically
|
|
||||||
at compile time, many thread-safety errors can only only be detected at
|
|
||||||
runtime.</p>
|
|
||||||
|
|
||||||
<h3>Thread <a name="State">State</a></h3>
|
|
||||||
|
|
||||||
<p>During the lifetime of a thread, it shall be in one of the following
|
|
||||||
states:</p>
|
|
||||||
|
|
||||||
<table summary="thread states" border="1" cellpadding="5">
|
|
||||||
<tr>
|
|
||||||
<td><b>State</b></td>
|
|
||||||
|
|
||||||
<td><b>Description</b></td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>Ready</td>
|
|
||||||
|
|
||||||
<td>Ready to run, but waiting for a processor.</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>Running</td>
|
|
||||||
|
|
||||||
<td>Currently executing on a processor. Zero or more threads
|
|
||||||
may be running at any time, with a maximum equal to the number
|
|
||||||
of processors.</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>Blocked</td>
|
|
||||||
|
|
||||||
<td>Waiting for some resource other than a processor which is
|
|
||||||
not currently available, or for the completion of calls to
|
|
||||||
library functions [1.9/6]. The term "waiting" is
|
|
||||||
synonymous for "blocked"</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>Terminated</td>
|
|
||||||
|
|
||||||
<td>Finished execution but not yet detached or joined.</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<p>Thread state transitions shall occur only as specified:</p>
|
|
||||||
|
|
||||||
<table summary="state transitions" border="1" cellpadding="5">
|
|
||||||
<tr>
|
|
||||||
<td><b>From</b></td>
|
|
||||||
|
|
||||||
<td><b>To</b></td>
|
|
||||||
|
|
||||||
<td><b>Cause</b></td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<p align="left">[none]</p>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td>Ready</td>
|
|
||||||
|
|
||||||
<td>Thread is created by a call to a library function. In the
|
|
||||||
case of the initial thread, creation is implicit and occurs
|
|
||||||
during the startup of the main() function [3.6.1].</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>Ready</td>
|
|
||||||
|
|
||||||
<td>Running</td>
|
|
||||||
|
|
||||||
<td>Processor becomes available.</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>Running</td>
|
|
||||||
|
|
||||||
<td>Ready</td>
|
|
||||||
|
|
||||||
<td>Thread preempted.</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>Running</td>
|
|
||||||
|
|
||||||
<td>Blocked</td>
|
|
||||||
|
|
||||||
<td>Thread calls a library function which waits for a resource
|
|
||||||
or for the completion of I/O.</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>Running</td>
|
|
||||||
|
|
||||||
<td>Terminated</td>
|
|
||||||
|
|
||||||
<td>Thread returns from its initial function, calls a thread
|
|
||||||
termination library function, or is cancelled by some other
|
|
||||||
thread calling a thread termination library function.</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>Blocked</td>
|
|
||||||
|
|
||||||
<td>Ready</td>
|
|
||||||
|
|
||||||
<td>The resource being waited for becomes available, or the
|
|
||||||
blocking library function completes.</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>Terminated</td>
|
|
||||||
|
|
||||||
<td>[none]</td>
|
|
||||||
|
|
||||||
<td>Thread is detached or joined by some other thread calling
|
|
||||||
the appropriate library function, or by program termination
|
|
||||||
[3.6.3].</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<p>[Note: if a suspend() function is added to the threading library,
|
|
||||||
additional transitions to the blocked state will have to be added to
|
|
||||||
the above table.]</p>
|
|
||||||
|
|
||||||
<h3><a name="Race condition">Race condition</a></h3>
|
|
||||||
|
|
||||||
<p>A race condition is what occurs when multiple threads read and write
|
|
||||||
to the same memory without proper synchronization, resulting in an
|
|
||||||
incorrect value being read or written. The result of a race condition
|
|
||||||
may be a bit pattern which isn't even a valid value for the data
|
|
||||||
type. A race condition results in undefined behavior [1.3.12].</p>
|
|
||||||
|
|
||||||
<p>Race conditions can be prevented by serializing memory access using
|
|
||||||
the tools provided by Boost.Threads.</p>
|
|
||||||
|
|
||||||
<h3><a name="Deadlock">Deadlock</a></h3>
|
|
||||||
|
|
||||||
<p>Deadlock is an execution state where for some set of threads, each
|
|
||||||
thread in the set is blocked waiting for some action by one of the
|
|
||||||
other threads in the set. Since each is waiting on the others, none
|
|
||||||
will ever become ready again.</p>
|
|
||||||
|
|
||||||
<h3><a name="Priority failure">Priority failure</a></h3>
|
|
||||||
|
|
||||||
<p>A priority failure (such as priority inversion or infinite
|
|
||||||
overtaking) occurs when threads executed in such a sequence that
|
|
||||||
required work is not performed in time to be useful.</p>
|
|
||||||
|
|
||||||
<h2>Memory visibility between threads</h2>
|
|
||||||
|
|
||||||
<p>An address [1.7] shall always point to the same memory byte,
|
|
||||||
regardless of the thread or processor dereferencing the address.</p>
|
|
||||||
|
|
||||||
<p>An object [1.8, 1.9] is accessible from multiple threads if it is of
|
|
||||||
static storage duration (static, extern) [3.7.1], or if a pointer or
|
|
||||||
reference to it is explicitly or implicitly dereferenced in multiple
|
|
||||||
threads.</p>
|
|
||||||
|
|
||||||
<p>For an object accessible from multiple threads, the value of the
|
|
||||||
object accessed from one thread may be indeterminate or different than
|
|
||||||
the value accessed from another thread, except under the conditions
|
|
||||||
specified in the following table. For the same row of the table, the
|
|
||||||
value of an object accessible at the indicated sequence point in thread
|
|
||||||
A will be determinate and the same if accessed at or after the
|
|
||||||
indicated sequence point in thread B, provided the object is not
|
|
||||||
otherwise modified. In the table, the "sequence point at a
|
|
||||||
call" is the sequence point after the evaluation of all function
|
|
||||||
arguments [1.9/17], while the "sequence point after a call"
|
|
||||||
is the sequence point after the copying of the returned value..."
|
|
||||||
[1.9/17].</p>
|
|
||||||
|
|
||||||
<table summary="memory visibility" border="1" cellpadding="5">
|
|
||||||
<tr>
|
|
||||||
<td align="center"><b>Thread A</b></td>
|
|
||||||
|
|
||||||
<td align="center"><b>Thread B</b></td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>The sequence point at a call to a library thread-creation
|
|
||||||
function.</td>
|
|
||||||
|
|
||||||
<td>The first sequence point of the initial function in the new
|
|
||||||
thread created by the Thread A call.</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>The sequence point at a call to a library function which
|
|
||||||
locks a mutex, directly or by waiting for a condition
|
|
||||||
variable.</td>
|
|
||||||
|
|
||||||
<td>The sequence point after a call to a library function which
|
|
||||||
unlocks the same mutex.</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>The last sequence point before thread termination.</td>
|
|
||||||
|
|
||||||
<td>The sequence point after a call to a library function which
|
|
||||||
joins the terminated thread.</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>The sequence point at a call to a library function which
|
|
||||||
signals or broadcasts a condition variable.</td>
|
|
||||||
|
|
||||||
<td>The sequence point after the call to the library function
|
|
||||||
which was waiting on that same condition variable or
|
|
||||||
signal.</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<p>The architecture of the execution environment and the observable
|
|
||||||
behavior of the abstract machine [1.9] shall be the same on all
|
|
||||||
processors.</p>
|
|
||||||
|
|
||||||
<p>The latitude granted by the C++ standard for an implementation to
|
|
||||||
alter the definition of observable behavior of the abstract machine to
|
|
||||||
include additional library I/O functions [1.9/6] is extended to include
|
|
||||||
threading library functions.</p>
|
|
||||||
|
|
||||||
<p>When an exception is thrown and there is no matching exception
|
|
||||||
handler in the same thread, behavior is undefined. The preferred
|
|
||||||
behavior is the same as when there is no matching exception handler in
|
|
||||||
a program [15.3/9]. That is, terminate() is called, and it is
|
|
||||||
implementation defined whether or not the stack is unwound.</p>
|
|
||||||
|
|
||||||
<h2><a name="Acknowledgements">Acknowledgements</a></h2>
|
|
||||||
|
|
||||||
<p>This document has been much improved by the incorporation of
|
|
||||||
comments from William Kempf.</p>
|
|
||||||
|
|
||||||
<p>The visibility rules are based on <a href=
|
|
||||||
"bibliography.html#Butenhof-97">[Butenhof 97]</a>.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p>Revised
|
|
||||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %b %Y" startspan -->05 Nov 2001<!--webbot bot="Timestamp" endspan i-checksum="15246" --></p>
|
|
||||||
|
|
||||||
<p>© Copyright Beman Dawes, 2001</p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
193
doc/faq.html
193
doc/faq.html
@@ -1,193 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content=
|
|
||||||
"text/html; charset=iso-8859-1">
|
|
||||||
<meta name="keywords" content="threads, BTL, thread library, C++">
|
|
||||||
<link rel="stylesheet" type="text/css" href="styles.css">
|
|
||||||
|
|
||||||
<title>Boost.Threads, FAQ</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body bgcolor="#FFFFFF" link="#0000FF" vlink="#800080">
|
|
||||||
<table summary="header" border="0" cellpadding="7" cellspacing="0"
|
|
||||||
width="100%">
|
|
||||||
<tr>
|
|
||||||
<td valign="top" width="300">
|
|
||||||
<h3><img src="../../../c++boost.gif" alt="C++ Boost" width="277" height="86"></h3>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td valign="top">
|
|
||||||
<h1 align="center">Boost.Threads</h1>
|
|
||||||
|
|
||||||
<h2 align="center">Frequently Asked Questions</h2>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h2>1. Are lock objects <a href="definitions.html#Thread-safe">
|
|
||||||
thread-safe</a>?</h2>
|
|
||||||
|
|
||||||
<p><b>No!</b> Lock objects are not meant to be shared between threads.
|
|
||||||
They are meant to be short lived objects created on automatic storage
|
|
||||||
within a code block. Any other usage is just likely to lead to errors
|
|
||||||
and won't really be of actual benefit any way. Share <a href=
|
|
||||||
"mutex_concept.html">mutexes</a>, not locks. For more information see
|
|
||||||
the <a href="rationale.html#lock_objects">rationale</a> behind the
|
|
||||||
design for lock objects.</p>
|
|
||||||
|
|
||||||
<h2>2a. Why was Boost.Threads modeled after (specific library
|
|
||||||
name)?</h2>
|
|
||||||
|
|
||||||
<p>It wasn't. Boost.Threads was designed from scratch. Extensive
|
|
||||||
design discussions involved numerous people representing a wide range
|
|
||||||
of experience across many platforms. To ensure portability, the initial
|
|
||||||
implements were done in parallel using POSIX Threads and theWin32
|
|
||||||
threading API. But the Boost.Threads design is very much in the spirit
|
|
||||||
of C++, and thus doesn't model such C based APIs.</p>
|
|
||||||
|
|
||||||
<h2>2b. Why wasn't Boost.Threads modeled after (specific library
|
|
||||||
name)?</h2>
|
|
||||||
|
|
||||||
<p>Existing C++ libraries either seemed dangerous (often failing to
|
|
||||||
take advantage of prior art to reduce errors) or had excessive
|
|
||||||
dependencies on library components unrelated to threading. Existing C
|
|
||||||
libraries couldn't meet our C++ requirements, and were also missing
|
|
||||||
certain features. For instance, the WIN32 thread API lacks condition
|
|
||||||
variables, even though these are critical for the important Monitor
|
|
||||||
pattern <a href="bibliography.html#Schmidt-00">[Schmidt 00]</a>.</p>
|
|
||||||
|
|
||||||
<h2>3. Why do <a href="mutex_concept.html">Mutexes</a> have noncopyable
|
|
||||||
semantics?</h2>
|
|
||||||
|
|
||||||
<p>To ensure that <a href="definitions.html#Deadlock">deadlocks</a>
|
|
||||||
don't occur. The only logical form of copy would be to use some
|
|
||||||
sort of shallow copy semantics in which multiple mutex objects could
|
|
||||||
refer to the same mutex state. This means that if ObjA has a mutex
|
|
||||||
object as part of its state and ObjB is copy constructed from it, then
|
|
||||||
when ObjB::foo() locks the mutex it has effectively locked ObjA as
|
|
||||||
well. This behavior can result in deadlock. Other copy semantics result
|
|
||||||
in similar problems (if you think you can prove this to be wrong then
|
|
||||||
supply us with an alternative and we'll reconsider).</p>
|
|
||||||
|
|
||||||
<h2>4. How can you prevent <a href="definitions.html#Deadlock">
|
|
||||||
deadlock</a> from occurring when a thread must lock multiple
|
|
||||||
mutexes?</h2>
|
|
||||||
|
|
||||||
<p>Always lock them in the same order. One easy way of doing this is to
|
|
||||||
use each mutex's address to determine the order in which they are
|
|
||||||
locked. A future Boost.Threads concept may wrap this pattern up in a
|
|
||||||
reusable class.</p>
|
|
||||||
|
|
||||||
<h2>5. Don't noncopyable <a href="mutex_concept.html">mutex</a>
|
|
||||||
semantics mean that a class with a mutex member will be noncopyable as
|
|
||||||
well?</h2>
|
|
||||||
|
|
||||||
<p>No, but what it does mean is that the compiler can't generate a
|
|
||||||
copy constructor and assignment operator, so they will have to be coded
|
|
||||||
explicitly. This is a <b>good thing</b>, however, since the compiler
|
|
||||||
generated operations would not be <a href=
|
|
||||||
"definitions.html#Thread-safe">thread-safe</a>. The following is a
|
|
||||||
simple example of a class with copyable semantics and internal
|
|
||||||
synchronization through a mutex member.</p>
|
|
||||||
<pre>
|
|
||||||
class counter
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
// Doesn't need synchronization since there can be no references to *this
|
|
||||||
// until after it's constructed!
|
|
||||||
explicit counter(int initial_value)
|
|
||||||
: m_value(initial_value)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// We only need to syncronize other for the same reason we don't have to
|
|
||||||
// synchronize on construction!
|
|
||||||
counter(const counter& other)
|
|
||||||
{
|
|
||||||
boost::mutex::scoped_lock scoped_lock(other.m_mutex);
|
|
||||||
m_value = other.m_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// For assignment we need to synchronize both objects!
|
|
||||||
const counter& operator=(const counter& other)
|
|
||||||
{
|
|
||||||
if (this == &other)
|
|
||||||
return *this;
|
|
||||||
|
|
||||||
boost::mutex::scoped_lock lock1(&m_mutex < &other.m_mutex ? m_mutex : other.m_mutex);
|
|
||||||
boost::mutex::scoped_lock lock2(&m_mutex > &other.m_mutex ? m_mutex : other.m_mutex);
|
|
||||||
m_value = other.m_value;
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
int value() const
|
|
||||||
{
|
|
||||||
boost::mutex::scoped_lock scoped_lock(m_mutex);
|
|
||||||
return m_value;
|
|
||||||
}
|
|
||||||
int increment()
|
|
||||||
{
|
|
||||||
boost::mutex::scoped_lock scoped_lock(m_mutex);
|
|
||||||
return ++m_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
mutable boost::mutex m_mutex;
|
|
||||||
int m_value;
|
|
||||||
};
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h2>6. How can you lock a <a href="mutex_concept.html">mutex</a> member
|
|
||||||
in a const member function, in order to implement the Monitor
|
|
||||||
Pattern?</h2>
|
|
||||||
|
|
||||||
<p>The Monitor Pattern mutex <a href="bibliography.html#Schmidt-00">
|
|
||||||
[Schmidt 00]</a> should simply be declared as mutable. See the example
|
|
||||||
code above. The internal state of mutex types could have been made
|
|
||||||
mutable, with all lock calls made via const functions, but this does a
|
|
||||||
poor job of documenting the actual semantics. Declaring a mutex member
|
|
||||||
as mutable clearly documentations the intended semantics.</p>
|
|
||||||
|
|
||||||
<h2>7. Why supply <a href="condition.html">condition variables</a>
|
|
||||||
rather than <a href="rationale.html#Events">event variables</a>?</h2>
|
|
||||||
|
|
||||||
<p>Condition variables result in user code much less prone to <a href=
|
|
||||||
"definitions.html#Race condition">race conditions</a> than event
|
|
||||||
variables. See <a href="rationale.html#Events">Rationale</a> for
|
|
||||||
analysis. Also see <a href="bibliography.html#Hoare-74">[Hoare74]</a>
|
|
||||||
and <a href="bibliography.html#Schmidt-00">[Schmidt 00]</a>.</p>
|
|
||||||
|
|
||||||
<h2>8. Why isn't thread cancellation or termination provided?</h2>
|
|
||||||
|
|
||||||
<p>There's a valid need for thread termination, so at some point
|
|
||||||
Boost.Threads probably will include it, but only after we can find a
|
|
||||||
truly safe (and portable) mechanism for this concept.</p>
|
|
||||||
|
|
||||||
<h2>9. Is it safe for threads to share automatic storage duration
|
|
||||||
(stack) objects via pointers or references?</h2>
|
|
||||||
|
|
||||||
<p>Only if you can guarantee that the lifetime of the stack object will
|
|
||||||
not end while other threads might still access the object. Thus the
|
|
||||||
safest practice is to avoid sharing stack objects, particularly in
|
|
||||||
designs where threads are created and destroyed dynamically. Restrict
|
|
||||||
sharing of stack objects to simple designs with very clear and
|
|
||||||
unchanging function and thread lifetimes. (Suggested by Darryl
|
|
||||||
Green).</p>
|
|
||||||
|
|
||||||
<h2>10. Why has class semaphore disappeared?</h2>
|
|
||||||
|
|
||||||
<p>Semaphore was removed as too error prone. The same effect can be
|
|
||||||
achieved with greater safety by the combination of a mutex and a
|
|
||||||
condition variable.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p>Revised
|
|
||||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->05 November, 2001<!--webbot bot="Timestamp" endspan i-checksum="39359" --></p>
|
|
||||||
|
|
||||||
<p><i>© Copyright <a href="mailto:williamkempf@hotmail.com">
|
|
||||||
William E. Kempf</a> 2001 all rights reserved.</i></p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
146
doc/index.html
146
doc/index.html
@@ -1,138 +1,12 @@
|
|||||||
|
<!-- Copyright (c) 2002-2003 Beman Dawes, William E. Kempf.
|
||||||
|
Subject to the Boost Software License, Version 1.0.
|
||||||
|
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
-->
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta http-equiv="Content-Type" content=
|
<meta http-equiv="refresh" content="0; URL=../../../doc/html/thread.html">
|
||||||
"text/html; charset=iso-8859-1">
|
</head>
|
||||||
<meta name="keywords" content="threads, BTL, thread library, C++">
|
<body>
|
||||||
|
Automatic redirection failed, please go to <a href="../../../doc/html/thread.html">../../../doc/html/thread.html</a>
|
||||||
<title>Boost.Threads, Index</title>
|
</body>
|
||||||
</head>
|
|
||||||
|
|
||||||
<body bgcolor="#FFFFFF" link="#0000FF" vlink="#800080">
|
|
||||||
<table summary="header" border="0" cellpadding="7" cellspacing="0"
|
|
||||||
width="100%">
|
|
||||||
<tr>
|
|
||||||
<td valign="top" width="300">
|
|
||||||
<h3><img src="../../../c++boost.gif" alt="C++ Boost" width=
|
|
||||||
"277" height="86"></h3>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td valign="top">
|
|
||||||
<h1 align="center">Boost.Threads</h1>
|
|
||||||
|
|
||||||
<h2 align="center">Documentation Map</h2>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h2>Contents</h2>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li><a href="overview.html">Overview</a></li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
<a href="mutex_concept.html">Mutex Concepts</a>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li><a href="mutex_concept.html#Mutex">Mutex</a></li>
|
|
||||||
|
|
||||||
<li><a href="mutex_concept.html#TryMutex">TryMutex</a></li>
|
|
||||||
|
|
||||||
<li><a href="mutex_concept.html#TimedMutex">
|
|
||||||
TimedMutex</a></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
Mutex Classes
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li><a href="mutex.html">mutex / try_mutex /
|
|
||||||
timed_mutex</a></li>
|
|
||||||
|
|
||||||
<li><a href="recursive_mutex.html">recursive_mutex /
|
|
||||||
recursive_try_mutex / recursive_timed_mutex</a></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
<a href="lock_concept.html">Lock Concepts</a>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li><a href="lock_concept.html#Lock">Lock</a></li>
|
|
||||||
|
|
||||||
<li><a href="lock_concept.html#ScopedLock">
|
|
||||||
ScopedLock</a></li>
|
|
||||||
|
|
||||||
<li><a href="lock_concept.html#ScopedTryLock">
|
|
||||||
ScopedTryLock</a></li>
|
|
||||||
|
|
||||||
<li><a href="lock_concept.html#ScopedTimedLock">
|
|
||||||
ScopedTimedLock</a></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
Lock Classes
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li><a href="scoped_lock.html">scoped_lock</a></li>
|
|
||||||
|
|
||||||
<li><a href="scoped_try_lock.html">scoped_try_lock</a></li>
|
|
||||||
|
|
||||||
<li><a href="scoped_timed_lock.html">
|
|
||||||
scoped_timed_lock</a></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>Class <a href="condition.html">condition</a></li>
|
|
||||||
|
|
||||||
<li>Class <a href="thread_specific_ptr.html">
|
|
||||||
thread_specific_ptr</a></li>
|
|
||||||
|
|
||||||
<li>Class <a href="thread.html">thread</a></li>
|
|
||||||
|
|
||||||
<li>Class <a href="thread_group.html">thread_group</a></li>
|
|
||||||
|
|
||||||
<li>Class <a href="xtime.html">xtime</a></li>
|
|
||||||
|
|
||||||
<li>Class <a href="lock_error.html">lock_error</a></li>
|
|
||||||
|
|
||||||
<li>Class <a href="thread_resource_error.html">
|
|
||||||
thread_resource_error</a></li>
|
|
||||||
|
|
||||||
<li>Routine <a href="call_once.html">call_once</a></li>
|
|
||||||
|
|
||||||
<li><a href="config.html">Configuration Information</a></li>
|
|
||||||
|
|
||||||
<li><a href="introduction.html">Introduction to design</a></li>
|
|
||||||
|
|
||||||
<li><a href="rationale.html">Rationale for design
|
|
||||||
decisions</a></li>
|
|
||||||
|
|
||||||
<li><a href="definitions.html">Definitions</a></li>
|
|
||||||
|
|
||||||
<li><a href="faq.html">Frequently Asked Questions</a></li>
|
|
||||||
|
|
||||||
<li><a href="bibliography.html">Bibliography</a></li>
|
|
||||||
|
|
||||||
<li><a href="acknowledgements.html">Acknowledgements</a></li>
|
|
||||||
</ul>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p>Revised
|
|
||||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->05 November, 2001<!--webbot bot="Timestamp" endspan i-checksum="39359" --></p>
|
|
||||||
|
|
||||||
<p>© <i>Copyright <a href="mailto:williamkempf@hotmail.com">
|
|
||||||
William E. Kempf</a> 2001</i></p>
|
|
||||||
|
|
||||||
<p>Permission to use, copy, modify, distribute and sell this software
|
|
||||||
and its documentation for any purpose is hereby granted without fee,
|
|
||||||
provided that the above copyright notice appear in all copies and that
|
|
||||||
both that copyright notice and this permission notice appear in
|
|
||||||
supporting documentation. William E. Kempf makes no representations
|
|
||||||
about the suitability of this software for any purpose. It is provided
|
|
||||||
"as is" without express or implied warranty.</p>
|
|
||||||
</body>
|
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|||||||
@@ -1,194 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content=
|
|
||||||
"text/html; charset=iso-8859-1">
|
|
||||||
<meta name="keywords" content="threads, BTL, thread library, C++">
|
|
||||||
|
|
||||||
<title>Boost.Threads, Introduction</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body bgcolor="#ffffff" link="#0000ff" vlink="#800080">
|
|
||||||
<table summary="header" border="0" cellpadding="7" cellspacing="0"
|
|
||||||
width="100%">
|
|
||||||
<tr>
|
|
||||||
<td valign="top" width="300">
|
|
||||||
<h3><img height="86" alt="C++ Boost" src=
|
|
||||||
"../../../c++boost.gif" width="277"></h3>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td valign="top">
|
|
||||||
<h1 align="center">Boost.Threads</h1>
|
|
||||||
|
|
||||||
<h2 align="center">Introduction</h2>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>Motivation</h3>
|
|
||||||
|
|
||||||
<p>With client/server and three-tier architectures becoming common
|
|
||||||
place in today's world, it's becoming increasingly important
|
|
||||||
for programs to be able to handle parallel processing. Modern day
|
|
||||||
operating systems usually provide some support for this through native
|
|
||||||
thread APIs. Unfortunately, writing portable code that makes use of
|
|
||||||
parallel processing in C++ is made very difficult by a lack of a
|
|
||||||
standard interface for these native APIs. Further, these APIs are
|
|
||||||
almost universally C APIs and fail to take advantage of C++'s
|
|
||||||
strengths, or to address C++'s issues.</p>
|
|
||||||
|
|
||||||
<p>The <b>Boost.Threads</b> library is an attempt to define a portable
|
|
||||||
interface for writing parallel processes in C++.</p>
|
|
||||||
|
|
||||||
<h3>Goals</h3>
|
|
||||||
|
|
||||||
<p>The <b>Boost.Threads</b> library has several goals that should help
|
|
||||||
to set it apart from other solutions. These goals are listed in order
|
|
||||||
of precedence with full descriptions below.</p>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<b>Portability</b>
|
|
||||||
|
|
||||||
<p><b>Boost.Threads</b> was designed to be highly portable. The
|
|
||||||
goal is for the interface to be easily implemented on any
|
|
||||||
platform that supports threads, and possibly even on platforms
|
|
||||||
without native thread support.</p>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
<b>Safety</b>
|
|
||||||
|
|
||||||
<p><b>Boost.Threads</b> was designed to be as safe as possible.
|
|
||||||
Writing <a href="definitions.html#Thread-safe">thread-safe</a>
|
|
||||||
code is very difficult and successful libraries must strive to
|
|
||||||
insulate the programmer from dangerous constructs as much as
|
|
||||||
possible. This is accomplished in several ways:</p>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<p align="left">C++ language features are used make
|
|
||||||
correct usage easy (if possible, the default) and
|
|
||||||
error-prone impossible or at least more difficult. For
|
|
||||||
example, see the <a href="mutex_concept.html">Mutex</a>
|
|
||||||
and <a href="lock_concept.html">Lock</a> designs, and
|
|
||||||
how note how they interact.</p>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
<p align="left">Certain traditional concurrent
|
|
||||||
programming features are considered so error-prone that
|
|
||||||
they are not provided at all. For example, see the <a
|
|
||||||
href="rationale.html#Events">Events Not Provided</a>
|
|
||||||
rationale.</p>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
<p align="left">Dangerous features, or features which
|
|
||||||
may be misused, are identified as such in the
|
|
||||||
documentation to make users aware of potential
|
|
||||||
pitfalls.</p>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
<b>Flexibility</b>
|
|
||||||
|
|
||||||
<p><b>Boost.Threads</b> was designed to be flexible. This goal
|
|
||||||
is often at odds with <i>safety</i>. When functionality might
|
|
||||||
be compromised by the desire to keep the interface safe, <b>
|
|
||||||
Boost.Threads</b> has been designed to provide the
|
|
||||||
functionality, but to make it's use prohibitive for general
|
|
||||||
use.</p>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
<b>Efficiency</b>
|
|
||||||
|
|
||||||
<p><b>Boost.Threads</b> was designed to be as efficient as
|
|
||||||
possible. When building a library on top of another library
|
|
||||||
there is always a danger that the result will be so much slower
|
|
||||||
than the "native" API that programmers are inclined
|
|
||||||
to ignore the higher level API. <b>Boost.Threads</b> was
|
|
||||||
designed to minimize the chances of this occurring. The
|
|
||||||
interfaces have been crafted to allow an implementation the
|
|
||||||
greatest chance of being as efficient as possible. This goal is
|
|
||||||
often at odds with the goal for <i>safety</i>. Every effort was
|
|
||||||
made to ensure efficient implementations, but when in conflict
|
|
||||||
<i>safety</i> has always taken precedence.</p>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<h3>Iterative Phases</h3>
|
|
||||||
|
|
||||||
<p>Another goal of <b>Boost.Threads</b> was to take a dynamic,
|
|
||||||
iterative approach in its development. The computing industry is still
|
|
||||||
exploring the concepts of parallel programming. Most thread libraries
|
|
||||||
supply only simple primitive concepts for thread synchronization. These
|
|
||||||
concepts are very simple, but they are very difficult to use safely or
|
|
||||||
to provide formal proofs for constructs built on top of them. Until
|
|
||||||
recently, these primitives were "state of the art" and the
|
|
||||||
only concepts available to programmers. Recently there has been a lot
|
|
||||||
of research in other concepts, such as in "Communicating
|
|
||||||
Sequential Processes." <b>Boost.Threads</b> was designed in
|
|
||||||
iterative steps, providing the building blocks necessary for the next
|
|
||||||
step, and giving the researcher the tools necessary to explore new
|
|
||||||
concepts in a portable manner.</p>
|
|
||||||
|
|
||||||
<p>Given the goal of following a dynamic, iterative approach <b>
|
|
||||||
Boost.Threads</b> shall go through several growth cycles. Each phase in
|
|
||||||
its development shall be roughly documented here.</p>
|
|
||||||
|
|
||||||
<h4>Phase 1, Synchronization Primitives</h4>
|
|
||||||
|
|
||||||
<p>Boost is all about providing high quality libraries with
|
|
||||||
implementations for many platforms. Unfortunately, there's a big
|
|
||||||
problem faced by developers wishing to supply such high quality
|
|
||||||
libraries, namely thread-safety. The C++ standard doesn't address
|
|
||||||
threads at all, but real world programs often make use of native
|
|
||||||
threading support. A portable library that doesn't address the
|
|
||||||
issue of thread-safety is there for not much help to a programmer who
|
|
||||||
wants to use the library in his multi-threaded application. So
|
|
||||||
there's a very great need for portable primitives that will allow
|
|
||||||
the library developer to create <a href="definitions.html#Thread-safe">
|
|
||||||
thread-safe</a> implementations. This need far out weighs the need for
|
|
||||||
portable methods to create and manage threads.</p>
|
|
||||||
|
|
||||||
<p>Because of this need, the first phase of <b>Boost.Threads</b>
|
|
||||||
focuses solely on providing portable primitive concepts for thread
|
|
||||||
synchronization. Types provided in this phase include the <a href="mutex.html">
|
|
||||||
mutex/try_mutex/timed_mutex</a>, <a href="recursive_mutex.html">
|
|
||||||
recursive_mutex/recursive_try_mutex/recursive_timed_mutex</a>, <a href=
|
|
||||||
"scoped_lock.html">scoped_lock</a>, <a href="scoped_try_lock.html">
|
|
||||||
scoped_try_lock</a>, <a href="scoped_timed_lock.html">
|
|
||||||
scoped_timed_lock</a> and <a href="lock_error.html">lock_error</a>.
|
|
||||||
These are considered the "core" synchronization primitives,
|
|
||||||
though there are others that will be added in later phases.</p>
|
|
||||||
|
|
||||||
<h4>Phase 2, Thread Management and Thread Specific Storage</h4>
|
|
||||||
|
|
||||||
<p>This phase addresses the creation and management of threads and
|
|
||||||
provides a mechanism for thread specific storage (data associated with
|
|
||||||
a thread instance). Thread management is a tricky issue in C++, so this
|
|
||||||
phase addresses only the basic needs of multi-threaded program. Later
|
|
||||||
phases are likely to add additional functionality in this area. This
|
|
||||||
phase of <b>Boost.Threads</b> adds the <a href="thread.html">thread</a>
|
|
||||||
and <a href="thread_specific_ptr.html">thread_specific_ptr</a> types.
|
|
||||||
With these additions the <b>Boost.Threads</b> library can be considered
|
|
||||||
minimal but complete.</p>
|
|
||||||
|
|
||||||
<h4>The Next Phase</h4>
|
|
||||||
|
|
||||||
<p>The next phase will address more advanced synchronization concepts,
|
|
||||||
such as read/write mutexes and barriers.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p>Revised
|
|
||||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->05 November, 2001<!--webbot bot="Timestamp" endspan i-checksum="39359" --></p>
|
|
||||||
|
|
||||||
<p><i>© Copyright <a href="mailto:williamkempf@hotmail.com">
|
|
||||||
William E. Kempf</a> 2001 all rights reserved.</i></p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
@@ -1,300 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content=
|
|
||||||
"text/html; charset=iso-8859-1">
|
|
||||||
<meta name="keywords" content="threads, BTL, thread library, C++">
|
|
||||||
|
|
||||||
<title>Boost.Threads, Lock Concept</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body bgcolor="#FFFFFF" link="#0000FF" vlink="#800080">
|
|
||||||
<table summary="header" border="0" cellpadding="7" cellspacing="0"
|
|
||||||
width="100%">
|
|
||||||
<tr>
|
|
||||||
<td valign="top" width="300">
|
|
||||||
<h3><img src="../../../c++boost.gif" alt="C++ Boost" width=
|
|
||||||
"277" height="86"></h3>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td valign="top">
|
|
||||||
<h1 align="center">Boost.Threads</h1>
|
|
||||||
|
|
||||||
<h2 align="center">Lock Concepts</h2>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p><a href="#Introduction">Introduction</a><br>
|
|
||||||
<a href="#Requirements">Concept Requirements</a><br>
|
|
||||||
<a href="#Lock">Lock Concept</a><br>
|
|
||||||
<a href="#ScopedLock">ScopedLock Concept</a><br>
|
|
||||||
<a href="#ScopedTryLock">ScopedTryLock Concept</a><br>
|
|
||||||
<a href="#ScopedTimedLock">ScopedTimedLock Concept</a><br>
|
|
||||||
<a href="#Models">Models</a></p>
|
|
||||||
|
|
||||||
<h2><a name="Introduction">Introduction</a></h2>
|
|
||||||
|
|
||||||
<p>The lock concepts provide exception safe means for locking and
|
|
||||||
unlocking a <a href="mutex_concept.html">mutex model</a>. In other
|
|
||||||
words they are an implementation of the <i>Scoped Locking</i> <a href=
|
|
||||||
"bibliography.html#Schmidt 00">[Schmidt 00]</a> pattern. The <a href=
|
|
||||||
"#ScopedLock">ScopedLock</a> concept, with <a href="#ScopedTryLock">
|
|
||||||
ScopedTryLock</a> and <a href="#ScopedTimedLock">ScopedTimedLock</a>
|
|
||||||
refinements, formalize the requirements.</p>
|
|
||||||
|
|
||||||
<p>Lock models are constructed with a reference to a <a href=
|
|
||||||
"mutex_concept.html">mutex model</a> and typically acquire ownership of
|
|
||||||
the <a href="mutex_concept.html">mutex model</a> by setting its state
|
|
||||||
to locked. They also ensure ownership is relinquished in the
|
|
||||||
destructor. Lock models also expose functions to query the lock status
|
|
||||||
and to manually lock and unlock the <a href="mutex_concept.html">mutex
|
|
||||||
model</a>.</p>
|
|
||||||
|
|
||||||
<p>Instances of lock models are meant to be short lived, expected to be
|
|
||||||
used at block scope only. The lock models are not <a href=
|
|
||||||
"definitions.html#Thread-safe">thread-safe</a>. Lock models must
|
|
||||||
maintain state to indicate whether or not they've been locked and
|
|
||||||
this state is not protected by any synchronization concepts. For this
|
|
||||||
reason an instance of a lock model should never be shared between
|
|
||||||
multiple threads.</p>
|
|
||||||
|
|
||||||
<h2>Concept <a name="Requirements">Requirements</a></h2>
|
|
||||||
|
|
||||||
<p>[For documentation purposes, portions of the concept requirements
|
|
||||||
are repeated in the documentation for specific lock classes. Those
|
|
||||||
copies need to be kept in sync with the requirements here.]</p>
|
|
||||||
|
|
||||||
<h3><a name="Lock">Lock</a> Concept</h3>
|
|
||||||
|
|
||||||
<p>For a <a href="#ScopedLock">ScopedLock</a>, <a href=
|
|
||||||
"#ScopedTryLock">ScopedTryLock</a>, or <a href="#ScopedTimedLock">
|
|
||||||
ScopedTimedLock</a> type <code>L</code> and an object <code>lk</code>
|
|
||||||
and const object <code>clk</code> of that type, the following
|
|
||||||
expressions must be well-formed and have the indicated effects.</p>
|
|
||||||
|
|
||||||
<p>The Lock concept is used as a base for the <a href="#ScopedLock">
|
|
||||||
ScopedLock</a>, <a href="#ScopedTryLock">ScopedTryLock</a>, and <a
|
|
||||||
href="#ScopedTimedLock">ScopedTimedLock</a> refinements. The associated
|
|
||||||
mutex type is as specified for each of those refinements
|
|
||||||
respectively.</p>
|
|
||||||
|
|
||||||
<table summary="Lock expressions" border="1" cellpadding="5">
|
|
||||||
<tr>
|
|
||||||
<td><b>Expression</b></td>
|
|
||||||
|
|
||||||
<td><b>Effects</b></td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td valign="top"><code>(&lk)->~L();</code></td>
|
|
||||||
|
|
||||||
<td><code>if (locked()) unlock();</code></td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td valign="top"><code>(&clk)->operator const
|
|
||||||
void*()</code></td>
|
|
||||||
|
|
||||||
<td>Returns type void*, non-zero if if the associated mutex has
|
|
||||||
been locked by <code>clk</code>, otherwise 0.</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td valign="top"><code>clk.locked()</code></td>
|
|
||||||
|
|
||||||
<td>Returns a <code>bool</code>, <code>(&clk)->operator
|
|
||||||
const void*() != 0</code></td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td valign="top"><code>lk.lock()</code></td>
|
|
||||||
|
|
||||||
<td>Throws lock_error if locked(). If the associated mutex is
|
|
||||||
already locked by some other thread, places the current thread
|
|
||||||
in the <a href="definitions.html#State">Blocked</a> state until
|
|
||||||
the associated mutex is unlocked, after which the current
|
|
||||||
thread is placed in the <a href="definitions.html#State">
|
|
||||||
Ready</a> state, eventually to be returned to the <a href=
|
|
||||||
"definitions.html#State">Running</a> state.<br>
|
|
||||||
Postcondition: locked()</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td valign="top"><code>lk.unlock()</code></td>
|
|
||||||
|
|
||||||
<td>If !locked(), throws lock_error, otherwise unlocks the
|
|
||||||
associated mutex.<br>
|
|
||||||
Postcondition: !locked()</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<h3><a name="ScopedLock">ScopedLock</a> Concept</h3>
|
|
||||||
|
|
||||||
<p>A ScopedLock must meet the <a href="#Lock">Lock</a> requirements.
|
|
||||||
For a ScopedLock type <code>L</code> and an object <code>lk</code> of
|
|
||||||
that type, and an object <code>m</code> of a type meeting the <a href=
|
|
||||||
"mutex_concept.html#Mutex">Mutex</a> requirements, and an object <code>
|
|
||||||
b</code> of type <code>bool</code>, the following expressions must be
|
|
||||||
well-formed and have the indicated effects.</p>
|
|
||||||
|
|
||||||
<table summary="ScopedLock expressions" border="1" cellpadding="5">
|
|
||||||
<tr>
|
|
||||||
<td><b>Expression</b></td>
|
|
||||||
|
|
||||||
<td><b>Effects</b></td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td valign="top"><code>L lk(m);</code></td>
|
|
||||||
|
|
||||||
<td>Constructs an object <code>lk</code>, and associates mutex
|
|
||||||
<code>m</code> with it, then calls <code>lock()</code></td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td valign="top"><code>L lk(m,b);</code></td>
|
|
||||||
|
|
||||||
<td>Constructs an object <code>lk</code>, and associates mutex
|
|
||||||
<code>m</code> with it, then if <code>b</code>, calls <code>
|
|
||||||
lock()</code></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<h3><a name="ScopedTryLock">ScopedTryLock</a> Concept</h3>
|
|
||||||
|
|
||||||
<p>A ScopedTryLock must meet the <a href="#Lock">Lock</a> requirements.
|
|
||||||
For a ScopedTryLock type <code>L</code> and an object <code>lk</code>
|
|
||||||
of that type, and an object <code>m</code> of a type meeting the <a
|
|
||||||
href="mutex_concept.html#TryMutex">TryMutex</a> requirements, and an
|
|
||||||
object <code>b</code> of type <code>bool</code>, the following
|
|
||||||
expressions must be well-formed and have the indicated effects.</p>
|
|
||||||
|
|
||||||
<table summary="ScopedTryLock expressions" border="1" cellpadding="5">
|
|
||||||
<tr>
|
|
||||||
<td><b>Expression</b></td>
|
|
||||||
|
|
||||||
<td><b>Effects</b></td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td valign="top"><code>L lk(m);</code></td>
|
|
||||||
|
|
||||||
<td>Constructs an object <code>lk</code>, and associates mutex
|
|
||||||
<code>m</code> with it, then calls <code>try_lock()</code></td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td valign="top"><code>L lk(m,b);</code></td>
|
|
||||||
|
|
||||||
<td>Constructs an object <code>lk</code>, and associates mutex
|
|
||||||
<code>m</code> with it, then if <code>b</code>, calls <code>
|
|
||||||
lock()</code></td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td valign="top"><code>lk.try_lock()</code></td>
|
|
||||||
|
|
||||||
<td>If locked(), throws <code>lock_error</code>. Makes a
|
|
||||||
non-blocking attempt to lock the associated mutex, returning
|
|
||||||
<code>true</code> if the lock attempt is successful, otherwise
|
|
||||||
<code>false</code>.</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<h3><a name="ScopedTimedLock">ScopedTimedLock</a> Concept</h3>
|
|
||||||
|
|
||||||
<p>A ScopedTimedLock must meet the <a href="#Lock">Lock</a>
|
|
||||||
requirements. For a ScopedTimedLock type <code>L</code> and an object
|
|
||||||
<code>lk</code> of that type, and an object <code>m</code> of a type
|
|
||||||
meeting the <a href="mutex_concept.html#TimedMutex">TimedMutex</a>
|
|
||||||
requirements, and an object <code>b</code> of type <code>bool</code>,
|
|
||||||
and an object <code>t</code> of type <code><a href="xtime.html">
|
|
||||||
xtime</a></code>, the following expressions must be well-formed and
|
|
||||||
have the indicated effects.</p>
|
|
||||||
|
|
||||||
<table summary="ScopedTimedLock expressions" border="1" cellpadding=
|
|
||||||
"5">
|
|
||||||
<tr>
|
|
||||||
<td><b>Expression</b></td>
|
|
||||||
|
|
||||||
<td><b>Effects</b></td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td valign="top"><code>L lk(m,t);</code></td>
|
|
||||||
|
|
||||||
<td>Constructs an object <code>lk</code>, and associates mutex
|
|
||||||
<code>m</code> with it, then calls <code>
|
|
||||||
timed_lock(t)</code></td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td valign="top"><code>L lk(m,b);</code></td>
|
|
||||||
|
|
||||||
<td>Constructs an object <code>lk</code>, and associates mutex
|
|
||||||
<code>m</code> with it, then if <code>b</code>, calls <code>
|
|
||||||
lock()</code></td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td valign="top"><code>lk.timed_lock(t)</code></td>
|
|
||||||
|
|
||||||
<td>If locked(), throws lock_error. Makes a blocking attempt to
|
|
||||||
lock the associated mutex, and returns <code>true</code> if
|
|
||||||
successful within the specified time <code>t</code>, otherwise
|
|
||||||
<code>false</code>.</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<h2><a name="Models">Models</a></h2>
|
|
||||||
|
|
||||||
<p><b>Boost.Threads</b> currently supplies three classes which model
|
|
||||||
lock concepts.</p>
|
|
||||||
|
|
||||||
<p>These classes are normally accessed via typedefs of the same name
|
|
||||||
supplied by a <a href="mutex_concept.html">mutex model</a>.</p>
|
|
||||||
|
|
||||||
<table summary="Lock concept classes" border="1" cellpadding="5">
|
|
||||||
<tr>
|
|
||||||
<td><b>Concept</b></td>
|
|
||||||
|
|
||||||
<td><b>Refines</b></td>
|
|
||||||
|
|
||||||
<td><b>Classes Modeling the Concept</b></td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td><a href="#ScopedLock">ScopedLock</a></td>
|
|
||||||
|
|
||||||
<td> </td>
|
|
||||||
|
|
||||||
<td><a href="scoped_lock.html">scoped_lock</a></td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td><a href="#ScopedTryLock">ScopedTryLock</a></td>
|
|
||||||
|
|
||||||
<td><a href="#ScopedLock">ScopedLock</a></td>
|
|
||||||
|
|
||||||
<td><a href="scoped_try_lock.html">scoped_try_lock</a> </td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td><a href="#ScopedTimedLock">ScopedTimedLock</a></td>
|
|
||||||
|
|
||||||
<td><a href="#ScopedLock">ScopedLock</a></td>
|
|
||||||
|
|
||||||
<td><a href="scoped_timed_lock.html">scoped_timed_lock</a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p>Revised
|
|
||||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->05 November, 2001<!--webbot bot="Timestamp" endspan i-checksum="39359" --></p>
|
|
||||||
|
|
||||||
<p><i>© Copyright <a href="mailto:williamkempf@hotmail.com">
|
|
||||||
William E. Kempf</a> 2001 all rights reserved.</i></p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
@@ -1,110 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content=
|
|
||||||
"text/html; charset=iso-8859-1">
|
|
||||||
<meta name="keywords" content="threads, BTL, thread library, C++">
|
|
||||||
<link rel="stylesheet" type="text/css" href="styles.css">
|
|
||||||
|
|
||||||
<title>Boost.Threads, lock_error</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body bgcolor="#FFFFFF" link="#0000FF" vlink="#800080">
|
|
||||||
<table summary="header" border="0" cellpadding="7" cellspacing="0"
|
|
||||||
width="100%">
|
|
||||||
<tr>
|
|
||||||
<td valign="top" width="300">
|
|
||||||
<h3><img src="../../../c++boost.gif" alt="C++ Boost" width=
|
|
||||||
"277" height="86"></h3>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td valign="top">
|
|
||||||
<h1 align="center">Boost.Threads</h1>
|
|
||||||
|
|
||||||
<h2 align="center">lock_error</h2>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p><a href="#Introduction">Introduction</a><br>
|
|
||||||
<a href="#Header">Header</a><br>
|
|
||||||
<a href="#Synopsis">Synopsis</a><br>
|
|
||||||
<a href="#Members">Members</a><br>
|
|
||||||
<a href="#Example">Example</a></p>
|
|
||||||
|
|
||||||
<h2><a name="Introduction">Introduction</a></h2>
|
|
||||||
|
|
||||||
<p>The <tt>lock_error</tt> class defines an exception type thrown to
|
|
||||||
indicate a locking related error has been detected. Examples of such
|
|
||||||
errors include a lock operation which can be determined to result in a
|
|
||||||
deadlock, or unlock operations attempted by a thread that does not own
|
|
||||||
the lock.</p>
|
|
||||||
|
|
||||||
<h2><a name="Header">Header</a></h2>
|
|
||||||
<pre>
|
|
||||||
#include <a href=
|
|
||||||
"../../../boost/thread/thread.hpp"><boost/thread/thread.hpp></a>
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h2><a name="Synopsis">Synopsis</a></h2>
|
|
||||||
<pre>
|
|
||||||
namespace boost
|
|
||||||
|
|
||||||
class lock_error : public std::runtime_error
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
lock_error();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h2><a name="Members">Members</a></h2>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>Constructor</h3>
|
|
||||||
<pre>
|
|
||||||
lock_error();
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>Constructs a <tt>lock_error</tt> object.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h2><a name="Example">Example</a> Usage</h2>
|
|
||||||
<pre>
|
|
||||||
#include <a href=
|
|
||||||
"../../../boost/thread/mutex.hpp"><boost/thread/mutex.hpp></a>
|
|
||||||
#include <a href=
|
|
||||||
"../../../boost/thread/thread.hpp"><boost/thread/thread.hpp></a>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
int main(int, char*[])
|
|
||||||
{
|
|
||||||
boost::mutex mutex;
|
|
||||||
boost::mutex::scoped_lock scoped_lock(mutex);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
boost::mutex::scoped_lock deadlock(mutex);
|
|
||||||
std::cout << "lock succeeded" << std::endl;
|
|
||||||
}
|
|
||||||
catch (boost::lock_error& err)
|
|
||||||
{
|
|
||||||
std::cout << err.what() << " - deadlock occurred." << std::endl;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>The output is:</p>
|
|
||||||
<pre>
|
|
||||||
thread lock error - deadlock occurred.
|
|
||||||
</pre>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p>Revised
|
|
||||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->05 November, 2001<!--webbot bot="Timestamp" endspan i-checksum="39359" --></p>
|
|
||||||
|
|
||||||
<p><i>© Copyright <a href="mailto:williamkempf@hotmail.com">
|
|
||||||
William E. Kempf</a> 2001 all rights reserved.</i></p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
359
doc/mutex.html
359
doc/mutex.html
@@ -1,359 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content=
|
|
||||||
"text/html; charset=iso-8859-1">
|
|
||||||
<meta name="keywords" content="threads, BTL, thread library, C++">
|
|
||||||
<link rel="stylesheet" type="text/css" href="styles.css">
|
|
||||||
|
|
||||||
<title>Boost.Threads, mutex</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body bgcolor="#ffffff" link="#0000ff" vlink="#800080">
|
|
||||||
<table summary="header" border="0" cellpadding="7" cellspacing="0"
|
|
||||||
width="100%">
|
|
||||||
<tr>
|
|
||||||
<td valign="top" width="300">
|
|
||||||
<h3><img alt="C++ Boost" src="../../../c++boost.gif" width=
|
|
||||||
"277" height="86"></h3>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td valign="top">
|
|
||||||
<h1 align="center">Boost.Threads</h1>
|
|
||||||
|
|
||||||
<h2 align="center">mutex<br>
|
|
||||||
try_mutex<br>
|
|
||||||
timed_mutex</h2>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p><a href="#Introduction">Introduction</a><br>
|
|
||||||
<a href="#Header">Header</a><br>
|
|
||||||
<a href="#mutex Synopsis">Class mutex Synopsis</a><br>
|
|
||||||
<a href="#mutex Members">Class mutex Members</a><br>
|
|
||||||
<a href="#try_mutex Synopsis">Class try_mutex Synopsis</a><br>
|
|
||||||
<a href="#try_mutex Members">Class try_mutex Members</a><br>
|
|
||||||
<a href="#timed_mutex Synopsis">Class timed_mutex Synopsis</a><br>
|
|
||||||
<a href="#timed_mutex Members">Class timed_mutex Members</a><br>
|
|
||||||
<a href="#Example">Example</a></p>
|
|
||||||
|
|
||||||
<h2><a name="Introduction">Introduction</a></h2>
|
|
||||||
|
|
||||||
<p>The <tt><a href="#mutex Synopsis">mutex</a></tt>, <tt><a href=
|
|
||||||
"#try_mutex Synopsis">try_mutex</a></tt> and <tt><a href=
|
|
||||||
"#timed_mutex Synopsis">timed_mutex</a></tt> classes define full
|
|
||||||
featured models of the <a href="mutex_concept.html#Mutex">Mutex</a>, <a
|
|
||||||
href="mutex_concept.html#TryMutex">TryMutex</a>, and <a href=
|
|
||||||
"mutex_concept.html#TimedMutex">TimedMutex</a> concepts. These types
|
|
||||||
should be used to non-recursively synchronize access to shared
|
|
||||||
resources. For recursive locking mechanics, see <a href=
|
|
||||||
"recursive_mutex.html">recursive mutexes</a>.</p>
|
|
||||||
|
|
||||||
<p>Each class supplies one or more typedefs for lock types which model
|
|
||||||
matching lock concepts. For the best possible performance you should
|
|
||||||
use the mutex class that supports the minimum set of lock types that
|
|
||||||
you need.</p>
|
|
||||||
|
|
||||||
<table summary="lock types" border="1" cellpadding="5">
|
|
||||||
<tr>
|
|
||||||
<td><b>Mutex Class</b></td>
|
|
||||||
|
|
||||||
<td><b>Lock name</b></td>
|
|
||||||
|
|
||||||
<td><b>Implementation defined Lock Type</b></td>
|
|
||||||
|
|
||||||
<td><b>Lock Concept</b></td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td valign="top"><a href="#mutex Synopsis"><code>
|
|
||||||
mutex</code></a></td>
|
|
||||||
|
|
||||||
<td valign="middle"><code>scoped_lock</code></td>
|
|
||||||
|
|
||||||
<td valign="middle"><code><a href="scoped_lock.html">
|
|
||||||
boost::</a></code><a href=
|
|
||||||
"scoped_lock.html"><code>detail::thread::scoped_lock<mutex></code></a></td>
|
|
||||||
|
|
||||||
<td valign="middle"><a href="lock_concept.html#ScopedLock">
|
|
||||||
ScopedLock</a></td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td valign="top"><tt><a href="#try_mutex Synopsis">
|
|
||||||
try_mutex</a></tt> </td>
|
|
||||||
|
|
||||||
<td valign="middle"><code>scoped_lock<br>
|
|
||||||
scoped_try_lock</code></td>
|
|
||||||
|
|
||||||
<td valign="middle"><code><a href="scoped_lock.html">
|
|
||||||
boost::</a></code><a href=
|
|
||||||
"scoped_lock.html"><code>detail::thread::scoped_lock<try_mutex><br>
|
|
||||||
|
|
||||||
</code></a> <code><a href="scoped_try_lock.html">
|
|
||||||
boost::detail::thread::scoped_try_lock<try_mutex></a></code></td>
|
|
||||||
|
|
||||||
<td valign="middle"><a href="lock_concept.html#ScopedLock">
|
|
||||||
ScopedLock</a><br>
|
|
||||||
<a href="lock_concept.html#ScopedTryLock">
|
|
||||||
ScopedTryLock</a></td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td valign="top"><code><a href="#timed_mutex Synopsis">
|
|
||||||
timed_mutex</a></code> </td>
|
|
||||||
|
|
||||||
<td valign="middle"><code>scoped_lock<br>
|
|
||||||
scoped_try_lock<br>
|
|
||||||
scoped_timed_lock</code></td>
|
|
||||||
|
|
||||||
<td valign="middle"><code><a href="scoped_lock.html">
|
|
||||||
boost::</a></code><a href=
|
|
||||||
"scoped_lock.html"><code>detail::thread::scoped_lock<timed_mutex></code></a><br>
|
|
||||||
|
|
||||||
<code><a href="scoped_try_lock.html">boost::</a></code><a
|
|
||||||
href=
|
|
||||||
"scoped_try_lock.html"><code>detail::thread::scoped_try_lock<timed_mutex></code></a><br>
|
|
||||||
|
|
||||||
<code><a href="scoped_timed_lock.html">boost::</a></code><a
|
|
||||||
href=
|
|
||||||
"scoped_timed_lock.html"><code>detail::thread::scoped_timed_lock<timed_mutex></code></a></td>
|
|
||||||
|
|
||||||
<td valign="middle"><a href="lock_concept.html#ScopedLock">
|
|
||||||
ScopedLock</a><br>
|
|
||||||
<a href="lock_concept.html#ScopedTryLock">
|
|
||||||
ScopedTryLock</a><br>
|
|
||||||
<a href="lock_concept.html#ScopedTimedLock">
|
|
||||||
ScopedTimedLock</a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<p>The <tt>mutex</tt>, <tt>try_mutex</tt> and <tt>timed_mutex</tt>
|
|
||||||
classes use an <tt>Unspecified</tt> <a href=
|
|
||||||
"mutex_concept.html#LockingStrategies">locking strategy</a>, so
|
|
||||||
attempts to recursively lock them or attempts to unlock them by threads
|
|
||||||
that don't own a lock on them result in <b>undefined behavior</b>.
|
|
||||||
This strategy allows implementations to be as efficient as possible on
|
|
||||||
any given platform. It is, however, recommended that implementations
|
|
||||||
include debugging support to detect misuse when <tt>NDEBUG</tt> is not
|
|
||||||
defined.</p>
|
|
||||||
|
|
||||||
<p>Like all the <b>Boost.Threads</b> <a href="mutex_concept.html">mutex
|
|
||||||
models</a>, the <tt>mutex</tt>, <tt>try_mutex</tt> and <tt>
|
|
||||||
timed_mutex</tt> leave the <a href=
|
|
||||||
"mutex_concept.html#SchedulingPolicies">scheduling policy</a> as <tt>
|
|
||||||
Unspecified</tt>. Programmers should assume that threads waiting for a
|
|
||||||
lock on objects of these types acquire the lock in a random order, even
|
|
||||||
though the specific behavior for a given platform may be different.</p>
|
|
||||||
|
|
||||||
<h2><a name="Header">Header</a></h2>
|
|
||||||
<pre>
|
|
||||||
#include <a href=
|
|
||||||
"../../../boost/thread/mutex.hpp"><boost/thread/mutex.hpp></a>
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h2>Class <a name="mutex Synopsis">mutex Synopsis</a></h2>
|
|
||||||
<pre>
|
|
||||||
namespace boost
|
|
||||||
{
|
|
||||||
class mutex : private <a href=
|
|
||||||
"../../utility/utility.htm">boost::noncopyable</a> // Exposition only.
|
|
||||||
// Class mutex meets the <a href=
|
|
||||||
"overview.html#NonCopyable">NonCopyable</a> requirement.
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef <i>[implementation defined; see <a href=
|
|
||||||
"#Introduction">Introduction</a>]</i> scoped_lock;
|
|
||||||
|
|
||||||
mutex();
|
|
||||||
~mutex();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h2>Class <a name="mutex Members">mutex Members</a></h2>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>Constructor</h3>
|
|
||||||
<pre>
|
|
||||||
mutex();
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Postconditions:</b> <code>*this</code> is in the unlocked
|
|
||||||
state.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>Destructor</h3>
|
|
||||||
<pre>
|
|
||||||
~mutex();
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Requires:</b> <code>*this</code> is in the unlocked state.</p>
|
|
||||||
|
|
||||||
<p><b>Effects:</b> Destroys <code>*this</code>.</p>
|
|
||||||
|
|
||||||
<p><b>Dangers:</b> Destruction of a locked mutex is a serious
|
|
||||||
programming error resulting in undefined behavior such as a program
|
|
||||||
crash.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h2>Class <a name="try_mutex Synopsis">try_mutex Synopsis</a></h2>
|
|
||||||
<pre>
|
|
||||||
namespace boost
|
|
||||||
{
|
|
||||||
class try_mutex : private boost::noncopyable // Exposition only.
|
|
||||||
// Class try_mutex meets the <a href=
|
|
||||||
"overview.html#NonCopyable">NonCopyable</a> requirement.
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef <i>[implementation defined; see <a href=
|
|
||||||
"#Introduction">Introduction</a>]</i> scoped_lock;
|
|
||||||
typedef <i>[implementation defined; see <a href=
|
|
||||||
"#Introduction">Introduction</a>]</i> scoped_try_lock;
|
|
||||||
|
|
||||||
try_mutex();
|
|
||||||
~try_mutex();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h2>Class <a name="try_mutex Members">try_mutex Members</a></h2>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>Constructor</h3>
|
|
||||||
<pre>
|
|
||||||
try_mutex();
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Postconditions:</b> <code>*this</code> is in the unlocked
|
|
||||||
state.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>Destructor</h3>
|
|
||||||
<pre>
|
|
||||||
~try_mutex();
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Requires:</b> <code>*this</code> is in the unlocked state.</p>
|
|
||||||
|
|
||||||
<p><b>Effects:</b> Destroys <code>*this</code>.</p>
|
|
||||||
|
|
||||||
<p><b>Dangers:</b> Destruction of a locked mutex is a serious
|
|
||||||
programming error resulting in undefined behavior such as a program
|
|
||||||
crash.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h2>Class <a name="timed_mutex Synopsis">timed_mutex Synopsis</a></h2>
|
|
||||||
<pre>
|
|
||||||
namespace boost
|
|
||||||
{
|
|
||||||
class timed_mutex : private boost::noncopyable // Exposition only.
|
|
||||||
// Class timed_mutex meets the <a href=
|
|
||||||
"overview.html#NonCopyable">NonCopyable</a> requirement.
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef <i>[implementation defined; see <a href=
|
|
||||||
"#Introduction">Introduction</a>]</i> scoped_lock;
|
|
||||||
typedef <i>[implementation defined; see <a href=
|
|
||||||
"#Introduction">Introduction</a>]</i> scoped_try_lock;
|
|
||||||
typedef <i>[implementation defined; see <a href=
|
|
||||||
"#Introduction">Introduction</a>]</i> scoped_timed_lock;
|
|
||||||
|
|
||||||
timed_mutex();
|
|
||||||
~timed_mutex();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h2>Class <a name="timed_mutex Members">timed_mutex Members</a></h2>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>Constructor</h3>
|
|
||||||
<pre>
|
|
||||||
timed_mutex();
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Postconditions:</b> <code>*this</code> is in the unlocked
|
|
||||||
state.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>Destructor</h3>
|
|
||||||
<pre>
|
|
||||||
~timed_mutex();
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Requires:</b> <code>*this</code> is in the unlocked state.</p>
|
|
||||||
|
|
||||||
<p><b>Effects:</b> Destroys <code>*this</code>.</p>
|
|
||||||
|
|
||||||
<p><b>Dangers:</b> Destruction of a locked mutex is a serious
|
|
||||||
programming error resulting in undefined behavior such as a program
|
|
||||||
crash.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h2><a name="Example">Example</a> Usage</h2>
|
|
||||||
<pre>
|
|
||||||
#include <a href=
|
|
||||||
"../../../boost/thread/mutex.hpp"><boost/thread/mutex.hpp></a>
|
|
||||||
#include <a href=
|
|
||||||
"../../../boost/thread/thread.hpp"><boost/thread/thread.hpp></a>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
boost::mutex io_mutex; // The iostreams are not guaranteed to be <a href=
|
|
||||||
"definitions.html#Thread-safe">thread-safe</a>!
|
|
||||||
|
|
||||||
class counter
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
counter() : count(0) { }
|
|
||||||
|
|
||||||
int increment() {
|
|
||||||
boost::mutex::scoped_lock scoped_lock(mutex);
|
|
||||||
return ++count;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
boost::mutex mutex;
|
|
||||||
int count;
|
|
||||||
};
|
|
||||||
|
|
||||||
counter c;
|
|
||||||
|
|
||||||
void change_count(void*)
|
|
||||||
{
|
|
||||||
int i = c.increment();
|
|
||||||
boost::mutex::scoped_lock scoped_lock(io_mutex);
|
|
||||||
std::cout << "count == " << i << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int, char*[])
|
|
||||||
{
|
|
||||||
const int num_threads = 4;
|
|
||||||
boost::thread_group thrds;
|
|
||||||
for (int i=0; i < num_threads; ++i)
|
|
||||||
thrds.create_thread(&change_count, 0);
|
|
||||||
|
|
||||||
thrds.join_all();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>The output is:</p>
|
|
||||||
<pre>
|
|
||||||
count == 1
|
|
||||||
count == 2
|
|
||||||
count == 3
|
|
||||||
count == 4
|
|
||||||
</pre>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p>Revised
|
|
||||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->05 November, 2001<!--webbot bot="Timestamp" endspan i-checksum="39359" --></p>
|
|
||||||
|
|
||||||
<p><i>© Copyright <a href="mailto:williamkempf@hotmail.com">
|
|
||||||
William E. Kempf</a> 2001 all rights reserved.</i></p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
@@ -1,337 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content=
|
|
||||||
"text/html; charset=iso-8859-1">
|
|
||||||
<meta name="keywords" content="threads, BTL, thread library, C++">
|
|
||||||
|
|
||||||
<title>Boost.Threads, Mutex Concept</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body bgcolor="#ffffff" link="#0000ff" vlink="#800080">
|
|
||||||
<table summary="header" border="0" cellpadding="7" cellspacing="0"
|
|
||||||
width="100%">
|
|
||||||
<tr>
|
|
||||||
<td valign="top" width="300">
|
|
||||||
<h3><img height="86" alt="C++ Boost" src=
|
|
||||||
"../../../c++boost.gif" width="277"></h3>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td valign="top">
|
|
||||||
<h1 align="center">Boost.Threads</h1>
|
|
||||||
|
|
||||||
<h2 align="center">Mutex Concepts</h2>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p><a href="#Introduction">Introduction</a><br>
|
|
||||||
<a href="#LockingStrategies">Locking Strategies</a><br>
|
|
||||||
<a href="#Recursive">Recursive</a><br>
|
|
||||||
<a href="#CheckedStrategy">Checked</a><br>
|
|
||||||
<a href="#UncheckedStrategy">Unchecked</a><br>
|
|
||||||
<a href="#UnspecifiedStrategy">
|
|
||||||
Unspecified</a><br>
|
|
||||||
<a href="#SchedulingPolicies">Scheduling Policies</a><br>
|
|
||||||
<a href="#FIFO">FIFO</a><br>
|
|
||||||
<a href="#Priority Driven">Priority
|
|
||||||
Driven</a><br>
|
|
||||||
<a href="#UndefinedScheduling">
|
|
||||||
Undefined</a><br>
|
|
||||||
<a href="#UnspecifiedScheduling">
|
|
||||||
Unspecified</a><br>
|
|
||||||
<a href="#Requirements">Concept Requirements</a><br>
|
|
||||||
<a href="#Mutex">Mutex Concept</a><br>
|
|
||||||
<a href="#TryMutex">TryMutex Concept</a><br>
|
|
||||||
<a href="#TimedMutex">TimedMutex
|
|
||||||
Concept</a><br>
|
|
||||||
<a href="#Models">Models</a></p>
|
|
||||||
|
|
||||||
<h2><a name="Introduction">Introduction</a></h2>
|
|
||||||
|
|
||||||
<p>A mutex (short for mutual-exclusion) concept serializes access to a
|
|
||||||
resource shared between multiple threads. The <a href="#Mutex">
|
|
||||||
Mutex</a> concept, with <a href="#TryMutex">TryMutex</a> and <a href=
|
|
||||||
"#TimedMutex">TimedMutex</a> refinements, formalize the requirements. A
|
|
||||||
model that implements Mutex and its refinements has two states: <b>
|
|
||||||
locked</b> and <b>unlocked</b>. Before using a shared resource, a
|
|
||||||
thread locks a Boost.Threads mutex model object, insuring <a href=
|
|
||||||
"definitions.html#Thread-safe">thread-safe</a> access to the shared
|
|
||||||
resource. When use of the shared resource is complete, the thread
|
|
||||||
unlocks the mutex model object, allowing another thread to acquire the
|
|
||||||
lock and use the shared resource.</p>
|
|
||||||
|
|
||||||
<p>Traditional C thread APIs, like Pthreads or the Windows thread APIs,
|
|
||||||
expose functions to lock and unlock a mutex model. This is dangerous
|
|
||||||
since it's easy to forget to unlock a locked mutex. When the flow
|
|
||||||
of control is complex, with multiple return points, the likelihood of
|
|
||||||
forgetting to unlock a mutex model would become even greater. When
|
|
||||||
exceptions are thrown, it becomes nearly impossible to ensure that the
|
|
||||||
mutex is unlocked properly when using these traditional API's. The
|
|
||||||
result is <a href="definitions.html#Deadlock">deadlock</a>.</p>
|
|
||||||
|
|
||||||
<p>Many C++ threading libraries use a pattern known as <i>Scoped
|
|
||||||
Locking</i> <a href="bibliography.html#Schmidt 00">[Schmidt 00]</a> to
|
|
||||||
free the programmer from the need to explicitly lock and unlock
|
|
||||||
mutexes. With this pattern, a <a href="lock_concept.html">lock
|
|
||||||
concept</a> is employed where the lock model's constructor locks
|
|
||||||
the associated mutex model and the destructor automatically does the
|
|
||||||
unlocking. The <b>Boost.Threads</b> library takes this pattern to the
|
|
||||||
extreme in that lock concepts are the only way to lock and unlock a
|
|
||||||
mutex model: lock and unlock functions are not exposed by any <b>
|
|
||||||
Boost.Threads</b> mutex models. This helps to ensure safe usage
|
|
||||||
patterns, especially when code throws exceptions.</p>
|
|
||||||
|
|
||||||
<h2><a name="LockingStrategies">Locking Strategies</a></h2>
|
|
||||||
|
|
||||||
<p>Every mutex model follows one of several locking strategies. These
|
|
||||||
strategies define the semantics for the locking operation when the
|
|
||||||
calling thread already owns a lock on the mutex model.</p>
|
|
||||||
|
|
||||||
<h3><a name="Recursive">Recursive</a></h3>
|
|
||||||
|
|
||||||
<p>With a recursive locking strategy when a thread attempts to acquire
|
|
||||||
a lock on the mutex model for which it already owns a lock, the
|
|
||||||
operation is successful. Note the distinction between a thread, which
|
|
||||||
may have multiple locks outstanding on a recursive mutex, and a lock
|
|
||||||
object, which even for a recursive mutex cannot have its lock()
|
|
||||||
function called multiple times without first calling unlock().</p>
|
|
||||||
|
|
||||||
<p>Internally a lock count is maintained and the owning thread must
|
|
||||||
unlock the mutex model the same number of times that it's locked it
|
|
||||||
before the mutex model's state returns to unlocked. Since mutex
|
|
||||||
models in <b>Boost.Threads</b> expose locking functionality only
|
|
||||||
through lock concepts, a thread will always unlock a mutex model the
|
|
||||||
same number of times that it locked it. This helps to eliminate a whole
|
|
||||||
set of errors typically found in traditional C style thread APIs.</p>
|
|
||||||
|
|
||||||
<p>Classes <a href="recursive_mutex.html">recursive_mutex</a>, <a href=
|
|
||||||
"recursive_mutex.html">recursive_try_mutex</a> and <a href=
|
|
||||||
"recursive_mutex.html">recursive_timed_mutex</a> use this locking
|
|
||||||
strategy.</p>
|
|
||||||
|
|
||||||
<h3><a name="CheckedStrategy">Checked</a></h3>
|
|
||||||
|
|
||||||
<p>With a checked locking strategy when a thread attempts to acquire a
|
|
||||||
lock on the mutex model for which the thread already owns a lock, the
|
|
||||||
operation will fail with some sort of error indication. Further,
|
|
||||||
attempts by a thread to unlock a mutex that was not locked by the
|
|
||||||
thread will also return some sort of error indication. In <b>
|
|
||||||
Boost.Threads</b>, an exception of type <a href="lock_error.html">
|
|
||||||
lock_error</a> would be thrown in these cases.</p>
|
|
||||||
|
|
||||||
<p><b>Boost.Threads</b> does not currently provide any mutex models
|
|
||||||
that use this strategy.</p>
|
|
||||||
|
|
||||||
<h3><a name="UncheckedStrategy">Unchecked</a></h3>
|
|
||||||
|
|
||||||
<p>With an unchecked locking strategy when a thread attempts to acquire
|
|
||||||
a lock on the mutex model for which the thread already owns a lock the
|
|
||||||
operation will <a href="definitions.html#Deadlock">deadlock</a>. In
|
|
||||||
general this locking strategy is less safe than a checked or recursive
|
|
||||||
strategy, but it's also a faster strategy and so is employed by
|
|
||||||
many libraries.</p>
|
|
||||||
|
|
||||||
<p><b>Boost.Threads</b> does not currently provide any mutex models
|
|
||||||
that use this strategy.</p>
|
|
||||||
|
|
||||||
<h3><a name="UnspecifiedStrategy">Unspecified</a></h3>
|
|
||||||
|
|
||||||
<p>With an unspecified locking strategy, when a thread attempts to
|
|
||||||
acquire a lock on a mutex model for which the thread already owns a
|
|
||||||
lock the operation results in <b>undefined behavior</b>. When a mutex
|
|
||||||
model has an unspecified locking strategy the programmer must assume
|
|
||||||
that the mutex model instead uses an unchecked strategy.</p>
|
|
||||||
|
|
||||||
<p>In general a mutex model with an unspecified locking strategy is
|
|
||||||
unsafe, and it requires programmer discipline to use the mutex model
|
|
||||||
properly. However, this strategy allows an implementation to be as fast
|
|
||||||
as possible with no restrictions on its implementation. This is
|
|
||||||
especially true for portable implementations that wrap the native
|
|
||||||
threading support of a platform. For this reason, the classes <a href=
|
|
||||||
"mutex.html">mutex</a>, <a href="mutex.html">try_mutex</a> and <a href=
|
|
||||||
"mutex.html">timed_mutex</a> use this locking strategy despite the lack
|
|
||||||
of safety.</p>
|
|
||||||
|
|
||||||
<h2><a name="SchedulingPolicies">Scheduling Policies</a></h2>
|
|
||||||
|
|
||||||
<p>Every mutex model follows one of several scheduling policies. These
|
|
||||||
policies define the semantics when the mutex model is unlocked and
|
|
||||||
there is more than one thread waiting to acquire a lock. In other
|
|
||||||
words, the policy defines which waiting thread shall acquire the
|
|
||||||
lock.</p>
|
|
||||||
|
|
||||||
<h3><a name="FIFO">FIFO</a></h3>
|
|
||||||
|
|
||||||
<p>With a FIFO scheduling policy, threads waiting for the lock will
|
|
||||||
acquire it in a first come first serve order (or First In First Out).
|
|
||||||
This can help prevent a high priority thread from starving lower
|
|
||||||
priority threads that are also waiting on the mutex lock.</p>
|
|
||||||
|
|
||||||
<h3><a name="Priority Driven">Priority Driven</a></h3>
|
|
||||||
|
|
||||||
<p>With a Priority Driven scheduling policy, the thread with the
|
|
||||||
highest priority acquires the lock. Note that this means that
|
|
||||||
low-priority threads may never acquire the lock if the mutex model has
|
|
||||||
high contention and there is always at least one high-priority thread
|
|
||||||
waiting. This is known as thread starvation. When multiple threads of
|
|
||||||
the same priority are waiting on the mutex lock one of the other
|
|
||||||
scheduling priorities will determine which thread shall acquire the
|
|
||||||
lock.</p>
|
|
||||||
|
|
||||||
<h3><a name="UndefinedScheduling">Undefined</a></h3>
|
|
||||||
|
|
||||||
<p>Threads acquire the lock in no particular order. Users should assume
|
|
||||||
that low-priority threads may wait indefinitely, and that threads of
|
|
||||||
the same priority acquire the lock in essentially random order.</p>
|
|
||||||
|
|
||||||
<h3><a name="UnspecifiedScheduling">Unspecified</a></h3>
|
|
||||||
|
|
||||||
<p>The mutex model does not specify which scheduling policy is used.
|
|
||||||
The programmer must assume that an undefined scheduling policy is used.
|
|
||||||
In order to ensure portability, all <b>Boost.Threads</b> mutex models
|
|
||||||
use an unspecified scheduling policy.</p>
|
|
||||||
|
|
||||||
<h2>Concept <a name="Requirements">Requirements</a></h2>
|
|
||||||
|
|
||||||
<h3><a name="Mutex">Mutex</a> Concept</h3>
|
|
||||||
|
|
||||||
<p>A Mutex object has two states: locked and unlocked. Mutex object
|
|
||||||
state can only be determined by an object meeting the <a href=
|
|
||||||
"lock_concept.html#ScopedLock">ScopedLock</a> requirements and
|
|
||||||
constructed for the Mutex object.</p>
|
|
||||||
|
|
||||||
<p>A Mutex is <a href="../../utility/utility.htm#Class noncopyable">
|
|
||||||
noncopyable</a>.</p>
|
|
||||||
|
|
||||||
<p>For a Mutex type M and an object m of that type, the following
|
|
||||||
expressions must be well-formed and have the indicated effects.</p>
|
|
||||||
|
|
||||||
<table summary="Mutex expressions" border="1" cellpadding="5">
|
|
||||||
<tr>
|
|
||||||
<td><b>Expression</b></td>
|
|
||||||
|
|
||||||
<td><b>Effects</b></td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td><code>M m;</code></td>
|
|
||||||
|
|
||||||
<td>Constructs a mutex object m. Post-condition: m is
|
|
||||||
unlocked.</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td><code>(&m)->~M();</code></td>
|
|
||||||
|
|
||||||
<td>Precondition: m is unlocked. Destroys a mutex object
|
|
||||||
m.</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td><code>M::scoped_lock</code></td>
|
|
||||||
|
|
||||||
<td>A type meeting the <a href="lock_concept.html#ScopedLock">
|
|
||||||
ScopedLock</a> requirements.</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<h3><a name="TryMutex">TryMutex</a> Concept</h3>
|
|
||||||
|
|
||||||
<p>A TryMutex must meet the <a href="#Mutex">Mutex</a> requirements. In
|
|
||||||
addition, for a TryMutex type M and an object m of that type, the
|
|
||||||
following expressions must be well-formed and have the indicated
|
|
||||||
effects.</p>
|
|
||||||
|
|
||||||
<table summary="TryMutex expressions" border="1" cellpadding="5">
|
|
||||||
<tr>
|
|
||||||
<td><b>Expression</b></td>
|
|
||||||
|
|
||||||
<td><b>Effects</b></td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td><code>M::scoped_try_lock</code></td>
|
|
||||||
|
|
||||||
<td>A type meeting the <a href=
|
|
||||||
"lock_concept.html#ScopedTryLock">ScopedTryLock</a>
|
|
||||||
requirements.</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<h3><a name="TimedMutex">TimedMutex</a> Concept</h3>
|
|
||||||
|
|
||||||
<p>A TimedMutex must meet the <a href="#TryMutex">TryMutex</a>
|
|
||||||
requirements. In addition, for a TimedMutex type M and an object m of
|
|
||||||
that type, the following expressions must be well-formed and have the
|
|
||||||
indicated effects.</p>
|
|
||||||
|
|
||||||
<table summary="TimedMutex expressions" border="1" cellpadding="5">
|
|
||||||
<tr>
|
|
||||||
<td><b>Expression</b></td>
|
|
||||||
|
|
||||||
<td><b>Effects</b></td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td><code>M::scoped_timed_lock</code></td>
|
|
||||||
|
|
||||||
<td>A type meeting the <a href=
|
|
||||||
"lock_concept.html#ScopedTimedLock">ScopedTimedLock</a>
|
|
||||||
requirements.</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<h2><a name="Models">Models</a></h2>
|
|
||||||
|
|
||||||
<p><b>Boost.Threads</b> currently supplies six classes which model
|
|
||||||
mutex concepts.</p>
|
|
||||||
|
|
||||||
<table summary="Mutex concept classes" border="1" cellpadding="5">
|
|
||||||
<tr>
|
|
||||||
<td><b>Concept</b></td>
|
|
||||||
|
|
||||||
<td><b>Refines</b></td>
|
|
||||||
|
|
||||||
<td><b>Classes Modeling the Concept</b></td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td valign="top"><a href="#Mutex">Mutex</a></td>
|
|
||||||
|
|
||||||
<td valign="top"> </td>
|
|
||||||
|
|
||||||
<td><a href="mutex.html">mutex</a><br>
|
|
||||||
<a href="recursive_mutex.html">recursive_mutex</a></td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td valign="top"><a href="#TryMutex">TryMutex</a></td>
|
|
||||||
|
|
||||||
<td valign="top"><a href="#Mutex">Mutex</a></td>
|
|
||||||
|
|
||||||
<td><a href="mutex.html">try_mutex<br>
|
|
||||||
</a> <a href="recursive_mutex.html">recursive_try_mutex</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td valign="top"><a href="#TimedMutex">TimedMutex</a></td>
|
|
||||||
|
|
||||||
<td valign="top"><a href="#TryMutex">TryMutex</a></td>
|
|
||||||
|
|
||||||
<td><a href="mutex.html">timed_mutex<br>
|
|
||||||
</a> <a href="recursive_mutex.html">
|
|
||||||
recursive_timed_mutex</a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p>Revised
|
|
||||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->05 November, 2001<!--webbot bot="Timestamp" endspan i-checksum="39359" --></p>
|
|
||||||
|
|
||||||
<p><i>© Copyright <a href="mailto:williamkempf@hotmail.com">
|
|
||||||
William E. Kempf</a> 2001 all rights reserved.</i></p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
917
doc/mutex_concepts.qbk
Normal file
917
doc/mutex_concepts.qbk
Normal file
@@ -0,0 +1,917 @@
|
|||||||
|
[section:mutex_concepts Mutex Concepts]
|
||||||
|
|
||||||
|
A mutex object facilitates protection against data races and allows thread-safe synchronization of data between threads. A thread
|
||||||
|
obtains ownership of a mutex object by calling one of the lock functions and relinquishes ownership by calling the corresponding
|
||||||
|
unlock function. Mutexes may be either recursive or non-recursive, and may grant simultaneous ownership to one or many
|
||||||
|
threads. __boost_thread__ supplies recursive and non-recursive mutexes with exclusive ownership semantics, along with a shared
|
||||||
|
ownership (multiple-reader / single-writer) mutex.
|
||||||
|
|
||||||
|
__boost_thread__ supports four basic concepts for lockable objects: __lockable_concept_type__, __timed_lockable_concept_type__,
|
||||||
|
__shared_lockable_concept_type__ and __upgrade_lockable_concept_type__. Each mutex type implements one or more of these concepts, as
|
||||||
|
do the various lock types.
|
||||||
|
|
||||||
|
[section:lockable `Lockable` Concept]
|
||||||
|
|
||||||
|
The __lockable_concept__ models exclusive ownership. A type that implements the __lockable_concept__ shall provide the following
|
||||||
|
member functions:
|
||||||
|
|
||||||
|
* [lock_ref_link `void lock();`]
|
||||||
|
* [try_lock_ref_link `bool try_lock();`]
|
||||||
|
* [unlock_ref_link `void unlock();`]
|
||||||
|
|
||||||
|
Lock ownership acquired through a call to __lock_ref__ or __try_lock_ref__ must be released through a call to __unlock_ref__.
|
||||||
|
|
||||||
|
[section:lock `void lock()`]
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[Effects:] [The current thread blocks until ownership can be obtained for the current thread.]]
|
||||||
|
|
||||||
|
[[Postcondition:] [The current thread owns `*this`.]]
|
||||||
|
|
||||||
|
[[Throws:] [__thread_resource_error__ if an error occurs.]]
|
||||||
|
|
||||||
|
]
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section:try_lock `bool try_lock()`]
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[Effects:] [Attempt to obtain ownership for the current thread without blocking.]]
|
||||||
|
|
||||||
|
[[Returns:] [`true` if ownership was obtained for the current thread, `false` otherwise.]]
|
||||||
|
|
||||||
|
[[Postcondition:] [If the call returns `true`, the current thread owns the `*this`.]]
|
||||||
|
|
||||||
|
[[Throws:] [__thread_resource_error__ if an error occurs.]]
|
||||||
|
|
||||||
|
]
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section:unlock `void unlock()`]
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[Precondition:] [The current thread owns `*this`.]]
|
||||||
|
|
||||||
|
[[Effects:] [Releases ownership by the current thread.]]
|
||||||
|
|
||||||
|
[[Postcondition:] [The current thread no longer owns `*this`.]]
|
||||||
|
|
||||||
|
[[Throws:] [Nothing]]
|
||||||
|
]
|
||||||
|
[endsect]
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section:timed_lockable `TimedLockable` Concept]
|
||||||
|
|
||||||
|
The __timed_lockable_concept__ refines the __lockable_concept__ to add support for
|
||||||
|
timeouts when trying to acquire the lock.
|
||||||
|
|
||||||
|
A type that implements the __timed_lockable_concept__ shall meet the requirements
|
||||||
|
of the __lockable_concept__. In addition, the following member functions must be
|
||||||
|
provided:
|
||||||
|
|
||||||
|
* [timed_lock_ref_link `bool timed_lock(boost::system_time const& abs_time);`]
|
||||||
|
* [timed_lock_duration_ref_link `template<typename DurationType> bool timed_lock(DurationType const& rel_time);`]
|
||||||
|
|
||||||
|
Lock ownership acquired through a call to __timed_lock_ref__ must be released through a call to __unlock_ref__.
|
||||||
|
|
||||||
|
[section:timed_lock `bool timed_lock(boost::system_time const& abs_time)`]
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[Effects:] [Attempt to obtain ownership for the current thread. Blocks until ownership can be obtained, or the specified time is
|
||||||
|
reached. If the specified time has already passed, behaves as __try_lock_ref__.]]
|
||||||
|
|
||||||
|
[[Returns:] [`true` if ownership was obtained for the current thread, `false` otherwise.]]
|
||||||
|
|
||||||
|
[[Postcondition:] [If the call returns `true`, the current thread owns `*this`.]]
|
||||||
|
|
||||||
|
[[Throws:] [__thread_resource_error__ if an error occurs.]]
|
||||||
|
]
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section:timed_lock_duration `template<typename DurationType> bool
|
||||||
|
timed_lock(DurationType const& rel_time)`]
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[Effects:] [As-if [timed_lock_ref_link
|
||||||
|
`timed_lock(boost::get_system_time()+rel_time)`].]]
|
||||||
|
|
||||||
|
]
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section:shared_lockable `SharedLockable` Concept]
|
||||||
|
|
||||||
|
The __shared_lockable_concept__ is a refinement of the __timed_lockable_concept__ that
|
||||||
|
allows for ['shared ownership] as well as ['exclusive ownership]. This is the
|
||||||
|
standard multiple-reader / single-write model: at most one thread can have
|
||||||
|
exclusive ownership, and if any thread does have exclusive ownership, no other threads
|
||||||
|
can have shared or exclusive ownership. Alternatively, many threads may have
|
||||||
|
shared ownership.
|
||||||
|
|
||||||
|
For a type to implement the __shared_lockable_concept__, as well as meeting the
|
||||||
|
requirements of the __timed_lockable_concept__, it must also provide the following
|
||||||
|
member functions:
|
||||||
|
|
||||||
|
* [lock_shared_ref_link `void lock_shared();`]
|
||||||
|
* [try_lock_shared_ref_link `bool try_lock_shared();`]
|
||||||
|
* [unlock_shared_ref_link `bool unlock_shared();`]
|
||||||
|
* [timed_lock_shared_ref_link `bool timed_lock_shared(boost::system_time const& abs_time);`]
|
||||||
|
|
||||||
|
Lock ownership acquired through a call to __lock_shared_ref__, __try_lock_shared_ref__ or __timed_lock_shared_ref__ must be released
|
||||||
|
through a call to __unlock_shared_ref__.
|
||||||
|
|
||||||
|
[section:lock_shared `void lock_shared()`]
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[Effects:] [The current thread blocks until shared ownership can be obtained for the current thread.]]
|
||||||
|
|
||||||
|
[[Postcondition:] [The current thread has shared ownership of `*this`.]]
|
||||||
|
|
||||||
|
[[Throws:] [__thread_resource_error__ if an error occurs.]]
|
||||||
|
|
||||||
|
]
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section:try_lock_shared `bool try_lock_shared()`]
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[Effects:] [Attempt to obtain shared ownership for the current thread without blocking.]]
|
||||||
|
|
||||||
|
[[Returns:] [`true` if shared ownership was obtained for the current thread, `false` otherwise.]]
|
||||||
|
|
||||||
|
[[Postcondition:] [If the call returns `true`, the current thread has shared ownership of `*this`.]]
|
||||||
|
|
||||||
|
[[Throws:] [__thread_resource_error__ if an error occurs.]]
|
||||||
|
|
||||||
|
]
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section:timed_lock_shared `bool timed_lock_shared(boost::system_time const& abs_time)`]
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[Effects:] [Attempt to obtain shared ownership for the current thread. Blocks until shared ownership can be obtained, or the
|
||||||
|
specified time is reached. If the specified time has already passed, behaves as __try_lock_shared_ref__.]]
|
||||||
|
|
||||||
|
[[Returns:] [`true` if shared ownership was acquired for the current thread, `false` otherwise.]]
|
||||||
|
|
||||||
|
[[Postcondition:] [If the call returns `true`, the current thread has shared
|
||||||
|
ownership of `*this`.]]
|
||||||
|
|
||||||
|
[[Throws:] [__thread_resource_error__ if an error occurs.]]
|
||||||
|
|
||||||
|
]
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section:unlock_shared `void unlock_shared()`]
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[Precondition:] [The current thread has shared ownership of `*this`.]]
|
||||||
|
|
||||||
|
[[Effects:] [Releases shared ownership of `*this` by the current thread.]]
|
||||||
|
|
||||||
|
[[Postcondition:] [The current thread no longer has shared ownership of `*this`.]]
|
||||||
|
|
||||||
|
[[Throws:] [Nothing]]
|
||||||
|
|
||||||
|
]
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section:upgrade_lockable `UpgradeLockable` Concept]
|
||||||
|
|
||||||
|
The __upgrade_lockable_concept__ is a refinement of the __shared_lockable_concept__ that allows for ['upgradable ownership] as well
|
||||||
|
as ['shared ownership] and ['exclusive ownership]. This is an extension to the multiple-reader / single-write model provided by the
|
||||||
|
__shared_lockable_concept__: a single thread may have ['upgradable ownership] at the same time as others have ['shared
|
||||||
|
ownership]. The thread with ['upgradable ownership] may at any time attempt to upgrade that ownership to ['exclusive ownership]. If
|
||||||
|
no other threads have shared ownership, the upgrade is completed immediately, and the thread now has ['exclusive ownership], which
|
||||||
|
must be relinquished by a call to __unlock_ref__, just as if it had been acquired by a call to __lock_ref__.
|
||||||
|
|
||||||
|
If a thread with ['upgradable ownership] tries to upgrade whilst other threads have ['shared ownership], the attempt will fail and
|
||||||
|
the thread will block until ['exclusive ownership] can be acquired.
|
||||||
|
|
||||||
|
Ownership can also be ['downgraded] as well as ['upgraded]: exclusive ownership of an implementation of the
|
||||||
|
__upgrade_lockable_concept__ can be downgraded to upgradable ownership or shared ownership, and upgradable ownership can be
|
||||||
|
downgraded to plain shared ownership.
|
||||||
|
|
||||||
|
For a type to implement the __upgrade_lockable_concept__, as well as meeting the
|
||||||
|
requirements of the __shared_lockable_concept__, it must also provide the following
|
||||||
|
member functions:
|
||||||
|
|
||||||
|
* [lock_upgrade_ref_link `void lock_upgrade();`]
|
||||||
|
* [unlock_upgrade_ref_link `bool unlock_upgrade();`]
|
||||||
|
* [unlock_upgrade_and_lock_ref_link `void unlock_upgrade_and_lock();`]
|
||||||
|
* [unlock_and_lock_upgrade_ref_link `void unlock_and_lock_upgrade();`]
|
||||||
|
* [unlock_upgrade_and_lock_shared_ref_link `void unlock_upgrade_and_lock_shared();`]
|
||||||
|
|
||||||
|
Lock ownership acquired through a call to __lock_upgrade_ref__ must be released through a call to __unlock_upgrade_ref__. If the
|
||||||
|
ownership type is changed through a call to one of the `unlock_xxx_and_lock_yyy()` functions, ownership must be released through a
|
||||||
|
call to the unlock function corresponding to the new level of ownership.
|
||||||
|
|
||||||
|
|
||||||
|
[section:lock_upgrade `void lock_upgrade()`]
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[Effects:] [The current thread blocks until upgrade ownership can be obtained for the current thread.]]
|
||||||
|
|
||||||
|
[[Postcondition:] [The current thread has upgrade ownership of `*this`.]]
|
||||||
|
|
||||||
|
[[Throws:] [__thread_resource_error__ if an error occurs.]]
|
||||||
|
|
||||||
|
]
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section:unlock_upgrade `void unlock_upgrade()`]
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[Precondition:] [The current thread has upgrade ownership of `*this`.]]
|
||||||
|
|
||||||
|
[[Effects:] [Releases upgrade ownership of `*this` by the current thread.]]
|
||||||
|
|
||||||
|
[[Postcondition:] [The current thread no longer has upgrade ownership of `*this`.]]
|
||||||
|
|
||||||
|
[[Throws:] [Nothing]]
|
||||||
|
|
||||||
|
]
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section:unlock_upgrade_and_lock `void unlock_upgrade_and_lock()`]
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[Precondition:] [The current thread has upgrade ownership of `*this`.]]
|
||||||
|
|
||||||
|
[[Effects:] [Atomically releases upgrade ownership of `*this` by the current thread and acquires exclusive ownership of `*this`. If
|
||||||
|
any other threads have shared ownership, blocks until exclusive ownership can be acquired.]]
|
||||||
|
|
||||||
|
[[Postcondition:] [The current thread has exclusive ownership of `*this`.]]
|
||||||
|
|
||||||
|
[[Throws:] [Nothing]]
|
||||||
|
|
||||||
|
]
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section:unlock_upgrade_and_lock_shared `void unlock_upgrade_and_lock_shared()`]
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[Precondition:] [The current thread has upgrade ownership of `*this`.]]
|
||||||
|
|
||||||
|
[[Effects:] [Atomically releases upgrade ownership of `*this` by the current thread and acquires shared ownership of `*this` without
|
||||||
|
blocking.]]
|
||||||
|
|
||||||
|
[[Postcondition:] [The current thread has shared ownership of `*this`.]]
|
||||||
|
|
||||||
|
[[Throws:] [Nothing]]
|
||||||
|
|
||||||
|
]
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section:unlock_and_lock_upgrade `void unlock_and_lock_upgrade()`]
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[Precondition:] [The current thread has exclusive ownership of `*this`.]]
|
||||||
|
|
||||||
|
[[Effects:] [Atomically releases exclusive ownership of `*this` by the current thread and acquires upgrade ownership of `*this`
|
||||||
|
without blocking.]]
|
||||||
|
|
||||||
|
[[Postcondition:] [The current thread has upgrade ownership of `*this`.]]
|
||||||
|
|
||||||
|
[[Throws:] [Nothing]]
|
||||||
|
|
||||||
|
]
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section:locks Lock Types]
|
||||||
|
|
||||||
|
[section:lock_guard Class template `lock_guard`]
|
||||||
|
|
||||||
|
template<typename Lockable>
|
||||||
|
class lock_guard
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit lock_guard(Lockable& m_);
|
||||||
|
lock_guard(Lockable& m_,boost::adopt_lock_t);
|
||||||
|
|
||||||
|
~lock_guard();
|
||||||
|
};
|
||||||
|
|
||||||
|
__lock_guard__ is very simple: on construction it
|
||||||
|
acquires ownership of the implementation of the __lockable_concept__ supplied as
|
||||||
|
the constructor parameter. On destruction, the ownership is released. This
|
||||||
|
provides simple RAII-style locking of a __lockable_concept_type__ object, to facilitate exception-safe
|
||||||
|
locking and unlocking. In addition, the [link
|
||||||
|
thread.synchronization.locks.lock_guard.constructor_adopt `lock_guard(Lockable &
|
||||||
|
m,boost::adopt_lock_t)` constructor] allows the __lock_guard__ object to
|
||||||
|
take ownership of a lock already held by the current thread.
|
||||||
|
|
||||||
|
[section:constructor `lock_guard(Lockable & m)`]
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[Effects:] [Stores a reference to `m`. Invokes [lock_ref_link `m.lock()`].]]
|
||||||
|
|
||||||
|
[[Throws:] [Any exception thrown by the call to [lock_ref_link `m.lock()`].]]
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section:constructor_adopt `lock_guard(Lockable & m,boost::adopt_lock_t)`]
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[Precondition:] [The current thread owns a lock on `m` equivalent to one
|
||||||
|
obtained by a call to [lock_ref_link `m.lock()`].]]
|
||||||
|
|
||||||
|
[[Effects:] [Stores a reference to `m`. Takes ownership of the lock state of
|
||||||
|
`m`.]]
|
||||||
|
|
||||||
|
[[Throws:] [Nothing.]]
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section:destructor `~lock_guard()`]
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[Effects:] [Invokes [unlock_ref_link `m.unlock()`] on the __lockable_concept_type__
|
||||||
|
object passed to the constructor.]]
|
||||||
|
|
||||||
|
[[Throws:] [Nothing.]]
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section:unique_lock Class template `unique_lock`]
|
||||||
|
|
||||||
|
template<typename Lockable>
|
||||||
|
class unique_lock
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
unique_lock();
|
||||||
|
explicit unique_lock(Lockable& m_);
|
||||||
|
unique_lock(Lockable& m_,adopt_lock_t);
|
||||||
|
unique_lock(Lockable& m_,defer_lock_t);
|
||||||
|
unique_lock(Lockable& m_,try_to_lock_t);
|
||||||
|
unique_lock(Lockable& m_,system_time const& target_time);
|
||||||
|
|
||||||
|
~unique_lock();
|
||||||
|
|
||||||
|
unique_lock(detail::thread_move_t<unique_lock<Lockable> > other);
|
||||||
|
unique_lock(detail::thread_move_t<upgrade_lock<Lockable> > other);
|
||||||
|
|
||||||
|
operator detail::thread_move_t<unique_lock<Lockable> >();
|
||||||
|
detail::thread_move_t<unique_lock<Lockable> > move();
|
||||||
|
unique_lock& operator=(detail::thread_move_t<unique_lock<Lockable> > other);
|
||||||
|
unique_lock& operator=(detail::thread_move_t<upgrade_lock<Lockable> > other);
|
||||||
|
|
||||||
|
void swap(unique_lock& other);
|
||||||
|
void swap(detail::thread_move_t<unique_lock<Lockable> > other);
|
||||||
|
|
||||||
|
void lock();
|
||||||
|
bool try_lock();
|
||||||
|
|
||||||
|
template<typename TimeDuration>
|
||||||
|
bool timed_lock(TimeDuration const& relative_time);
|
||||||
|
bool timed_lock(::boost::system_time const& absolute_time);
|
||||||
|
|
||||||
|
void unlock();
|
||||||
|
|
||||||
|
bool owns_lock() const;
|
||||||
|
operator ``['unspecified-bool-type]``() const;
|
||||||
|
bool operator!() const;
|
||||||
|
|
||||||
|
Lockable* mutex() const;
|
||||||
|
Lockable* release();
|
||||||
|
};
|
||||||
|
|
||||||
|
__unique_lock__ is more complex than __lock_guard__: not only does it provide for RAII-style locking, it also allows for deferring
|
||||||
|
acquiring the lock until the __lock_ref__ member function is called explicitly, or trying to acquire the lock in a non-blocking
|
||||||
|
fashion, or with a timeout. Consequently, __unlock_ref__ is only called in the destructor if the lock object has locked the
|
||||||
|
__lockable_concept_type__ object, or otherwise adopted a lock on the __lockable_concept_type__ object.
|
||||||
|
|
||||||
|
Specializations of __unique_lock__ model the __timed_lockable_concept__ if the supplied __lockable_concept_type__ type itself models
|
||||||
|
__timed_lockable_concept__ (e.g. `boost::unique_lock<boost::timed_mutex>`), or the __lockable_concept__ otherwise
|
||||||
|
(e.g. `boost::unique_lock<boost::mutex>`).
|
||||||
|
|
||||||
|
An instance of __unique_lock__ is said to ['own] the lock state of a __lockable_concept_type__ `m` if __mutex_func_ref__ returns a
|
||||||
|
pointer to `m` and __owns_lock_ref__ returns `true`. If an object that ['owns] the lock state of a __lockable_concept_type__ object
|
||||||
|
is destroyed, then the destructor will invoke [unlock_ref_link `mutex()->unlock()`].
|
||||||
|
|
||||||
|
The member functions of __unique_lock__ are not thread-safe. In particular, __unique_lock__ is intended to model the ownership of a
|
||||||
|
__lockable_concept_type__ object by a particular thread, and the member functions that release ownership of the lock state
|
||||||
|
(including the destructor) must be called by the same thread that acquired ownership of the lock state.
|
||||||
|
|
||||||
|
[section:defaultconstructor `unique_lock()`]
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[Effects:] [Creates a lock object with no associated mutex.]]
|
||||||
|
|
||||||
|
[[Postcondition:] [__owns_lock_ref__ returns `false`. __mutex_func_ref__ returns `NULL`.]]
|
||||||
|
|
||||||
|
[[Throws:] [Nothing.]]
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section:constructor `unique_lock(Lockable & m)`]
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[Effects:] [Stores a reference to `m`. Invokes [lock_ref_link `m.lock()`].]]
|
||||||
|
|
||||||
|
[[Postcondition:] [__owns_lock_ref__ returns `true`. __mutex_func_ref__ returns `&m`.]]
|
||||||
|
|
||||||
|
[[Throws:] [Any exception thrown by the call to [lock_ref_link `m.lock()`].]]
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section:constructor_adopt `unique_lock(Lockable & m,boost::adopt_lock_t)`]
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[Precondition:] [The current thread owns an exclusive lock on `m`.]]
|
||||||
|
|
||||||
|
[[Effects:] [Stores a reference to `m`. Takes ownership of the lock state of `m`.]]
|
||||||
|
|
||||||
|
[[Postcondition:] [__owns_lock_ref__ returns `true`. __mutex_func_ref__ returns `&m`.]]
|
||||||
|
|
||||||
|
[[Throws:] [Nothing.]]
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section:constructor_defer `unique_lock(Lockable & m,boost::defer_lock_t)`]
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[Effects:] [Stores a reference to `m`.]]
|
||||||
|
|
||||||
|
[[Postcondition:] [__owns_lock_ref__ returns `false`. __mutex_func_ref__ returns `&m`.]]
|
||||||
|
|
||||||
|
[[Throws:] [Nothing.]]
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section:constructor_try `unique_lock(Lockable & m,boost::try_to_lock_t)`]
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[Effects:] [Stores a reference to `m`. Invokes [try_lock_ref_link
|
||||||
|
`m.try_lock()`], and takes ownership of the lock state if the call returns
|
||||||
|
`true`.]]
|
||||||
|
|
||||||
|
[[Postcondition:] [__mutex_func_ref__ returns `&m`. If the call to __try_lock_ref__
|
||||||
|
returned `true`, then __owns_lock_ref__ returns `true`, otherwise __owns_lock_ref__
|
||||||
|
returns `false`.]]
|
||||||
|
|
||||||
|
[[Throws:] [Nothing.]]
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section:constructor_abs_time `unique_lock(Lockable & m,boost::system_time const& abs_time)`]
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[Effects:] [Stores a reference to `m`. Invokes [timed_lock_ref_link
|
||||||
|
`m.timed_lock(abs_time)`], and takes ownership of the lock state if the call
|
||||||
|
returns `true`.]]
|
||||||
|
|
||||||
|
[[Postcondition:] [__mutex_func_ref__ returns `&m`. If the call to __timed_lock_ref__
|
||||||
|
returned `true`, then __owns_lock_ref__ returns `true`, otherwise __owns_lock_ref__
|
||||||
|
returns `false`.]]
|
||||||
|
|
||||||
|
[[Throws:] [Any exceptions thrown by the call to [timed_lock_ref_link `m.timed_lock(abs_time)`].]]
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section:destructor `~unique_lock()`]
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[Effects:] [Invokes __mutex_func_ref__`->`[unlock_ref_link `unlock()`] if
|
||||||
|
__owns_lock_ref__ returns `true`.]]
|
||||||
|
|
||||||
|
[[Throws:] [Nothing.]]
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section:owns_lock `bool owns_lock() const`]
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[Returns:] [`true` if the `*this` owns the lock on the __lockable_concept_type__
|
||||||
|
object associated with `*this`.]]
|
||||||
|
|
||||||
|
[[Throws:] [Nothing.]]
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section:mutex `Lockable* mutex() const`]
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[Returns:] [A pointer to the __lockable_concept_type__ object associated with
|
||||||
|
`*this`, or `NULL` if there is no such object.]]
|
||||||
|
|
||||||
|
[[Throws:] [Nothing.]]
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section:bool_conversion `operator unspecified-bool-type() const`]
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[Returns:] [If __owns_lock_ref__ would return `true`, a value that evaluates to
|
||||||
|
`true` in boolean contexts, otherwise a value that evaluates to `false` in
|
||||||
|
boolean contexts.]]
|
||||||
|
|
||||||
|
[[Throws:] [Nothing.]]
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section:operator_not `bool operator!() const`]
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[Returns:] [`!` __owns_lock_ref__.]]
|
||||||
|
|
||||||
|
[[Throws:] [Nothing.]]
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section:release `Lockable* release()`]
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[Effects:] [The association between `*this` and the __lockable_concept_type__ object is removed, without affecting the lock state
|
||||||
|
of the __lockable_concept_type__ object. If __owns_lock_ref__ would have returned `true`, it is the responsibility of the calling
|
||||||
|
code to ensure that the __lockable_concept_type__ is correctly unlocked.]]
|
||||||
|
|
||||||
|
[[Returns:] [A pointer to the __lockable_concept_type__ object associated with `*this` at the point of the call, or `NULL` if there
|
||||||
|
is no such object.]]
|
||||||
|
|
||||||
|
[[Throws:] [Nothing.]]
|
||||||
|
|
||||||
|
[[Postcondition:] [`*this` is no longer associated with any __lockable_concept_type__ object. __mutex_func_ref__ returns `NULL` and
|
||||||
|
__owns_lock_ref__ returns `false`.]]
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section:shared_lock Class template `shared_lock`]
|
||||||
|
|
||||||
|
template<typename Lockable>
|
||||||
|
class shared_lock
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
shared_lock();
|
||||||
|
explicit shared_lock(Lockable& m_);
|
||||||
|
shared_lock(Lockable& m_,adopt_lock_t);
|
||||||
|
shared_lock(Lockable& m_,defer_lock_t);
|
||||||
|
shared_lock(Lockable& m_,try_to_lock_t);
|
||||||
|
shared_lock(Lockable& m_,system_time const& target_time);
|
||||||
|
shared_lock(detail::thread_move_t<shared_lock<Lockable> > other);
|
||||||
|
shared_lock(detail::thread_move_t<unique_lock<Lockable> > other);
|
||||||
|
shared_lock(detail::thread_move_t<upgrade_lock<Lockable> > other);
|
||||||
|
|
||||||
|
~shared_lock();
|
||||||
|
|
||||||
|
operator detail::thread_move_t<shared_lock<Lockable> >();
|
||||||
|
detail::thread_move_t<shared_lock<Lockable> > move();
|
||||||
|
|
||||||
|
shared_lock& operator=(detail::thread_move_t<shared_lock<Lockable> > other);
|
||||||
|
shared_lock& operator=(detail::thread_move_t<unique_lock<Lockable> > other);
|
||||||
|
shared_lock& operator=(detail::thread_move_t<upgrade_lock<Lockable> > other);
|
||||||
|
void swap(shared_lock& other);
|
||||||
|
|
||||||
|
void lock();
|
||||||
|
bool try_lock();
|
||||||
|
bool timed_lock(boost::system_time const& target_time);
|
||||||
|
void unlock();
|
||||||
|
|
||||||
|
operator ``['unspecified-bool-type]``() const;
|
||||||
|
bool operator!() const;
|
||||||
|
bool owns_lock() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
Like __unique_lock__, __shared_lock__ models the __lockable_concept__, but rather than acquiring unique ownership of the supplied
|
||||||
|
__lockable_concept_type__ object, locking an instance of __shared_lock__ acquires shared ownership.
|
||||||
|
|
||||||
|
Like __unique_lock__, not only does it provide for RAII-style locking, it also allows for deferring acquiring the lock until the
|
||||||
|
__lock_ref__ member function is called explicitly, or trying to acquire the lock in a non-blocking fashion, or with a
|
||||||
|
timeout. Consequently, __unlock_ref__ is only called in the destructor if the lock object has locked the __lockable_concept_type__
|
||||||
|
object, or otherwise adopted a lock on the __lockable_concept_type__ object.
|
||||||
|
|
||||||
|
An instance of __shared_lock__ is said to ['own] the lock state of a __lockable_concept_type__ `m` if __mutex_func_ref__ returns a
|
||||||
|
pointer to `m` and __owns_lock_ref__ returns `true`. If an object that ['owns] the lock state of a __lockable_concept_type__ object
|
||||||
|
is destroyed, then the destructor will invoke [unlock_shared_ref_link `mutex()->unlock_shared()`].
|
||||||
|
|
||||||
|
The member functions of __shared_lock__ are not thread-safe. In particular, __shared_lock__ is intended to model the shared
|
||||||
|
ownership of a __lockable_concept_type__ object by a particular thread, and the member functions that release ownership of the lock
|
||||||
|
state (including the destructor) must be called by the same thread that acquired ownership of the lock state.
|
||||||
|
|
||||||
|
[section:defaultconstructor `shared_lock()`]
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[Effects:] [Creates a lock object with no associated mutex.]]
|
||||||
|
|
||||||
|
[[Postcondition:] [__owns_lock_ref__ returns `false`. __mutex_func_ref__ returns `NULL`.]]
|
||||||
|
|
||||||
|
[[Throws:] [Nothing.]]
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section:constructor `shared_lock(Lockable & m)`]
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[Effects:] [Stores a reference to `m`. Invokes [lock_shared_ref_link `m.lock_shared()`].]]
|
||||||
|
|
||||||
|
[[Postcondition:] [__owns_lock_shared_ref__ returns `true`. __mutex_func_ref__ returns `&m`.]]
|
||||||
|
|
||||||
|
[[Throws:] [Any exception thrown by the call to [lock_shared_ref_link `m.lock_shared()`].]]
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section:constructor_adopt `shared_lock(Lockable & m,boost::adopt_lock_t)`]
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[Precondition:] [The current thread owns an exclusive lock on `m`.]]
|
||||||
|
|
||||||
|
[[Effects:] [Stores a reference to `m`. Takes ownership of the lock state of `m`.]]
|
||||||
|
|
||||||
|
[[Postcondition:] [__owns_lock_shared_ref__ returns `true`. __mutex_func_ref__ returns `&m`.]]
|
||||||
|
|
||||||
|
[[Throws:] [Nothing.]]
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section:constructor_defer `shared_lock(Lockable & m,boost::defer_lock_t)`]
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[Effects:] [Stores a reference to `m`.]]
|
||||||
|
|
||||||
|
[[Postcondition:] [__owns_lock_shared_ref__ returns `false`. __mutex_func_ref__ returns `&m`.]]
|
||||||
|
|
||||||
|
[[Throws:] [Nothing.]]
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section:constructor_try `shared_lock(Lockable & m,boost::try_to_lock_t)`]
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[Effects:] [Stores a reference to `m`. Invokes [try_lock_shared_ref_link
|
||||||
|
`m.try_lock_shared()`], and takes ownership of the lock state if the call returns
|
||||||
|
`true`.]]
|
||||||
|
|
||||||
|
[[Postcondition:] [__mutex_func_ref__ returns `&m`. If the call to __try_lock_shared_ref__
|
||||||
|
returned `true`, then __owns_lock_shared_ref__ returns `true`, otherwise __owns_lock_shared_ref__
|
||||||
|
returns `false`.]]
|
||||||
|
|
||||||
|
[[Throws:] [Nothing.]]
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section:constructor_abs_time `shared_lock(Lockable & m,boost::system_time const& abs_time)`]
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[Effects:] [Stores a reference to `m`. Invokes [timed_lock_shared_ref_link
|
||||||
|
`m.timed_lock(abs_time)`], and takes ownership of the lock state if the call
|
||||||
|
returns `true`.]]
|
||||||
|
|
||||||
|
[[Postcondition:] [__mutex_func_ref__ returns `&m`. If the call to __timed_lock_shared_ref__
|
||||||
|
returned `true`, then __owns_lock_shared_ref__ returns `true`, otherwise __owns_lock_shared_ref__
|
||||||
|
returns `false`.]]
|
||||||
|
|
||||||
|
[[Throws:] [Any exceptions thrown by the call to [timed_lock_shared_ref_link `m.timed_lock(abs_time)`].]]
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section:destructor `~shared_lock()`]
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[Effects:] [Invokes __mutex_func_ref__`->`[unlock_shared_ref_link `unlock_shared()`] if
|
||||||
|
__owns_lock_shared_ref__ returns `true`.]]
|
||||||
|
|
||||||
|
[[Throws:] [Nothing.]]
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section:owns_lock `bool owns_lock() const`]
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[Returns:] [`true` if the `*this` owns the lock on the __lockable_concept_type__
|
||||||
|
object associated with `*this`.]]
|
||||||
|
|
||||||
|
[[Throws:] [Nothing.]]
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section:mutex `Lockable* mutex() const`]
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[Returns:] [A pointer to the __lockable_concept_type__ object associated with
|
||||||
|
`*this`, or `NULL` if there is no such object.]]
|
||||||
|
|
||||||
|
[[Throws:] [Nothing.]]
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section:bool_conversion `operator unspecified-bool-type() const`]
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[Returns:] [If __owns_lock_shared_ref__ would return `true`, a value that evaluates to
|
||||||
|
`true` in boolean contexts, otherwise a value that evaluates to `false` in
|
||||||
|
boolean contexts.]]
|
||||||
|
|
||||||
|
[[Throws:] [Nothing.]]
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section:operator_not `bool operator!() const`]
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[Returns:] [`!` __owns_lock_shared_ref__.]]
|
||||||
|
|
||||||
|
[[Throws:] [Nothing.]]
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section:release `Lockable* release()`]
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[Effects:] [The association between `*this` and the __lockable_concept_type__ object is removed, without affecting the lock state
|
||||||
|
of the __lockable_concept_type__ object. If __owns_lock_shared_ref__ would have returned `true`, it is the responsibility of the calling
|
||||||
|
code to ensure that the __lockable_concept_type__ is correctly unlocked.]]
|
||||||
|
|
||||||
|
[[Returns:] [A pointer to the __lockable_concept_type__ object associated with `*this` at the point of the call, or `NULL` if there
|
||||||
|
is no such object.]]
|
||||||
|
|
||||||
|
[[Throws:] [Nothing.]]
|
||||||
|
|
||||||
|
[[Postcondition:] [`*this` is no longer associated with any __lockable_concept_type__ object. __mutex_func_ref__ returns `NULL` and
|
||||||
|
__owns_lock_shared_ref__ returns `false`.]]
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section:upgrade_lock Class template `upgrade_lock`]
|
||||||
|
|
||||||
|
template<typename Lockable>
|
||||||
|
class upgrade_lock
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit upgrade_lock(Lockable& m_);
|
||||||
|
|
||||||
|
upgrade_lock(detail::thread_move_t<upgrade_lock<Lockable> > other);
|
||||||
|
upgrade_lock(detail::thread_move_t<unique_lock<Lockable> > other);
|
||||||
|
|
||||||
|
~upgrade_lock();
|
||||||
|
|
||||||
|
operator detail::thread_move_t<upgrade_lock<Lockable> >();
|
||||||
|
detail::thread_move_t<upgrade_lock<Lockable> > move();
|
||||||
|
|
||||||
|
upgrade_lock& operator=(detail::thread_move_t<upgrade_lock<Lockable> > other);
|
||||||
|
upgrade_lock& operator=(detail::thread_move_t<unique_lock<Lockable> > other);
|
||||||
|
|
||||||
|
void swap(upgrade_lock& other);
|
||||||
|
|
||||||
|
void lock();
|
||||||
|
void unlock();
|
||||||
|
|
||||||
|
operator ``['unspecified-bool-type]``() const;
|
||||||
|
bool operator!() const;
|
||||||
|
bool owns_lock() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
Like __unique_lock__, __upgrade_lock__ models the __lockable_concept__, but rather than acquiring unique ownership of the supplied
|
||||||
|
__lockable_concept_type__ object, locking an instance of __upgrade_lock__ acquires upgrade ownership.
|
||||||
|
|
||||||
|
Like __unique_lock__, not only does it provide for RAII-style locking, it also allows for deferring acquiring the lock until the
|
||||||
|
__lock_ref__ member function is called explicitly, or trying to acquire the lock in a non-blocking fashion, or with a
|
||||||
|
timeout. Consequently, __unlock_ref__ is only called in the destructor if the lock object has locked the __lockable_concept_type__
|
||||||
|
object, or otherwise adopted a lock on the __lockable_concept_type__ object.
|
||||||
|
|
||||||
|
An instance of __upgrade_lock__ is said to ['own] the lock state of a __lockable_concept_type__ `m` if __mutex_func_ref__ returns a
|
||||||
|
pointer to `m` and __owns_lock_ref__ returns `true`. If an object that ['owns] the lock state of a __lockable_concept_type__ object
|
||||||
|
is destroyed, then the destructor will invoke [unlock_upgrade_ref_link `mutex()->unlock_upgrade()`].
|
||||||
|
|
||||||
|
The member functions of __upgrade_lock__ are not thread-safe. In particular, __upgrade_lock__ is intended to model the upgrade
|
||||||
|
ownership of a __lockable_concept_type__ object by a particular thread, and the member functions that release ownership of the lock
|
||||||
|
state (including the destructor) must be called by the same thread that acquired ownership of the lock state.
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section:upgrade_to_unique_lock Class template `upgrade_to_unique_lock`]
|
||||||
|
|
||||||
|
template <class Lockable>
|
||||||
|
class upgrade_to_unique_lock
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit upgrade_to_unique_lock(upgrade_lock<Lockable>& m_);
|
||||||
|
|
||||||
|
~upgrade_to_unique_lock();
|
||||||
|
|
||||||
|
upgrade_to_unique_lock(detail::thread_move_t<upgrade_to_unique_lock<Lockable> > other);
|
||||||
|
upgrade_to_unique_lock& operator=(detail::thread_move_t<upgrade_to_unique_lock<Lockable> > other);
|
||||||
|
void swap(upgrade_to_unique_lock& other);
|
||||||
|
|
||||||
|
operator ``['unspecified-bool-type]``() const;
|
||||||
|
bool operator!() const;
|
||||||
|
bool owns_lock() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
__upgrade_to_unique_lock__ allows for a temporary upgrade of an __upgrade_lock__ to exclusive ownership. When constructed with a
|
||||||
|
reference to an instance of __upgrade_lock__, if that instance has upgrade ownership on some __lockable_concept_type__ object, that
|
||||||
|
ownership is upgraded to exclusive ownership. When the __upgrade_to_unique_lock__ instance is destroyed, the ownership of the
|
||||||
|
__lockable_concept_type__ is downgraded back to ['upgrade ownership].
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
205
doc/mutexes.qbk
Normal file
205
doc/mutexes.qbk
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
[section:mutex_types Mutex Types]
|
||||||
|
|
||||||
|
[section:mutex Class `mutex`]
|
||||||
|
|
||||||
|
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 scoped_lock 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`]
|
||||||
|
|
||||||
|
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`]
|
||||||
|
|
||||||
|
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 scoped_timed_lock 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`]
|
||||||
|
|
||||||
|
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 scoped_lock 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`]
|
||||||
|
|
||||||
|
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`]
|
||||||
|
|
||||||
|
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 scoped_lock 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]
|
||||||
45
doc/once.qbk
Normal file
45
doc/once.qbk
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
[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`]
|
||||||
|
|
||||||
|
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`]
|
||||||
|
|
||||||
|
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(args)`, and the invocation of
|
||||||
|
`call_once` is effective if and only if `func(args)` 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]
|
||||||
@@ -1,224 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content=
|
|
||||||
"text/html; charset=windows-1252">
|
|
||||||
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
|
|
||||||
<meta name="ProgId" content="FrontPage.Editor.Document">
|
|
||||||
|
|
||||||
<title>Boost.Threads Overview</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<table summary="header" border="0" cellpadding="7" cellspacing="0"
|
|
||||||
width="100%">
|
|
||||||
<tr>
|
|
||||||
<td valign="top" width="300">
|
|
||||||
<h3><img height="86" alt="C++ Boost" src=
|
|
||||||
"../../../c++boost.gif" width="277"></h3>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td valign="top">
|
|
||||||
<h1 align="center">Boost.Threads</h1>
|
|
||||||
|
|
||||||
<h2 align="center">Overview</h2>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<p><a href="#Introduction">Introduction</a><br>
|
|
||||||
<a href="#Dangers">Dangers</a><br>
|
|
||||||
<a href="#Library">C++ Standard Library usage</a><br>
|
|
||||||
<a href="#Common">Common requirements</a></p>
|
|
||||||
|
|
||||||
<h2><a name="Introduction">Introduction</a></h2>
|
|
||||||
|
|
||||||
<p>Boost.Threads allows C++ programs to execute as multiple,
|
|
||||||
asynchronous, independent, threads-of-execution. Each thread has its
|
|
||||||
own machine state including program instruction counter and registers.
|
|
||||||
Programs which execute as multiple threads are called multi-threaded
|
|
||||||
programs to distinguish them from traditional single-threaded programs.
|
|
||||||
<a href="definitions.html">Definitions</a> gives a more complete
|
|
||||||
description of the multi-threading execution environment.</p>
|
|
||||||
|
|
||||||
<p>Multi-threading provides several advantages:</p>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li>Programs which would otherwise block waiting for some external
|
|
||||||
event can continue to respond if the blocking operation is placed
|
|
||||||
in a separate thread. Multi-threading is usually an absolute
|
|
||||||
requirement for these programs.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li>Well-designed multi-threaded programs may execute faster than
|
|
||||||
single-threaded programs, particularly on multi-processor hardware.
|
|
||||||
Note, however, that poorly-designed multi-threaded programs are
|
|
||||||
often slower that single-threaded programs.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li>Some program designs may be easier to formulate using a
|
|
||||||
multi-threaded approach. After all, the real world is
|
|
||||||
asynchronous!</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<h2><a name="Dangers">Dangers</a></h2>
|
|
||||||
|
|
||||||
<p>Beyond the errors which can occur in single-threaded programs,
|
|
||||||
multi-threaded programs are subject to additional errors:</p>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li><a href="definitions.html#Race condition">Race
|
|
||||||
conditions</a>.</li>
|
|
||||||
|
|
||||||
<li><a href="definitions.html#Deadlock">Deadlock</a> (sometimes
|
|
||||||
called "deadly embrace")</li>
|
|
||||||
|
|
||||||
<li><a href="definitions.html#Priority failure">Priority
|
|
||||||
failures</a> (priority inversion, infinite overtaking, starvation,
|
|
||||||
etc.)</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<p>Every multi-threaded program must be designed carefully to avoid
|
|
||||||
race conditions and deadlock. These aren't rare or exotic failures
|
|
||||||
- they are virtually guaranteed to occur unless multi-threaded code is
|
|
||||||
designed to avoid them. Priority failures are somewhat less common, but
|
|
||||||
are none-the-less serious.</p>
|
|
||||||
|
|
||||||
<p>The <a href="introduction.html">Boost.Threads design</a> attempts to
|
|
||||||
minimize these errors, but they will still occur unless the programmer
|
|
||||||
proactively designs to avoid them.</p>
|
|
||||||
|
|
||||||
<h3>Testing and debugging considerations</h3>
|
|
||||||
|
|
||||||
<p>Multi-threaded programs are non-deterministic. In other words, the
|
|
||||||
same program with the same input data may follow different execution
|
|
||||||
paths each time it is invoked. That can make testing and debugging a
|
|
||||||
nightmare:</p>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li>Failures are often not repeatable.</li>
|
|
||||||
|
|
||||||
<li>Probe effect causes debuggers to produce very different results
|
|
||||||
from non-debug uses.</li>
|
|
||||||
|
|
||||||
<li>Debuggers require special support to show thread state.</li>
|
|
||||||
|
|
||||||
<li>Tests on a single processor system may give no indication of
|
|
||||||
serious errors which would appear on multiprocessor systems, and
|
|
||||||
visa versa. Thus test cases should include a varying number of
|
|
||||||
processors.</li>
|
|
||||||
|
|
||||||
<li>For programs which create a varying number of threads according
|
|
||||||
to workload, tests which don't span the full range of
|
|
||||||
possibilities may miss serious errors.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<h3>Getting a head start</h3>
|
|
||||||
|
|
||||||
<p>Although it might appear that multi-threaded programs are inherently
|
|
||||||
unreliable, many reliable multi-threaded programs do exist.
|
|
||||||
Multi-threading techniques are known which lead to reliable
|
|
||||||
programs.</p>
|
|
||||||
|
|
||||||
<p>Design patterns for reliable multi-threaded programs, including the
|
|
||||||
important <i>monitor</i> pattern, are presented in <cite>
|
|
||||||
Pattern-Oriented Software Architecture Volume 2 - Patterns for
|
|
||||||
Concurrent and Networked Objects</cite> [<a href=
|
|
||||||
"bibliography.html#Schmidt-00">Schmidt 00</a>]. Many important
|
|
||||||
multi-threading programming considerations (independent of threading
|
|
||||||
library) are discussed in <cite>Programming with POSIX Threads</cite>
|
|
||||||
[<a href="bibliography.html#Butenhof-97">Butenhof 97</a>].</p>
|
|
||||||
|
|
||||||
<p>Doing some reading before attempting multi-threaded designs will give
|
|
||||||
you a head start toward reliable multi-threaded programs.</p>
|
|
||||||
|
|
||||||
<h2><a name="Library">C++ Standard Library usage in multi-threaded
|
|
||||||
programs</a></h2>
|
|
||||||
|
|
||||||
<h3>Runtime libraries</h3>
|
|
||||||
|
|
||||||
<p><b>Warning:</b> Multi-threaded programs such as those using <b>
|
|
||||||
Boost.Threads</b> must link to <a href="definitions.html#Thread-safe">
|
|
||||||
thread-safe</a> versions of all runtime libraries used by the program,
|
|
||||||
including the runtime library for the C++ Standard Library. Otherwise
|
|
||||||
<a href="definitions.html#Race condition">race conditions</a> will
|
|
||||||
occur when multiple threads simultaneously execute runtime library
|
|
||||||
functions for <i>new</i>, <i>delete</i>, or other language features
|
|
||||||
which imply shared state.</p>
|
|
||||||
|
|
||||||
<h3>Potentially non-thread-safe functions</h3>
|
|
||||||
|
|
||||||
<p>Certain C++ Standard Library functions inherited from C are
|
|
||||||
particular problems because they hold internal state between calls:</p>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li>rand</li>
|
|
||||||
|
|
||||||
<li>strtok</li>
|
|
||||||
|
|
||||||
<li>asctime</li>
|
|
||||||
|
|
||||||
<li>ctime</li>
|
|
||||||
|
|
||||||
<li>gmtime</li>
|
|
||||||
|
|
||||||
<li>localtime</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<p>It is possible to write thread-safe implementations of these by
|
|
||||||
using <a href="thread_specific_ptr.html">thread-specific storage</a>,
|
|
||||||
and several C++ compiler vendors do just that. The technique is
|
|
||||||
well-know and is explained in [<a href=
|
|
||||||
"bibliography.html#Butenhof-97">Buttenhof-97</a>].</p>
|
|
||||||
|
|
||||||
<p>But at least one vendor (HP-UX) does not provide thread-safe
|
|
||||||
implementations of the above functions in their otherwise thread-safe
|
|
||||||
runtime library. Instead they provide replacement functions with
|
|
||||||
different names and arguments.</p>
|
|
||||||
|
|
||||||
<p><b>Recommendation:</b> For the most portable, yet thread-safe code,
|
|
||||||
use Boost replacements for the problem functions. See the <a href=
|
|
||||||
"../../random/index.html">Boost Random Number Library</a> and <a href=
|
|
||||||
"../../tokenizer/index.htm">Boost Tokenizer Library</a>.</p>
|
|
||||||
|
|
||||||
<h2><a name="Common">Common</a> requirements for all Boost.Threads
|
|
||||||
components</h2>
|
|
||||||
|
|
||||||
<h3>Exceptions</h3>
|
|
||||||
|
|
||||||
<p><b>Boost.Threads</b> destructors never throw exceptions. Unless
|
|
||||||
otherwise specified, other <b>Boost.Threads</b> functions that do not
|
|
||||||
have an exception-specification may throw implementation-defined
|
|
||||||
exceptions.</p>
|
|
||||||
|
|
||||||
<p>In particular, <b>Boost.Threads</b> reports failure to allocate
|
|
||||||
storage by throwing an exception of type std::bad_alloc, or a class
|
|
||||||
derived from std::bad_alloc, failure to obtain thread resources other
|
|
||||||
than memory by throwing an exception of type <a href=
|
|
||||||
"thread_resource_error.html">boost::thread_resource_error</a>, and
|
|
||||||
certain lock related failures by throwing an exception of type <a href=
|
|
||||||
"lock_error.html">boost::lock_error</a></p>
|
|
||||||
|
|
||||||
<p><b>Rationale:</b> Follows the C++ Standard Library practice of
|
|
||||||
allowing all functions except destructors or other specified functions
|
|
||||||
to throw exceptions on errors.</p>
|
|
||||||
|
|
||||||
<h3><a name="NonCopyable">NonCopyable</a> requirement</h3>
|
|
||||||
|
|
||||||
<p><b>Boost.Threads</b> classes documented as meeting the NonCopyable
|
|
||||||
requirement disallow copy construction and copy assignment. For the
|
|
||||||
sake of exposition, the synopsis of such classes show private
|
|
||||||
derivation from <a href="../../utility/utility.htm">
|
|
||||||
boost::noncopyable</a>. Users should not depend on this derivation,
|
|
||||||
however, as implementations are free to meet the NonCopyable
|
|
||||||
requirement in other ways.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p>Revised
|
|
||||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->05 November, 2001<!--webbot bot="Timestamp" endspan i-checksum="39359" --></p>
|
|
||||||
|
|
||||||
<p>© Copyright 2001 Beman Dawes</p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
15
doc/overview.qbk
Normal file
15
doc/overview.qbk
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
[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]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
@@ -1,481 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content=
|
|
||||||
"text/html; charset=iso-8859-1">
|
|
||||||
<meta name="keywords" content="threads, BTL, thread library, C++">
|
|
||||||
|
|
||||||
<title>Boost.Threads, rationale</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body bgcolor="#ffffff" link="#0000ff" vlink="#800080">
|
|
||||||
<table summary="header" border="0" cellpadding="7" cellspacing="0"
|
|
||||||
width="100%">
|
|
||||||
<tr>
|
|
||||||
<td valign="top" width="300">
|
|
||||||
<h3><img height="86" alt="C++ Boost" src=
|
|
||||||
"../../../c++boost.gif" width="277"></h3>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td valign="top">
|
|
||||||
<h1 align="center">Boost.Threads</h1>
|
|
||||||
|
|
||||||
<h2 align="center">Rationale</h2>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p>This page explains the rationale behind various design decisions in
|
|
||||||
the <b>Boost.Threads</b> library. Having the rationale documented here
|
|
||||||
should explain how we arrived at the current design as well as prevent
|
|
||||||
future rehashing of discussions and thought processes that have already
|
|
||||||
occurred. It can also give users a lot of insight into the design
|
|
||||||
process required for this library.</p>
|
|
||||||
|
|
||||||
<h2><a name="library">Rationale for the Creation of
|
|
||||||
Boost.Threads</a></h2>
|
|
||||||
|
|
||||||
<p>Processes often have a degree of "potential parallelism"
|
|
||||||
and it can often be more intuitive to design systems with this in mind.
|
|
||||||
Further, these parallel processes can result in more responsive
|
|
||||||
programs. The benefits for multi-threaded programming are quite well
|
|
||||||
known to most modern programmers, yet the C++ language doesn't
|
|
||||||
directly support this concept.</p>
|
|
||||||
|
|
||||||
<p>Many platforms support multi-threaded programming despite the fact
|
|
||||||
that the language doesn't support it. They do this through external
|
|
||||||
libraries, which are, unfortunately, platform specific. POSIX has tried
|
|
||||||
to address this problem through the standardization of a
|
|
||||||
"pthread" library. However, this is a standard only on POSIX
|
|
||||||
platforms, so its portability is limited.</p>
|
|
||||||
|
|
||||||
<p>Another problem with POSIX and other platform specific thread
|
|
||||||
libraries is that they are almost universally C based libraries. This
|
|
||||||
leaves several C++ specific issues unresolved, such as what happens
|
|
||||||
when an exception is thrown in a thread. Further, there are some C++
|
|
||||||
concepts, such as destructors, that can make usage much easier than
|
|
||||||
what's available in a C library.</p>
|
|
||||||
|
|
||||||
<p>What's truly needed is C++ language support for threads.
|
|
||||||
However, the C++ standards committee needs existing practice or a good
|
|
||||||
proposal as a starting point for adding this to the standard.</p>
|
|
||||||
|
|
||||||
<p>The Boost.Threads library was developed to provide a C++ developer
|
|
||||||
with a portable interface for writing multi-threaded programs on
|
|
||||||
numerous platforms. There's a hope that the library can be the
|
|
||||||
basis for a more detailed proposal for the C++ standards committee to
|
|
||||||
consider for inclusion in the next C++ standard.</p>
|
|
||||||
|
|
||||||
<h2><a name="primitives">Rationale for the Low Level Primitives
|
|
||||||
Supported in Boost.Threads</a></h2>
|
|
||||||
|
|
||||||
<p>The Boost.Threads library supplies a set of low level primitives for
|
|
||||||
writing multi-threaded programs, such as mutexes and condition variables.
|
|
||||||
In fact, the first release of Boost.Threads supports only these low level
|
|
||||||
primitives. However, computer science research has shown that use of these
|
|
||||||
primitives is difficult since there's no way to mathematically prove
|
|
||||||
that a usage pattern is correct, meaning it doesn't result in race
|
|
||||||
conditions or deadlocks. There are several algebras (such as CSP, CCS and
|
|
||||||
Join calculus) that have been developed to help write provably correct
|
|
||||||
parallel processes. In order to prove the correctness these processes must
|
|
||||||
be coded using higher level abstractions. So why does Boost.Threads support
|
|
||||||
the lower level concepts?</p>
|
|
||||||
|
|
||||||
<p>The reason is simple: the higher level concepts need to be
|
|
||||||
implemented using at least some of the lower level concepts. So having
|
|
||||||
portable lower level concepts makes it easier to develop the higher
|
|
||||||
level concepts and will allow researchers to experiment with various
|
|
||||||
techniques.</p>
|
|
||||||
|
|
||||||
<p>Beyond this theoretical application of higher level concepts,
|
|
||||||
however, the fact remains that many multi-threaded programs are written
|
|
||||||
using only the lower level concepts, so they are useful in and of
|
|
||||||
themselves, even if it's hard to prove that their usage is correct.
|
|
||||||
Since many users will be familiar with these lower level concepts but
|
|
||||||
be unfamiliar with any of the higher level concepts there's also an
|
|
||||||
argument for accessibility.</p>
|
|
||||||
|
|
||||||
<h2><a name="lock_objects">Rationale for the Lock Design</a></h2>
|
|
||||||
|
|
||||||
<p>Programmers who are used to multi-threaded programming issues will
|
|
||||||
quickly note that the Boost.Thread's design for mutex lock concepts
|
|
||||||
is not <a href="definitions.html#Thread-safe">thread-safe</a> (this is
|
|
||||||
clearly documented as well). At first this may seem like a serious
|
|
||||||
design flaw. Why have a multi-threading primitive that's not
|
|
||||||
thread-safe itself?</p>
|
|
||||||
|
|
||||||
<p>A lock object is not a synchronization primitive. A lock
|
|
||||||
object's sole responsibility is to ensure that a mutex is both
|
|
||||||
locked and unlocked in a manner that won't result in the common
|
|
||||||
error of locking a mutex and then forgetting to unlock it. This means
|
|
||||||
that instances of a lock object are only going to be created, at least
|
|
||||||
in theory, within block scope and won't be shared between threads.
|
|
||||||
Only the mutex objects will be created outside of block scope and/or
|
|
||||||
shared between threads. Though it's possible to create a lock
|
|
||||||
object outside of block scope and to share it between threads to do so
|
|
||||||
would not be a typical usage. Nor are there any cases when such usage
|
|
||||||
would be required.</p>
|
|
||||||
|
|
||||||
<p>Lock objects must maintain some state information. In order to allow
|
|
||||||
a program to determine if a try_lock or timed_lock was successful the
|
|
||||||
lock object must retain state indicating the success or failure of the
|
|
||||||
call made in its constructor. If a lock object were to have such state
|
|
||||||
and remain thread-safe it would need to synchronize access to the state
|
|
||||||
information which would result in roughly doubling the time of most
|
|
||||||
operations. Worse, since checking the state can occur only by a call
|
|
||||||
after construction we'd have a race condition if the lock object
|
|
||||||
were shared between threads.</p>
|
|
||||||
|
|
||||||
<p>So, to avoid the overhead of synchronizing access to the state
|
|
||||||
information and to avoid the race condition the Boost.Threads library
|
|
||||||
simply does nothing to make lock objects thread-safe. Instead, sharing
|
|
||||||
a lock object between threads results in undefined behavior. Since the
|
|
||||||
only proper usage of lock objects is within block scope this isn't
|
|
||||||
a problem, and so long as the lock object is properly used there's
|
|
||||||
no danger of any multi-threading issues.</p>
|
|
||||||
|
|
||||||
<h2><a name="thread">Rationale for Non-copyable Thread Type</a></h2>
|
|
||||||
|
|
||||||
<p>Programmers who are used to C libraries for multi-threaded
|
|
||||||
programming are likely to wonder why Boost.Threads uses a non-copyable
|
|
||||||
design for <a href="thread.html">boost::thread</a>. After all, the C
|
|
||||||
thread types are copyable, and you often have a need for copying them
|
|
||||||
within user code. However, careful comparison of C designs to C++
|
|
||||||
designs shows a flaw in this logic.</p>
|
|
||||||
|
|
||||||
<p>All C types are copyable. It is, in fact, not possible to make a
|
|
||||||
non-copyable type in C. For this reason types that represent system
|
|
||||||
resources in C are often designed to behave very similarly to a pointer
|
|
||||||
to dynamic memory. There's an API for acquiring the resource and an
|
|
||||||
API for releasing the resources. For memory we have pointers as the
|
|
||||||
type and alloc/free for the acquisition and release APIs. For files we
|
|
||||||
have FILE* as the type and fopen/fclose for the acquisition and release
|
|
||||||
APIs. You can freely copy instances of the types but must manually
|
|
||||||
manage the lifetime of the actual resource through the acquisition and
|
|
||||||
release APIs.</p>
|
|
||||||
|
|
||||||
<p>C++ designs recognize that the acquisition and release APIs are
|
|
||||||
error prone and try to eliminate possible errors by acquiring the
|
|
||||||
resource in the constructor and releasing it in the destructor. The
|
|
||||||
best example of such a design is the std::iostream set of classes which
|
|
||||||
can represent the same resource as the FILE* type in C. A file is
|
|
||||||
opened in the std::fstream's constructor and closed in its
|
|
||||||
destructor. However, if an iostream were copyable it could lead to a
|
|
||||||
file being closed twice, an obvious error, so the std::iostream types
|
|
||||||
are noncopyable by design. This is the same design used by
|
|
||||||
boost::thread, which is a simple and easy to understand design
|
|
||||||
that's consistent with other C++ standard types.</p>
|
|
||||||
|
|
||||||
<p>During the design of boost::thread it was pointed out that it would
|
|
||||||
be possible to allow it to be a copyable type if some form of
|
|
||||||
"reference management" were used, such as ref-counting or
|
|
||||||
ref-lists, and many argued for a boost::thread_ref design instead. The
|
|
||||||
reasoning was that copying "thread" objects was a typical
|
|
||||||
need in the C libraries, and so presumably would be in the C++
|
|
||||||
libraries as well. It was also thought that implementations could
|
|
||||||
provide more efficient reference management then wrappers (such as
|
|
||||||
boost::shared_ptr) around a noncopyable thread concept. Analysis of
|
|
||||||
whether or not these arguments would hold true don't appear to bear
|
|
||||||
them out. To illustrate the analysis we'll first provide
|
|
||||||
pseudo-code illustrating the six typical usage patterns of a thread
|
|
||||||
object.</p>
|
|
||||||
|
|
||||||
<h3>1. Simple creation of a thread.</h3>
|
|
||||||
<pre>
|
|
||||||
void foo()
|
|
||||||
{
|
|
||||||
create_thread(&bar);
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h3>2. Creation of a thread that's later joined.</h3>
|
|
||||||
<pre>
|
|
||||||
void foo()
|
|
||||||
{
|
|
||||||
thread = create_thread(&bar);
|
|
||||||
join(thread);
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h3>3. Simple creation of several threads in a loop.</h3>
|
|
||||||
<pre>
|
|
||||||
void foo()
|
|
||||||
{
|
|
||||||
for (int i=0; i<NUM_THREADS; ++i)
|
|
||||||
create_thread(&bar);
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h3>4. Creation of several threads in a loop which are later
|
|
||||||
joined.</h3>
|
|
||||||
<pre>
|
|
||||||
void foo()
|
|
||||||
{
|
|
||||||
for (int i=0; i<NUM_THREADS; ++i)
|
|
||||||
threads[i] = create_thread(&bar);
|
|
||||||
for (int i=0; i<NUM_THREADS; ++i)
|
|
||||||
threads[i].join();
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h3>5. Creation of a thread whose ownership is passed to another
|
|
||||||
object/method.</h3>
|
|
||||||
<pre>
|
|
||||||
void foo()
|
|
||||||
{
|
|
||||||
thread = create_thread(&bar);
|
|
||||||
manager.owns(thread);
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h3>6. Creation of a thread whose ownership is shared between multiple
|
|
||||||
objects.</h3>
|
|
||||||
<pre>
|
|
||||||
void foo()
|
|
||||||
{
|
|
||||||
thread = create_thread(&bar);
|
|
||||||
manager1.add(thread);
|
|
||||||
manager2.add(thread);
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>Of these usage patterns there's only one that requires reference
|
|
||||||
management (number 6). Hopefully it's fairly obvious that this
|
|
||||||
usage pattern simply won't occur as often as the other usage
|
|
||||||
patterns. So there really isn't a "typical need" for a
|
|
||||||
thread concept, though there is some need.</p>
|
|
||||||
|
|
||||||
<p>Since the need isn't typical we must use different criteria for
|
|
||||||
deciding on either a thread_ref or thread design. Possible criteria
|
|
||||||
include ease of use and performance. So let's analyze both of these
|
|
||||||
carefully.</p>
|
|
||||||
|
|
||||||
<p>With ease of use we can look at existing experience. The standard
|
|
||||||
C++ objects that represent a system resource, such as std::iostream,
|
|
||||||
are noncopyable, so we know that C++ programmers must at least be
|
|
||||||
experienced with this design. Most C++ developers are also used to
|
|
||||||
smart pointers such as boost::shared_ptr, so we know they can at least
|
|
||||||
adapt to a thread_ref concept with little effort. So existing
|
|
||||||
experience isn't going to lead us to a choice.</p>
|
|
||||||
|
|
||||||
<p>The other thing we can look at is how difficult it is to use both
|
|
||||||
types for the six usage patterns above. If we find it overly difficult
|
|
||||||
to use a concept for any of the usage patterns there would be a good
|
|
||||||
argument for choosing the other design. So we'll code all six usage
|
|
||||||
patterns using both designs.</p>
|
|
||||||
|
|
||||||
<h3>1.</h3>
|
|
||||||
<pre>
|
|
||||||
void foo()
|
|
||||||
{
|
|
||||||
thread thrd(&bar);
|
|
||||||
}
|
|
||||||
|
|
||||||
void foo()
|
|
||||||
{
|
|
||||||
thread_ref thrd = create_thread(&bar);
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h3>2.</h3>
|
|
||||||
<pre>
|
|
||||||
void foo()
|
|
||||||
{
|
|
||||||
thread thrd(&bar);
|
|
||||||
thrd.join();
|
|
||||||
}
|
|
||||||
|
|
||||||
void foo()
|
|
||||||
{
|
|
||||||
thread_ref thrd =
|
|
||||||
create_thread(&bar);thrd->join();
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h3>3.</h3>
|
|
||||||
<pre>
|
|
||||||
void foo()
|
|
||||||
{
|
|
||||||
for (int i=0; i<NUM_THREADS; ++i)
|
|
||||||
thread thrd(&bar);
|
|
||||||
}
|
|
||||||
|
|
||||||
void foo()
|
|
||||||
{
|
|
||||||
for (int i=0; i<NUM_THREADS; ++i)
|
|
||||||
thread_ref thrd = create_thread(&bar);
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h3>4.</h3>
|
|
||||||
<pre>
|
|
||||||
void foo()
|
|
||||||
{
|
|
||||||
std::auto_ptr<thread> threads[NUM_THREADS];
|
|
||||||
for (int i=0; i<NUM_THREADS; ++i)
|
|
||||||
threads[i] = std::auto_ptr<thread>(new thread(&bar));
|
|
||||||
for (int i= 0; i<NUM_THREADS;
|
|
||||||
++i)threads[i]->join();
|
|
||||||
}
|
|
||||||
|
|
||||||
void foo()
|
|
||||||
{
|
|
||||||
thread_ref threads[NUM_THREADS];
|
|
||||||
for (int i=0; i<NUM_THREADS; ++i)
|
|
||||||
threads[i] = create_thread(&bar);
|
|
||||||
for (int i= 0; i<NUM_THREADS;
|
|
||||||
++i)threads[i]->join();
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h3>5.</h3>
|
|
||||||
<pre>
|
|
||||||
void foo()
|
|
||||||
{
|
|
||||||
thread thrd* = new thread(&bar);
|
|
||||||
manager.owns(thread);
|
|
||||||
}
|
|
||||||
|
|
||||||
void foo()
|
|
||||||
{
|
|
||||||
thread_ref thrd = create_thread(&bar);
|
|
||||||
manager.owns(thrd);
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h3>6.</h3>
|
|
||||||
<pre>
|
|
||||||
void foo()
|
|
||||||
{
|
|
||||||
boost::shared_ptr<thread> thrd(new thread(&bar));
|
|
||||||
manager1.add(thrd);
|
|
||||||
manager2.add(thrd);
|
|
||||||
}
|
|
||||||
|
|
||||||
void foo()
|
|
||||||
{
|
|
||||||
thread_ref thrd = create_thread(&bar);
|
|
||||||
manager1.add(thrd);
|
|
||||||
manager2.add(thrd);
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>This shows the usage patterns being nearly identical in complexity
|
|
||||||
for both designs. The only actual added complexity occurs because of
|
|
||||||
the use of operator new in (4), (5) and (6) and the use of
|
|
||||||
std::auto_ptr and boost::shared_ptr in (4) and (6) respectively.
|
|
||||||
However, that's not really much added complexity, and C++
|
|
||||||
programmers are used to using these idioms any way. Some may dislike
|
|
||||||
the presence of operator new in user code, but this can be eliminated
|
|
||||||
by proper design of higher level concepts, such as the
|
|
||||||
boost::thread_group class that simplifies example (4) down to:</p>
|
|
||||||
<pre>
|
|
||||||
void foo()
|
|
||||||
{
|
|
||||||
thread_group threads;
|
|
||||||
for (int i=0; i<NUM_THREADS; ++i)
|
|
||||||
threads.create_thread(&bar);
|
|
||||||
threads.join_all();
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>So ease of use is really a wash and not much help in picking a
|
|
||||||
design.</p>
|
|
||||||
|
|
||||||
<p>So what about performance? If you look at the above code examples we
|
|
||||||
can analyze the theoretical impact to performance that both designs
|
|
||||||
have. For (1) we can see that platforms that don't have a
|
|
||||||
ref-counted native thread type (POSIX, for instance) will be impacted
|
|
||||||
by a thread_ref design. Even if the native thread type is ref-counted
|
|
||||||
there may be an impact if more state information has to be maintained
|
|
||||||
for concepts foreign to the native API, such as clean up stacks for
|
|
||||||
Win32 implementations. For (2) the performance impact will be identical
|
|
||||||
to (1). The same for (3). For (4) things get a little more interesting
|
|
||||||
and we find that theoretically at least the thread_ref may perform
|
|
||||||
faster since the thread design requires dynamic memory
|
|
||||||
allocation/deallocation. However, in practice there may be dynamic
|
|
||||||
allocation for the thread_ref design as well, it will just be hidden
|
|
||||||
from the user. As long as the implementation has to do dynamic
|
|
||||||
allocations the thread_ref loses again because of the reference
|
|
||||||
management. For (5) we see the same impact as we do for (4). For (6) we
|
|
||||||
still have a possible impact to the thread design because of dynamic
|
|
||||||
allocation but thread_ref no longer suffers because of it's
|
|
||||||
reference management, and in fact, theoretically at least, the
|
|
||||||
thread_ref may do a better job of managing the references. All of this
|
|
||||||
indicates that thread wins for (1), (2) and (3), with (4) and (5) the
|
|
||||||
winner depends on the implementation and the platform but the thread
|
|
||||||
design probably has a better chance, and with (6) it will again depend
|
|
||||||
on the implementation and platform but this time we favor thread_ref
|
|
||||||
slightly. Given all of this it's a narrow margin, but the thread
|
|
||||||
design prevails.</p>
|
|
||||||
|
|
||||||
<p>Given this analysis, and the fact that noncopyable objects for
|
|
||||||
system resources are the normal designs that C++ programmers are used
|
|
||||||
to dealing with, the Boost.Threads library has gone with a noncopyable
|
|
||||||
design.</p>
|
|
||||||
|
|
||||||
<h2>Rationale for not providing <i><a name="Events">Event</a>
|
|
||||||
Variables</i></h2>
|
|
||||||
|
|
||||||
<p><i>Event variables</i> are simply far too error-prone. <a href=
|
|
||||||
"condition.html">Condition variables</a> are a much safer
|
|
||||||
alternative.</p>
|
|
||||||
|
|
||||||
<p>[Note that Graphical User Interface <i>events</i> are a different
|
|
||||||
concept, and are not what is being discussed here.]</p>
|
|
||||||
|
|
||||||
<p>Event variables were one of the first synchronization primitives.
|
|
||||||
They are still used today, for example, in the native Windows
|
|
||||||
multithreading API.</p>
|
|
||||||
|
|
||||||
<p>Yet both respected computer science researchers and experienced
|
|
||||||
multithreading practitioners believe event variables are so inherently
|
|
||||||
error-prone that they should never be used, and thus should not be part
|
|
||||||
of a multithreading library.</p>
|
|
||||||
|
|
||||||
<p>Per Brinch Hansen <a href="bibliography.html#Brinch-Hansen-73">
|
|
||||||
[Brinch Hansen 73]</a> analyzed event variables in some detail,
|
|
||||||
pointing out [emphasis his] that "<i>event operations force the
|
|
||||||
programmer to be aware of the relative speeds of the sending and
|
|
||||||
receiving processes</i>". His summary:</p>
|
|
||||||
|
|
||||||
<blockquote>
|
|
||||||
<p>We must therefore conclude that event variables of the previous
|
|
||||||
type are impractical for system design. <i>The effect of an
|
|
||||||
interaction between two processes must be independent of the speed
|
|
||||||
at which it is carried out.</i></p>
|
|
||||||
</blockquote>
|
|
||||||
|
|
||||||
<p>Experienced programmers using the Windows platform today report that
|
|
||||||
event variables are a continuing source of errors, even after previous
|
|
||||||
bad experiences caused them to be very careful in their use of event
|
|
||||||
variables. Overt problems can be avoided, for example, by teaming the
|
|
||||||
event variable with a mutex, but that may just convert a <a href=
|
|
||||||
"definitions.html#Race condition">race condition</a> into another
|
|
||||||
problem, such as excessive resource use. One of the most distressing
|
|
||||||
aspects of the experience reports is the claim that many defects are
|
|
||||||
latent. That is, the programs appear to work correctly, but contain
|
|
||||||
hidden timing dependencies which will cause them to fail when
|
|
||||||
environmental factors or usage patterns change, altering relative
|
|
||||||
thread timings.</p>
|
|
||||||
|
|
||||||
<p>The decision to exclude event variables from Boost.Threads has been
|
|
||||||
surprising to some Windows programmers. They have written programs
|
|
||||||
which work using event variables, and wonder what the problem is. It
|
|
||||||
seems similar to the "goto considered harmful" controversy of
|
|
||||||
30 years ago. It isn't that events, like gotos, can't be made
|
|
||||||
to work, but rather that virtually all programs using alternatives will
|
|
||||||
be easier to write, debug, read, maintain, and be less likely to
|
|
||||||
contain latent defects.</p>
|
|
||||||
|
|
||||||
<p>[Rationale provided by Beman Dawes]</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p>Revised
|
|
||||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->05 November, 2001<!--webbot bot="Timestamp" endspan i-checksum="39359" --></p>
|
|
||||||
|
|
||||||
<p><i>© Copyright <a href="mailto:williamkempf@hotmail.com">
|
|
||||||
William E. Kempf</a> 2001 all rights reserved.</i></p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
@@ -1,368 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content=
|
|
||||||
"text/html; charset=iso-8859-1">
|
|
||||||
<meta name="keywords" content="threads, BTL, thread library, C++">
|
|
||||||
<link rel="stylesheet" type="text/css" href="styles.css">
|
|
||||||
|
|
||||||
<title>Boost.Threads, recursive_mutex</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body bgcolor="#FFFFFF" link="#0000FF" vlink="#800080">
|
|
||||||
<table summary="header" border="0" cellpadding="7" cellspacing="0" width="100%">
|
|
||||||
<tr>
|
|
||||||
<td valign="top" width="300">
|
|
||||||
<h3><img src="../../../c++boost.gif" alt="C++ Boost" width=
|
|
||||||
"277" height="86"></h3>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td valign="top">
|
|
||||||
<h1 align="center">Boost.Threads</h1>
|
|
||||||
|
|
||||||
<h2 align="center">recursive_mutex<br>
|
|
||||||
recursive_try_mutex<br>
|
|
||||||
recursive_timed_mutex</h2>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p><a href="#Introduction">Introduction</a><br>
|
|
||||||
<a href="#Header">Header</a><br>
|
|
||||||
<a href="#recursive_mutex Synopsis">Class recursive_mutex
|
|
||||||
Synopsis</a><br>
|
|
||||||
<a href="#recursive_mutex Members">Class recursive_mutex
|
|
||||||
Members</a><br>
|
|
||||||
<a href="#recursive_try_mutex Synopsis">Class recursive_try_mutex
|
|
||||||
Synopsis</a><br>
|
|
||||||
<a href="#recursive_try_mutex Members">Class recursive_try_mutex
|
|
||||||
Members</a><br>
|
|
||||||
<a href="#recursive_timed_mutex Synopsis">Class recursive_timed_mutex
|
|
||||||
Synopsis</a><br>
|
|
||||||
<a href="#recursive_timed_mutex Members">Class recursive_timed_mutex
|
|
||||||
Members</a><br>
|
|
||||||
<a href="#Example">Example</a></p>
|
|
||||||
|
|
||||||
<h2><a name="Introduction">Introduction</a></h2>
|
|
||||||
|
|
||||||
<p>The <code>recursive_mutex</code>, <code>recursive_try_mutex</code>
|
|
||||||
and <code>recursive_timed_mutex</code> classes define full featured
|
|
||||||
models of the <a href="mutex_concept.html#Mutex">Mutex</a>, <a href=
|
|
||||||
"mutex_concept.html#TryMutex">TryMutex</a> and <a href=
|
|
||||||
"mutex_concept.html#TimedMutex">TimedMutex</a> concepts with recursive
|
|
||||||
locking semantics. These types should be used to synchronize access to
|
|
||||||
shared resources when recursive locking by a single thread is likely to
|
|
||||||
occur. A good example for this is when a class supplies "internal
|
|
||||||
synchronization" to ensure <a href="definitions.html#Thread-safe">
|
|
||||||
thread-safety</a> and a function of the class may have to call other
|
|
||||||
functions of the class which also attempt to lock the mutex. For
|
|
||||||
recursive locking mechanics, see <a href="mutex.html">mutexes</a>.</p>
|
|
||||||
|
|
||||||
<p>Each class supplies one or more typedefs for lock types which model
|
|
||||||
matching lock concepts. For the best possible performance you should
|
|
||||||
use the mutex class that supports the minimum set of lock types that
|
|
||||||
you need.</p>
|
|
||||||
|
|
||||||
<table summary="lock types" border="1" cellpadding="5">
|
|
||||||
<tr>
|
|
||||||
<td><b>Mutex Class</b></td>
|
|
||||||
|
|
||||||
<td><b>Lock name</b></td>
|
|
||||||
|
|
||||||
<td><b>Implementation defined Lock Type</b></td>
|
|
||||||
|
|
||||||
<td><b>Lock Concept</b></td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td valign="top"><a href="#recursive_mutex Synopsis"><code>
|
|
||||||
recursive_mutex</code></a></td>
|
|
||||||
|
|
||||||
<td valign="middle"><code>scoped_lock</code></td>
|
|
||||||
|
|
||||||
<td valign="middle"><a href="scoped_lock.html"><code>
|
|
||||||
detail::thread::scoped_lock<recursive_mutex></code></a></td>
|
|
||||||
|
|
||||||
<td valign="middle"><a href="lock_concept.html#ScopedLock">
|
|
||||||
ScopedLock</a></td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td valign="top"><code><a href="#recursive_try_mutex Synopsis">
|
|
||||||
recursive_try_mutex</a></code></td>
|
|
||||||
|
|
||||||
<td valign="middle"><code>scoped_lock<br>
|
|
||||||
scoped_try_lock</code></td>
|
|
||||||
|
|
||||||
<td valign="middle"><a href="scoped_lock.html"><code>
|
|
||||||
detail::thread::scoped_lock<recursive_try_mutex><br>
|
|
||||||
</code></a> <code><a href="scoped_try_lock.html">
|
|
||||||
detail::thread::scoped_try_lock<recursive_try_mutex></a></code></td>
|
|
||||||
|
|
||||||
<td valign="middle"><a href="lock_concept.html#ScopedLock">
|
|
||||||
ScopedLock</a><br>
|
|
||||||
<a href="lock_concept.html#ScopedTryLock">
|
|
||||||
ScopedTryLock</a></td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td valign="top"><code><a href=
|
|
||||||
"#recursive_timed_mutex Synopsis">
|
|
||||||
recursive_timed_mutex</a></code> </td>
|
|
||||||
|
|
||||||
<td valign="middle"><code>scoped_lock<br>
|
|
||||||
scoped_try_lock<br>
|
|
||||||
scoped_timed_lock</code></td>
|
|
||||||
|
|
||||||
<td valign="middle"><a href="scoped_lock.html"><code>
|
|
||||||
detail::thread::scoped_lock<recursive_timed_mutex></code></a><br>
|
|
||||||
|
|
||||||
<a href="scoped_try_lock.html"><code>
|
|
||||||
detail::thread::scoped_try_lock<recursive_timed_mutex></code></a><br>
|
|
||||||
|
|
||||||
<a href="scoped_timed_lock.html"><code>
|
|
||||||
detail::thread::scoped_timed_lock<recursive_timed_mutex></code></a></td>
|
|
||||||
|
|
||||||
<td valign="middle"><a href="lock_concept.html#ScopedLock">
|
|
||||||
ScopedLock</a><br>
|
|
||||||
<a href="lock_concept.html#ScopedTryLock">
|
|
||||||
ScopedTryLock</a><br>
|
|
||||||
<a href="lock_concept.html#ScopedTimedLock">
|
|
||||||
ScopedTimedLock</a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<p>The <code>recursive_mutex</code>, <code>recursive_try_mutex</code>
|
|
||||||
and <code>recursive_timed_mutex</code> employ a <code>Recursive</code>
|
|
||||||
<a href="mutex_concept.html#LockingStrategies">locking strategy</a>, so
|
|
||||||
attempts to recursively lock them succeed and an internal "lock
|
|
||||||
count" is maintained. Attempts to unlock them by a thread that
|
|
||||||
does not own a lock on them will result in a <a href="lock_error.html">
|
|
||||||
lock_error</a> exception being thrown.</p>
|
|
||||||
|
|
||||||
<p>The <code>recursive_mutex</code>, <code>recursive_try_mutex</code>
|
|
||||||
and <code>recursive_timed_mutex</code> leave the <a href=
|
|
||||||
"mutex_concept.html#SchedulingPolicies">scheduling policy</a> as <code>
|
|
||||||
Unspecified</code>. Programmers should assume that threads waiting for
|
|
||||||
a lock on objects of these types acquire the lock in a random order,
|
|
||||||
even though the specific behavior for a given platform may be
|
|
||||||
different.</p>
|
|
||||||
|
|
||||||
<h2><a name="Header">Header</a></h2>
|
|
||||||
<pre>
|
|
||||||
#include <a href=
|
|
||||||
"../../../boost/thread/recursive_mutex.hpp"><boost/thread/recursive_mutex.hpp></a>
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h2>Class <a name="recursive_mutex Synopsis">recursive_mutex
|
|
||||||
Synopsis</a></h2>
|
|
||||||
<hr>
|
|
||||||
<pre>
|
|
||||||
namespace boost
|
|
||||||
{
|
|
||||||
class recursive_mutex : private <a href=
|
|
||||||
"../../utility/utility.htm">boost::noncopyable</a> // Exposition only.
|
|
||||||
// Class recursive_mutex meets the <a href=
|
|
||||||
"overview.html#NonCopyable">NonCopyable</a> requirement.
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef <i>[implementation defined; see <a href=
|
|
||||||
"#Introduction">Introduction</a>]</i> scoped_lock;
|
|
||||||
|
|
||||||
recursive_mutex();
|
|
||||||
~recursive_mutex();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h2>Class <a name="recursive_mutex Members">recursive_mutex
|
|
||||||
Members</a></h2>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>Constructor</h3>
|
|
||||||
<pre>
|
|
||||||
recursive_mutex();
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Postconditions:</b> <code>*this</code> is in the unlocked
|
|
||||||
state.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>Destructor</h3>
|
|
||||||
<pre>
|
|
||||||
~recursive_mutex();
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Requires:</b> <code>*this</code> is in the unlocked state.</p>
|
|
||||||
|
|
||||||
<p><b>Effects:</b> Destroys <code>*this</code>.</p>
|
|
||||||
|
|
||||||
<p><b>Dangers:</b> Destruction of a locked mutex is a serious
|
|
||||||
programming error resulting in undefined behavior such as a program
|
|
||||||
crash..</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h2>Class <a name="recursive_try_mutex Synopsis">recursive_try_mutex
|
|
||||||
Synopsis</a></h2>
|
|
||||||
<pre>
|
|
||||||
namespace boost
|
|
||||||
{
|
|
||||||
class recursive_try_mutex : private boost::noncopyable // Exposition only.
|
|
||||||
// Class recursive_try_mutex meets the <a href=
|
|
||||||
"overview.html#NonCopyable">NonCopyable</a> requirement.
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef <i>[implementation defined; see <a href=
|
|
||||||
"#Introduction">Introduction</a>]</i> scoped_lock;
|
|
||||||
typedef <i>[implementation defined; see <a href=
|
|
||||||
"#Introduction">Introduction</a>]</i> scoped_try_lock;
|
|
||||||
|
|
||||||
recursive_try_mutex();
|
|
||||||
~recursive_try_mutex();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h2>Class <a name="recursive_try_mutex Members">recursive_try_mutex
|
|
||||||
Members</a></h2>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>Constructor</h3>
|
|
||||||
<pre>
|
|
||||||
recursive_try_mutex();
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Postconditions:</b> <code>*this</code> is in the unlocked
|
|
||||||
state.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>Destructor</h3>
|
|
||||||
<pre>
|
|
||||||
~recursive_try_mutex();
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Requires:</b> <code>*this</code> is in the unlocked state.</p>
|
|
||||||
|
|
||||||
<p><b>Effects:</b> Destroys <code>*this</code>.</p>
|
|
||||||
|
|
||||||
<p><b>Dangers:</b> Destruction of a locked mutex is a serious
|
|
||||||
programming error resulting in undefined behavior such as a program
|
|
||||||
crash..</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h2>Class <a name="recursive_timed_mutex Synopsis">
|
|
||||||
recursive_timed_mutex Synopsis</a></h2>
|
|
||||||
<pre>
|
|
||||||
namespace boost
|
|
||||||
{
|
|
||||||
class recursive_timed_mutex : private boost::noncopyable // Exposition only.
|
|
||||||
// Class recursive_timed_mutex meets the <a href=
|
|
||||||
"overview.html#NonCopyable">NonCopyable</a> requirement.
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef <i>[implementation defined; see <a href=
|
|
||||||
"#Introduction">Introduction</a>]</i> scoped_lock;
|
|
||||||
typedef <i>[implementation defined; see <a href=
|
|
||||||
"#Introduction">Introduction</a>]</i> scoped_try_lock;
|
|
||||||
typedef <i>[implementation defined; see <a href=
|
|
||||||
"#Introduction">Introduction</a>]</i> scoped_timed_lock;
|
|
||||||
|
|
||||||
recursive_timed_mutex();
|
|
||||||
~recursive_timed_mutex();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h2>Class <a name="recursive_timed_mutex Members">recursive_timed_mutex
|
|
||||||
Members</a></h2>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>Constructor</h3>
|
|
||||||
<pre>
|
|
||||||
recursive_timed_mutex();
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Postconditions:</b> <code>*this</code> is in the unlocked
|
|
||||||
state.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>Destructor</h3>
|
|
||||||
<pre>
|
|
||||||
~recursive_timed_mutex();
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Requires:</b> <code>*this</code> is in the unlocked state.</p>
|
|
||||||
|
|
||||||
<p><b>Effects:</b> Destroys <code>*this</code>.</p>
|
|
||||||
|
|
||||||
<p><b>Dangers:</b> Destruction of a locked mutex is a serious
|
|
||||||
programming error resulting in undefined behavior such as a program
|
|
||||||
crash..</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h2><a name="Example">Example</a> Usage</h2>
|
|
||||||
<pre>
|
|
||||||
#include <a href=
|
|
||||||
"../../../boost/thread/recursive_mutex.hpp"><boost/thread/recursive_mutex.hpp></a>
|
|
||||||
#include <a href=
|
|
||||||
"../../../boost/thread/thread.hpp"><boost/thread/thread.hpp></a>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
class counter
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
counter() : count(0) { }
|
|
||||||
|
|
||||||
int add(int val) {
|
|
||||||
boost::recursive_mutex::scoped_lock scoped_lock(mutex);
|
|
||||||
count += val;
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
int increment() {
|
|
||||||
boost::recursive_mutex::scoped_lock scoped_lock(mutex);
|
|
||||||
return add(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
boost::recursive_mutex mutex;
|
|
||||||
int count;
|
|
||||||
};
|
|
||||||
|
|
||||||
counter c;
|
|
||||||
|
|
||||||
void change_count(void*)
|
|
||||||
{
|
|
||||||
std::cout << "count == " << c.increment() << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int, char*[])
|
|
||||||
{
|
|
||||||
const int num_threads=4;
|
|
||||||
|
|
||||||
boost::thread_group threads;
|
|
||||||
for (int i=0; i < num_threads; ++i)
|
|
||||||
threads.create_thread(&change_count, 0);
|
|
||||||
|
|
||||||
threads.join_all();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>The output is:</p>
|
|
||||||
<pre>
|
|
||||||
count == 1
|
|
||||||
count == 2
|
|
||||||
count == 3
|
|
||||||
count == 4
|
|
||||||
</pre>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p>Revised
|
|
||||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->05 November, 2001<!--webbot bot="Timestamp" endspan i-checksum="39359" --></p>
|
|
||||||
|
|
||||||
<p><i>© Copyright <a href="mailto:williamkempf@hotmail.com">
|
|
||||||
William E. Kempf</a> 2001 all rights reserved.</i></p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
@@ -1,134 +0,0 @@
|
|||||||
<html>
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
|
||||||
<meta name="keywords" content="threads, BTL, thread library, C++">
|
|
||||||
<title>Boost.Threads, atomic_t</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body bgcolor="#FFFFFF" link="#0000FF" vlink="#800080">
|
|
||||||
|
|
||||||
<table border="0" cellpadding="7" cellspacing="0" width="100%">
|
|
||||||
<tr>
|
|
||||||
<td valign="top" width="300">
|
|
||||||
<h3><img src="../../../c++boost.gif" alt="C++ Boost" width="277" height="86"></h3>
|
|
||||||
</td>
|
|
||||||
<td valign="top">
|
|
||||||
<h1 align="center">Boost.Threads</h1>
|
|
||||||
<h2 align="center">atomic_t</h2>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h2>Header</h2>
|
|
||||||
|
|
||||||
<p>The <tt>atomic_t</tt> class defines an "atomic integer" type. This class should be used
|
|
||||||
to perform thread safe operations on an integral type with out the overhead of locks. Only
|
|
||||||
a limited set of integer operations are available with an <tt>atomic_t</tt> instance.</p>
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
#include <boost/thread/atomic.hpp>
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h2>Public Interface</h2>
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
class atomic_t
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef <b>implementation defined</b> value_type;
|
|
||||||
|
|
||||||
explicit atomic_t(value_type val=0);
|
|
||||||
};
|
|
||||||
|
|
||||||
atomic_t::value_type read(const atomic_t& x);
|
|
||||||
atomic_t::value_type increment(atomic_t& x);
|
|
||||||
atomic_t::value_type decrement(atomic_t& x);
|
|
||||||
atomic_t::value_type swap(atomic_t& x, atomic_t::value_type y);
|
|
||||||
atomic_t::value_type compare_swap(atomic_t& x, atomic_t::value_type y, atomic_t::value_type z);
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h3>Constructor</h3>
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
atomic_t(atomic_t::value_type val=0);
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>Constructs an <tt>atomic_t</tt> and sets its value to <tt>val</tt>.</p>
|
|
||||||
|
|
||||||
<h3>read</h3>
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
atomic_t::value_type read(const atomic_t& x);
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>Gets the current value of <tt>x</tt>.</p>
|
|
||||||
|
|
||||||
<h3>increment</h3>
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
atomic_t::value_type increment(atomic_t& x);
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>Increments <tt>x</tt> and returns a value <tt>< 0</tt> if the result is less than 0,
|
|
||||||
<tt>> 0</tt> if the result is greater than 0 and <tt>== 0</tt> if the result is equal to
|
|
||||||
0.</p>
|
|
||||||
|
|
||||||
<h3>decrement</h3>
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
atomic_t::value_type decrement(atomic_t& x);
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>Decrements <tt>x</tt> and returns a value <tt>< 0</tt> if the result is less than 0,
|
|
||||||
<tt>> 0</tt> if the result is greater than 0 and <tt>== 0</tt> if the result is equal to
|
|
||||||
0.</p>
|
|
||||||
|
|
||||||
<h3>swap</h3>
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
atomic_t::value_type swap(atomic_t& x, atomic_t::value_type y);
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>Assigns the value of <tt>y</tt> to <tt>x</tt> and returns the value of <tt>x</tt> prior
|
|
||||||
to the swap.</p>
|
|
||||||
|
|
||||||
<h3>compare_swap</h3>
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
atomic_t::value_type compare_swap(atomic_t& x, atomic_t::value_type y, atomic_t::value_type z);
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>Compares the value of <tt>z</tt> to the value of <tt>x</tt> and if equal sets the value of
|
|
||||||
<tt>x</tt> to the value of <tt>y</tt> and returns the value of <tt>x</tt> prior to the swap.</p>
|
|
||||||
|
|
||||||
<h2>Example Usage</h2>
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
#include <boost/thread/atomic.hpp>
|
|
||||||
#include <boost/test/test_tools.hpp>
|
|
||||||
|
|
||||||
int test_main(int, char*[])
|
|
||||||
{
|
|
||||||
boost::atomic_t a;
|
|
||||||
BOOST_TEST_VERIFY(boost::read(a) == 0);
|
|
||||||
BOOST_TEST_VERIFY(boost::increment(a) > 0);
|
|
||||||
BOOST_TEST_VERIFY(boost::decrement(a) == 0);
|
|
||||||
BOOST_TEST_VERIFY(boost::swap(a, 1) == 0);
|
|
||||||
BOOST_TEST_VERIFY(boost::swap(a, 2, 0) == 1);
|
|
||||||
BOOST_TEST_VERIFY(boost::read(a) == 1);
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p>Revised <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->05 November, 2001<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><i>© Copyright <a href="mailto:williamkempf@hotmail.com">William E. Kempf</a>
|
|
||||||
2001 all rights reserved.</i></p>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,227 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content=
|
|
||||||
"text/html; charset=iso-8859-1">
|
|
||||||
<meta name="keywords" content="threads, BTL, thread library, C++">
|
|
||||||
<link rel="stylesheet" type="text/css" href="styles.css">
|
|
||||||
|
|
||||||
<title>Boost.Threads, scoped_lock</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body bgcolor="#FFFFFF" link="#0000FF" vlink="#800080">
|
|
||||||
<table summary="header" border="0" cellpadding="7" cellspacing="0"
|
|
||||||
width="100%">
|
|
||||||
<tr>
|
|
||||||
<td valign="top" width="300">
|
|
||||||
<h3><img src="../../../c++boost.gif" alt="C++ Boost" width=
|
|
||||||
"277" height="86"></h3>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td valign="top">
|
|
||||||
<h1 align="center">Boost.Threads</h1>
|
|
||||||
|
|
||||||
<h2 align="center">scoped_lock</h2>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p><a href="#Introduction">Introduction</a><br>
|
|
||||||
<a href="#Header">Header</a><br>
|
|
||||||
<a href="#Synopsis">Synopsis</a><br>
|
|
||||||
<a href="#Members">Members</a><br>
|
|
||||||
<a href="#Example">Example</a></p>
|
|
||||||
|
|
||||||
<h2><a name="Introduction">Introduction</a></h2>
|
|
||||||
|
|
||||||
<p>This class template defines a generic lock type which meets the <a
|
|
||||||
href="lock_concept.html#ScopedLock">ScopedLock</a> requirements. The <a
|
|
||||||
href="mutex.html">mutex</a>, <a href="mutex.html">try_mutex</a>, <a
|
|
||||||
href="mutex.html">timed_mutex</a>, <a href="recursive_mutex.html">
|
|
||||||
recursive_mutex</a>, <a href="recursive_mutex.html">
|
|
||||||
recursive_try_mutex</a> and <a href="recursive_mutex.html">
|
|
||||||
recursive_timed_mutex</a> classes all use this template to define their
|
|
||||||
<code>scoped_lock</code> types.</p>
|
|
||||||
|
|
||||||
<p>Like all the <b>Boost.Threads</b> <a href="lock_concept.html">lock
|
|
||||||
models</a>, <code>scoped_lock</code> objects are meant to be
|
|
||||||
short-lived. Objects of the class are not <a href=
|
|
||||||
"definitions.html#thread-safe">thread-safe</a>, and so should not be
|
|
||||||
shared between threads.</p>
|
|
||||||
|
|
||||||
<p>Class <code>scoped_lock</code> follows the "resource
|
|
||||||
acquisition is initialization" idiom <a href=
|
|
||||||
"bibliography.html#Stroustrup-00">[Stroustrup 00 14.4.1]</a> and is a
|
|
||||||
realization of the "Scoped Locking Pattern" <a href=
|
|
||||||
"bibliography.html#Schmidt-00">[Schmidt-00]</a>. Thus the usage is to
|
|
||||||
let the constructor do the locking, and then let the destructor do the
|
|
||||||
unlocking automatically at the end of the enclosing scope. The lock()
|
|
||||||
and unlock() members are usually not explicitly called, but are
|
|
||||||
provided to allow for complex overlapping locks of multiple
|
|
||||||
mutexes.</p>
|
|
||||||
|
|
||||||
<p>The type used to instantiate the class must meet the <a href=
|
|
||||||
"mutex_concept.html#Mutex">Mutex</a> requirements.</p>
|
|
||||||
|
|
||||||
<p>Although this class is an implementation detail, it is publicly
|
|
||||||
documented here because of its importance.</p>
|
|
||||||
|
|
||||||
<h2><a name="Header">Header</a></h2>
|
|
||||||
<pre>
|
|
||||||
#include <a href=
|
|
||||||
"../../../boost/thread/detail/lock.hpp"><boost/thread/detail/lock.hpp></a>
|
|
||||||
<i>This header is usually not included directly by programmers
|
|
||||||
because it is supplied by <a href=
|
|
||||||
"../../../boost/thread/mutex.hpp"><boost/thread/mutex.hpp></a> or
|
|
||||||
<a href=
|
|
||||||
"../../../boost/thread/recursive_mutex.hpp"><boost/thread/recursive_mutex.hpp></a></i>
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h2><a name="Synopsis">Synopsis</a></h2>
|
|
||||||
<pre>
|
|
||||||
namespace boost { namespace detail { namespace thread {
|
|
||||||
template <typename Mutex>
|
|
||||||
class scoped_lock : private <a href=
|
|
||||||
"../../utility/utility.htm#Class noncopyable">boost::noncopyable</a> // Exposition only.
|
|
||||||
// Class scoped_lock meets the <a href=
|
|
||||||
"overview.html#NonCopyable">NonCopyable</a> requirement.
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef Mutex mutex_type;
|
|
||||||
|
|
||||||
explicit scoped_lock(Mutex& mx, bool initially_locked=true);
|
|
||||||
~scoped_lock();
|
|
||||||
|
|
||||||
void lock();
|
|
||||||
void unlock();
|
|
||||||
|
|
||||||
operator const void*() const;
|
|
||||||
bool locked() const;
|
|
||||||
};
|
|
||||||
} // namespace thread
|
|
||||||
} // namespace detail
|
|
||||||
} // namespace boost
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h2><a name="Members">Members</a></h2>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>Constructor</h3>
|
|
||||||
<pre>
|
|
||||||
explicit scoped_lock(Mutex& mx, bool initially_locked=true);
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Effects:</b> Associates mutex <code>mx</code> with <code>
|
|
||||||
*this</code>. If <code>initially_locked</code> is <code>true,</code>
|
|
||||||
calls <code>lock()</code>.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>Destructor</h3>
|
|
||||||
<pre>
|
|
||||||
~scoped_lock();
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Effects:</b> If <code>locked()</code>, calls <code>
|
|
||||||
unlock()</code>. Destroys <code>*this</code>.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>lock</h3>
|
|
||||||
<pre>
|
|
||||||
void lock();
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Effects:</b> If the associated mutex is already locked by another
|
|
||||||
lock in the current thread, the effects depend on the locking strategy
|
|
||||||
of the associated mutex, as shown in the following table:</p>
|
|
||||||
|
|
||||||
<table summary="lock effects" border="1" cellpadding="5">
|
|
||||||
<tr>
|
|
||||||
<td><i><a href="mutex_concept.html#LockingStrategies">Locking
|
|
||||||
Strategy</a><br>
|
|
||||||
of associated mutex</i></td>
|
|
||||||
|
|
||||||
<td><i>Effect if associated mutex is already locked by the
|
|
||||||
current thread</i></td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>Recursive</td>
|
|
||||||
|
|
||||||
<td>As if an additional lock were added to the mutex.</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>Checked</td>
|
|
||||||
|
|
||||||
<td>Throws <a href="lock_error.html">lock_error</a>.</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>Unchecked</td>
|
|
||||||
|
|
||||||
<td>Undefined behavior [<a href="bibliography.html#ISO">ISO</a>
|
|
||||||
1.3.12] (but typically, <a href="definitions.html#Deadlock">
|
|
||||||
deadlock</a>.)</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<p>If the associated mutex is already locked by some other thread,
|
|
||||||
places the current thread in the <a href="definitions.html#State">
|
|
||||||
Blocked</a> state until the associated mutex is unlocked, after which
|
|
||||||
the current thread is placed in the <a href="definitions.html#State">
|
|
||||||
Ready</a> state, eventually to be returned to the <a href=
|
|
||||||
"definitions.html#State">Running</a> state.</p>
|
|
||||||
|
|
||||||
<p><b>Postcondition:</b> locked()</p>
|
|
||||||
|
|
||||||
<p><b>Throws:</b> <a href="lock_error.html">lock_error</a> if <code>
|
|
||||||
locked()</code> or as indicated in <b>Effects</b>.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>unlock</h3>
|
|
||||||
<pre>
|
|
||||||
void unlock();
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Effects:</b> Unlocks the associated mutex.</p>
|
|
||||||
|
|
||||||
<p><b>Throws:</b> <a href="lock_error.html">lock_error</a> if <code>
|
|
||||||
!locked()</code>.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>const void* Conversion</h3>
|
|
||||||
<pre>
|
|
||||||
operator const void*() const;
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Returns:</b> If the associated mutex is currently locked, a value
|
|
||||||
convertible to <code>true</code>, else a value convertible to <code>
|
|
||||||
false</code>.</p>
|
|
||||||
|
|
||||||
<p><b>Rationale:</b> A <code>const void*</code> conversion is
|
|
||||||
considered safer than a conversion to <code>bool</code>.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>locked</h3>
|
|
||||||
<pre>
|
|
||||||
bool locked() const;
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Returns:</b> <code>this->operator const void*() !=
|
|
||||||
0</code>.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h2><a name="Example">Example</a> Usage</h2>
|
|
||||||
|
|
||||||
<p>See the example given in the documentation for the <a href=
|
|
||||||
"mutex.html">mutex</a> class.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p>Revised
|
|
||||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->05 November, 2001<!--webbot bot="Timestamp" endspan i-checksum="39359" --></p>
|
|
||||||
|
|
||||||
<p><i>© Copyright <a href="mailto:williamkempf@hotmail.com">
|
|
||||||
William E. Kempf</a> 2001 all rights reserved.</i></p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
@@ -1,267 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content=
|
|
||||||
"text/html; charset=iso-8859-1">
|
|
||||||
<meta name="keywords" content="threads, BTL, thread library, C++">
|
|
||||||
<link rel="stylesheet" type="text/css" href="styles.css">
|
|
||||||
|
|
||||||
<title>Boost.Threads, scoped_timed_lock</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body bgcolor="#FFFFFF" link="#0000FF" vlink="#800080">
|
|
||||||
<table summary="header" border="0" cellpadding="7" cellspacing="0"
|
|
||||||
width="100%">
|
|
||||||
<tr>
|
|
||||||
<td valign="top" width="300">
|
|
||||||
<h3><img src="../../../c++boost.gif" alt="C++ Boost" width=
|
|
||||||
"277" height="86"></h3>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td valign="top">
|
|
||||||
<h1 align="center">Boost.Threads</h1>
|
|
||||||
|
|
||||||
<h2 align="center">scoped_timed_lock</h2>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p><a href="#Introduction">Introduction</a><br>
|
|
||||||
<a href="#Header">Header</a><br>
|
|
||||||
<a href="#Synopsis">Synopsis</a><br>
|
|
||||||
<a href="#Members">Members</a><br>
|
|
||||||
<a href="#Example">Example</a></p>
|
|
||||||
|
|
||||||
<h2><a name="Introduction">Introduction</a></h2>
|
|
||||||
|
|
||||||
<p>This class template defines a generic lock type which meets the <a
|
|
||||||
href="lock_concept.html#ScopedTimedLock">ScopedTimedLock</a>
|
|
||||||
requirements. The <a href="mutex.html">timed_mutex</a> and <a href=
|
|
||||||
"recursive_mutex.html">recursive_timed_mutex</a> classes use this
|
|
||||||
template to define their <code>scoped_timed_lock</code> types.</p>
|
|
||||||
|
|
||||||
<p>Like all the <b>Boost.Threads</b> <a href="lock_concept.html">lock
|
|
||||||
models</a>, <code>scoped_timed_lock</code> objects are meant to be
|
|
||||||
short-lived. Objects of the class are not <a href=
|
|
||||||
"definitions.html#thread-safe">thread-safe</a>, and so should not be
|
|
||||||
shared between threads.</p>
|
|
||||||
|
|
||||||
<p>Class <code>scoped_timed_lock</code> follows the "resource
|
|
||||||
acquisition is initialization" idiom <a href=
|
|
||||||
"bibliography.html#Stroustrup-00">[Stroustrup 00 14.4.1]</a> and is a
|
|
||||||
realization of the "Scoped Locking Pattern" <a href=
|
|
||||||
"bibliography.html#Schmidt-00">[Schmidt-00]</a>. Thus the usage is to
|
|
||||||
let the constructor do the locking, and then let the destructor do the
|
|
||||||
unlocking automatically at the end of the enclosing scope. The lock()
|
|
||||||
and unlock() members are usually not explicitly called, but are
|
|
||||||
provided to allow for complex overlapping locks of multiple
|
|
||||||
mutexes.</p>
|
|
||||||
|
|
||||||
<p>The type used to instantiate the class must meet the <a href=
|
|
||||||
"mutex_concept.html#TimedMutex">TimedMutex</a> requirements.</p>
|
|
||||||
|
|
||||||
<p>Although this class is an implementation detail, it is publicly
|
|
||||||
documented here because of its importance.</p>
|
|
||||||
|
|
||||||
<h2><a name="Header">Header</a></h2>
|
|
||||||
<pre>
|
|
||||||
#include <a href=
|
|
||||||
"../../../boost/thread/detail/lock.hpp"><boost/thread/detail/lock.hpp></a>
|
|
||||||
<i>This header is usually not included directly by programmers
|
|
||||||
because it is supplied by <a href=
|
|
||||||
"../../../boost/thread/mutex.hpp"><boost/thread/mutex.hpp></a> or
|
|
||||||
<a href=
|
|
||||||
"../../../boost/thread/recursive_mutex.hpp"><boost/thread/recursive_mutex.hpp></a></i>
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h2><a name="Synopsis">Synopsis</a></h2>
|
|
||||||
<pre>
|
|
||||||
namespace boost { namespace detail { namespace thread {
|
|
||||||
template <typename TimedMutex>
|
|
||||||
class scoped_timed_lock : private <a href=
|
|
||||||
"../../utility/utility.htm#Class noncopyable">boost::noncopyable</a> // Exposition only.
|
|
||||||
// Class scoped_timed_lock meets the <a href=
|
|
||||||
"overview.html#NonCopyable">NonCopyable</a> requirement.
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef TimedMutex mutex_type;
|
|
||||||
|
|
||||||
scoped_timed_lock(TimedMutex& mx, const boost::xtime& xt);
|
|
||||||
scoped_timed_lock(TimedMutex& mx, bool initially_locked);
|
|
||||||
~scoped_timed_lock();
|
|
||||||
|
|
||||||
void lock();
|
|
||||||
bool timed_lock(const xtime& xt);
|
|
||||||
void unlock();
|
|
||||||
|
|
||||||
operator const void*() const;
|
|
||||||
};
|
|
||||||
} // namespace thread
|
|
||||||
} // namesapce detail
|
|
||||||
} // namespace boost
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h2><a name="Members">Members</a></h2>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>Constructor</h3>
|
|
||||||
<pre>
|
|
||||||
scoped_timed_lock(TimedMutex& mx, const <a href=
|
|
||||||
"xtime.html">xtime</a>& xt);
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Effects:</b> Associates mutex <code>mx</code> with <code>
|
|
||||||
*this</code>. Calls <code>timed_lock</code>( <code>xt</code>)</p>
|
|
||||||
<hr>
|
|
||||||
<pre>
|
|
||||||
scoped_timed_lock(TimedMutex& mx, bool initially_locked);
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Effects:</b> Associates mutex <code>mx</code> with <code>
|
|
||||||
*this</code>. If <code>initially_locked</code> is <code>true</code>,
|
|
||||||
calls <code>lock()</code>.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>Destructor</h3>
|
|
||||||
<pre>
|
|
||||||
~scoped_timed_lock();
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Effects:</b> If <code>locked()</code>, calls <code>
|
|
||||||
unlock()</code>. Destroys <code>*this</code>.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>lock</h3>
|
|
||||||
<pre>
|
|
||||||
void lock();
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Effects:</b> If the associated mutex is already locked by another
|
|
||||||
lock in the current thread, the effects depend on the locking strategy
|
|
||||||
of the associated mutex, as shown in the following table:</p>
|
|
||||||
|
|
||||||
<table summary="lock effects" border="1" cellpadding="5">
|
|
||||||
<tr>
|
|
||||||
<td><i><a href="mutex_concept.html#LockingStrategies">Locking
|
|
||||||
Strategy</a><br>
|
|
||||||
of associated mutex</i></td>
|
|
||||||
|
|
||||||
<td><i>Effect if associated mutex is already locked by the
|
|
||||||
current thread</i></td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>Recursive</td>
|
|
||||||
|
|
||||||
<td>As if an additional lock were added to the mutex.</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>Checked</td>
|
|
||||||
|
|
||||||
<td>Throws <a href="lock_error.html">lock_error</a>.</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>Unchecked</td>
|
|
||||||
|
|
||||||
<td>Undefined behavior [<a href="bibliography.html#ISO">ISO</a>
|
|
||||||
1.3.12] (but typically, <a href="definitions.html#Deadlock">
|
|
||||||
deadlock</a>.)</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<p>If the associated mutex is already locked by some other thread,
|
|
||||||
places the current thread in the <a href="definitions.html#State">
|
|
||||||
Blocked</a> state until the associated mutex is unlocked, after which
|
|
||||||
the current thread is placed in the <a href="definitions.html#State">
|
|
||||||
Ready</a> state, eventually to be returned to the <a href=
|
|
||||||
"definitions.html#State">Running</a> state. Places the associated mutex
|
|
||||||
in the locked state.</p>
|
|
||||||
|
|
||||||
<p><b>Throws:</b> <a href="lock_error.html">lock_error</a> if <code>
|
|
||||||
locked()</code> or as indicated in <b>Effects</b>.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>timed_lock</h3>
|
|
||||||
<pre>
|
|
||||||
bool timed_lock(const <a href="xtime.html">xtime</a>& xt);
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Effects:</b> Same as <code>lock()</code>, except that if xt is
|
|
||||||
reached, places the current thread in the <a href=
|
|
||||||
"definitions.html#State">Ready</a> state without further ado.</p>
|
|
||||||
|
|
||||||
<p><b>Returns:</b> <code>locked()</code>.</p>
|
|
||||||
|
|
||||||
<p><b>Throws:</b> <a href="lock_error.html">lock_error</a> if <code>
|
|
||||||
locked()</code> or as indicated in <b>Effects</b>.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>unlock</h3>
|
|
||||||
<pre>
|
|
||||||
void unlock();
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Effects:</b> Unlocks the associated mutex.</p>
|
|
||||||
|
|
||||||
<p><b>Throws:</b> <a href="lock_error.html">lock_error</a> if <code>
|
|
||||||
!locked()</code>.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>const void* Conversion</h3>
|
|
||||||
<pre>
|
|
||||||
operator const void*() const;
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Returns:</b> If the associated mutex is currently locked, a value
|
|
||||||
convertible to <code>true</code>, else a value convertible to <code>
|
|
||||||
false</code>.</p>
|
|
||||||
|
|
||||||
<p><b>Rationale:</b> A <code>const void*</code> conversion is
|
|
||||||
considered safer than a conversion to <code>bool</code>.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>locked</h3>
|
|
||||||
<pre>
|
|
||||||
bool locked() const;
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Returns:</b> <code>this->operator const void*() !=
|
|
||||||
0</code>.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h2><a name="Example">Example</a> Usage</h2>
|
|
||||||
<pre>
|
|
||||||
#include <boost/thread/mutex.hpp>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
int main(int, char*[])
|
|
||||||
{
|
|
||||||
boost::timed_mutex mutex;
|
|
||||||
boost::xtime xt;
|
|
||||||
boost::get_xtime(&xt, boost::TIME_UTC);
|
|
||||||
xt.sec += 1;
|
|
||||||
boost::mutex::scoped_timed_lock scope_timed_lock(mutex, xt);
|
|
||||||
if (scope_timed_lock.locked())
|
|
||||||
std::cout << "locked" << std::endl;
|
|
||||||
else
|
|
||||||
std::cout << "unlocked" << std::endl;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>The output is:</p>
|
|
||||||
<pre>
|
|
||||||
locked
|
|
||||||
</pre>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p>Revised
|
|
||||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%B %d, %Y" startspan -->November 05, 2001<!--webbot bot="Timestamp" endspan i-checksum="39585" --></p>
|
|
||||||
|
|
||||||
<p><i>© Copyright <a href="mailto:williamkempf@hotmail.com">
|
|
||||||
William E. Kempf</a> 2001 all rights reserved.</i></p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
@@ -1,305 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content=
|
|
||||||
"text/html; charset=iso-8859-1">
|
|
||||||
<meta name="keywords" content="threads, BTL, thread library, C++">
|
|
||||||
<link rel="stylesheet" type="text/css" href="styles.css">
|
|
||||||
|
|
||||||
<title>Boost.Threads, scoped_try_lock</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body bgcolor="#FFFFFF" link="#0000FF" vlink="#800080">
|
|
||||||
<table summary="header" border="0" cellpadding="7" cellspacing="0"
|
|
||||||
width="100%">
|
|
||||||
<tr>
|
|
||||||
<td valign="top" width="300">
|
|
||||||
<h3><img src="../../../c++boost.gif" alt="C++ Boost" width=
|
|
||||||
"277" height="86"></h3>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td valign="top">
|
|
||||||
<h1 align="center">Boost.Threads</h1>
|
|
||||||
|
|
||||||
<h2 align="center">scoped_try_lock</h2>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p><a href="#Introduction">Introduction</a><br>
|
|
||||||
<a href="#Header">Header</a><br>
|
|
||||||
<a href="#Synopsis">Synopsis</a><br>
|
|
||||||
<a href="#Members">Members</a><br>
|
|
||||||
<a href="#Example">Example</a></p>
|
|
||||||
|
|
||||||
<h2><a name="Introduction">Introduction</a></h2>
|
|
||||||
|
|
||||||
<p>This class template defines a generic lock type which meets the <a
|
|
||||||
href="lock_concept.html#ScopedTryLock">ScopedTryLock</a> requirements.
|
|
||||||
The <a href="mutex.html">try_mutex</a>, <a href="mutex.html">
|
|
||||||
timed_mutex</a>, <a href="recursive_mutex.html">recursive_try_mutex</a>
|
|
||||||
and <a href="recursive_mutex.html">recursive_timed_mutex</a> classes
|
|
||||||
use this template to define their <code>scoped_try_lock</code>
|
|
||||||
types.</p>
|
|
||||||
|
|
||||||
<p>Like all the <b>Boost.Threads</b> <a href="lock_concept.html">lock
|
|
||||||
models</a>, <code>scoped_try_lock</code> objects are meant to be
|
|
||||||
short-lived. Objects of the class are not <a href=
|
|
||||||
"definitions.html#thread-safe">thread-safe</a>, and so should not be
|
|
||||||
shared between threads.</p>
|
|
||||||
|
|
||||||
<p>Class <code>scoped_try_lock</code> follows the "resource
|
|
||||||
acquisition is initialization" idiom <a href=
|
|
||||||
"bibliography.html#Stroustrup-00">[Stroustrup 00 14.4.1]</a> and is a
|
|
||||||
realization of the "Scoped Locking Pattern" <a href=
|
|
||||||
"bibliography.html#Schmidt-00">[Schmidt-00]</a>. Thus the usage is to
|
|
||||||
let the constructor do the locking, and then let the destructor do the
|
|
||||||
unlocking automatically at the end of the enclosing scope. The lock()
|
|
||||||
and unlock() members are usually not explicitly called, but are
|
|
||||||
provided to allow for complex overlapping locks of multiple
|
|
||||||
mutexes.</p>
|
|
||||||
|
|
||||||
<p>Although this class is an implementation detail, it is publicly
|
|
||||||
documented here because of its importance.</p>
|
|
||||||
|
|
||||||
<p>The type used to instantiate the class must meet the <a href=
|
|
||||||
"mutex_concept.html#TryMutex">TryMutex</a> requirements.</p>
|
|
||||||
|
|
||||||
<h2><a name="Header">Header</a></h2>
|
|
||||||
<pre>
|
|
||||||
#include <a href=
|
|
||||||
"../../../boost/thread/detail/lock.hpp"><boost/thread/detail/lock.hpp></a>
|
|
||||||
<i>This header is usually not included directly by programmers
|
|
||||||
because it is supplied by <a href=
|
|
||||||
"../../../boost/thread/mutex.hpp"><boost/thread/mutex.hpp></a> or
|
|
||||||
<a href=
|
|
||||||
"../../../boost/thread/recursive_mutex.hpp"><boost/thread/recursive_mutex.hpp></a></i>
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h2><a name="Synopsis">Synopsis</a></h2>
|
|
||||||
<pre>
|
|
||||||
namespace boost { namespace detail { namespace thread {
|
|
||||||
template <typename TryMutex>
|
|
||||||
class scoped_try_lock : private <a href=
|
|
||||||
"../../utility/utility.htm#Class noncopyable">boost::noncopyable</a> // Exposition only.
|
|
||||||
// Class scoped_try_lock meets the <a href=
|
|
||||||
"overview.html#NonCopyable">NonCopyable</a> requirement.
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef TryMutex mutex_type;
|
|
||||||
|
|
||||||
explicit scoped_try_lock(TryMutex& mx);
|
|
||||||
scoped_try_lock(TryMutex& mx, bool initially_locked);
|
|
||||||
~scoped_try_lock();
|
|
||||||
|
|
||||||
void lock();
|
|
||||||
bool try_lock();
|
|
||||||
void unlock();
|
|
||||||
|
|
||||||
operator const void*() const;
|
|
||||||
};
|
|
||||||
} // namespace thread
|
|
||||||
} // namespace detail
|
|
||||||
} // namespace boost
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h2><a name="Members">Members</a></h2>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>Constructors</h3>
|
|
||||||
<pre>
|
|
||||||
explicit scoped_try_lock(TryMutex& mx);
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Effects:</b> Associates mutex <code>mx</code> with <code>
|
|
||||||
*this</code>. Calls <code>try_lock()</code>.</p>
|
|
||||||
<hr>
|
|
||||||
<pre>
|
|
||||||
scoped_try_lock(TryMutex& mx, bool initially_locked);
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Effects:</b> Associates mutex <code>mx</code> with <code>
|
|
||||||
*this</code>. If <code>initially_locked</code> is <code>true,</code>
|
|
||||||
calls <code>lock()</code>.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>Destructor</h3>
|
|
||||||
<pre>
|
|
||||||
~scoped_try_lock();
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Effects:</b> If <code>locked()</code>, calls <code>
|
|
||||||
unlock()</code>. Destroys <code>*this</code>.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>lock</h3>
|
|
||||||
<pre>
|
|
||||||
void lock();
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Effects:</b> If the associated mutex is already locked by another
|
|
||||||
lock in the current thread, the effects depend on the locking strategy
|
|
||||||
of the associated mutex, as shown in the following table:</p>
|
|
||||||
|
|
||||||
<table summary="lock effects" border="1" cellpadding="5" height="147">
|
|
||||||
<tr>
|
|
||||||
<td height="34"><i><a href=
|
|
||||||
"mutex_concept.html#LockingStrategies">Locking Strategy</a><br>
|
|
||||||
of associated mutex</i></td>
|
|
||||||
|
|
||||||
<td height="34"><i>Effect if associated mutex is already locked
|
|
||||||
by the current thread</i></td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td height="19">Recursive</td>
|
|
||||||
|
|
||||||
<td height="19">As if an additional lock were added to the
|
|
||||||
mutex.</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td height="19">Checked</td>
|
|
||||||
|
|
||||||
<td height="19">Throws <a href="lock_error.html">
|
|
||||||
lock_error</a>.</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td height="19">Unchecked</td>
|
|
||||||
|
|
||||||
<td height="19">Undefined behavior [<a href=
|
|
||||||
"bibliography.html#ISO">ISO</a> 1.3.12] (but typically, <a
|
|
||||||
href="definitions.html#Deadlock">deadlock</a>.)</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<p>If the associated mutex is already locked by some other thread,
|
|
||||||
places the current thread in the <a href="definitions.html#State">
|
|
||||||
Blocked</a> state until the associated mutex is unlocked, after which
|
|
||||||
the current thread is placed in the <a href="definitions.html#State">
|
|
||||||
Ready</a> state, eventually to be returned to the <a href=
|
|
||||||
"definitions.html#State">Running</a> state. Places the associated mutex
|
|
||||||
in the locked state.</p>
|
|
||||||
|
|
||||||
<p><b>Throws:</b> <a href="lock_error.html">lock_error</a> if <code>
|
|
||||||
locked()</code> or as indicated in <b>Effects</b>.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>try_lock</h3>
|
|
||||||
<pre>
|
|
||||||
bool try_lock();
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Effects:</b> If the associated mutex is already locked by another
|
|
||||||
lock in the current thread, the effects depend on the locking strategy
|
|
||||||
of the associated mutex, as shown in the following table:</p>
|
|
||||||
|
|
||||||
<table summary="try_lock effects" border="1" cellpadding="5" height=
|
|
||||||
"147">
|
|
||||||
<tr>
|
|
||||||
<td height="34"><i><a href=
|
|
||||||
"mutex_concept.html#LockingStrategies">Locking Strategy</a><br>
|
|
||||||
of associated mutex</i></td>
|
|
||||||
|
|
||||||
<td height="34"><i>Effect if associated mutex is already locked
|
|
||||||
by the current thread</i></td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td height="19">Recursive</td>
|
|
||||||
|
|
||||||
<td height="19">As if an additional lock were added to the
|
|
||||||
mutex.</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td height="19">Checked</td>
|
|
||||||
|
|
||||||
<td height="19">Throws <a href="lock_error.html">
|
|
||||||
lock_error</a>.</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td height="19">Unspecified</td>
|
|
||||||
|
|
||||||
<td height="19">Undefined behavior [<a href=
|
|
||||||
"bibliography.html#ISO">ISO</a> 1.3.12] (but typically, <a
|
|
||||||
href="definitions.html#Deadlock">deadlock</a>.)</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<p>If the associated mutex is not already locked by some other thread,
|
|
||||||
locks the associated mutex and returns true, else returns false.</p>
|
|
||||||
|
|
||||||
<p><b>Returns:</b> See effects.</p>
|
|
||||||
|
|
||||||
<p><b>Throws:</b> <a href="lock_error.html">lock_error</a> if <code>
|
|
||||||
locked()</code> or as indicated in <b>Effects</b>.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>unlock</h3>
|
|
||||||
<pre>
|
|
||||||
void unlock();
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Effects:</b> Unlocks the associated mutex.</p>
|
|
||||||
|
|
||||||
<p><b>Throws:</b> <a href="lock_error.html">lock_error</a> if <code>
|
|
||||||
!locked()</code>.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>const void* Conversion</h3>
|
|
||||||
<pre>
|
|
||||||
operator const void*() const;
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Returns:</b> If the associated mutex is currently locked, a value
|
|
||||||
convertible to <code>true</code>, else a value convertible to <code>
|
|
||||||
false</code>.</p>
|
|
||||||
|
|
||||||
<p><b>Rationale:</b> A <code>const void*</code> conversion is
|
|
||||||
considered safer than a conversion to <code>bool</code>.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>locked</h3>
|
|
||||||
<pre>
|
|
||||||
bool locked() const;
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Returns:</b> <code>this->operator const void*() !=
|
|
||||||
0</code>.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h2><a name="Example">Example</a> Usage</h2>
|
|
||||||
<pre>
|
|
||||||
#include <a href=
|
|
||||||
"../../../boost/thread/mutex.hpp"><boost/thread/mutex.hpp></a>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
int main(int, char*[])
|
|
||||||
{
|
|
||||||
boost::mutex mutex;
|
|
||||||
boost::mutex::try_lock lock(mutex);
|
|
||||||
if (lock)
|
|
||||||
std::cout << "locked" << std::endl;
|
|
||||||
else
|
|
||||||
std::cout << "unlocked" << std::endl;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>The output is:</p>
|
|
||||||
<pre>
|
|
||||||
locked
|
|
||||||
</pre>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p>Revised
|
|
||||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->05 November, 2001<!--webbot bot="Timestamp" endspan i-checksum="39359" --></p>
|
|
||||||
|
|
||||||
<p><i>© Copyright <a href="mailto:williamkempf@hotmail.com">
|
|
||||||
William E. Kempf</a> 2001 all rights reserved.</i></p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
35
doc/shared_mutex_ref.qbk
Normal file
35
doc/shared_mutex_ref.qbk
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
[section:shared_mutex Class `shared_mutex`]
|
||||||
|
|
||||||
|
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]
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
PRE
|
|
||||||
{
|
|
||||||
BACKGROUND-COLOR: lightcyan
|
|
||||||
}
|
|
||||||
261
doc/thread.html
261
doc/thread.html
@@ -1,261 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content=
|
|
||||||
"text/html; charset=iso-8859-1">
|
|
||||||
<meta name="keywords" content=
|
|
||||||
"threads, Boost.Threads, thread library, C++">
|
|
||||||
<link rel="stylesheet" type="text/css" href="styles.css">
|
|
||||||
|
|
||||||
<title>Boost.Threads, thread</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body bgcolor="#ffffff" link="#0000ff" vlink="#800080">
|
|
||||||
<table summary="header" border="0" cellpadding="7" cellspacing="0"
|
|
||||||
width="100%">
|
|
||||||
<tr>
|
|
||||||
<td valign="top" width="300">
|
|
||||||
<h3><img height="86" alt="C++ Boost" src=
|
|
||||||
"../../../c++boost.gif" width="277"></h3>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td valign="top">
|
|
||||||
<h1 align="center">Boost.Threads</h1>
|
|
||||||
|
|
||||||
<h2 align="center">Class thread</h2>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p><a href="#Introduction">Introduction</a><br>
|
|
||||||
<a href="#Header">Header</a><br>
|
|
||||||
<a href="#Synopsis">Synopsis</a><br>
|
|
||||||
<a href="#Members">Members</a><br>
|
|
||||||
<a href="#Example">Example</a></p>
|
|
||||||
|
|
||||||
<h2><a name="Introduction">Introduction</a></h2>
|
|
||||||
|
|
||||||
<p>The <code>thread</code> class represents threads of execution, and
|
|
||||||
provides the functionality to create and manage threads within the <b>
|
|
||||||
Boost.Threads</b> library. See <a href="definitions.html">
|
|
||||||
Definitions</a> for a precise description of "thread of
|
|
||||||
execution", and for definitions of threading related terms and of
|
|
||||||
thread states such as "blocked".</p>
|
|
||||||
|
|
||||||
<p>A thread of execution has an initial function. For the program's
|
|
||||||
initial thread, the initial function is <code>main()</code>. For other
|
|
||||||
threads, the initial function is <code>operator()</code> of the
|
|
||||||
function object passed to the class <code>thread</code>
|
|
||||||
constructor.</p>
|
|
||||||
|
|
||||||
<p>A thread of execution is said to be "finished" or
|
|
||||||
"finished execution" when its initial function returns or is
|
|
||||||
terminated. This includes completion of all thread cleanup handlers,
|
|
||||||
and completion of the normal C++ function return behaviors, such as
|
|
||||||
destruction of automatic storage (stack) objects and releasing any
|
|
||||||
associated implementation resources.</p>
|
|
||||||
|
|
||||||
<p>A thread object has an associated state which is either
|
|
||||||
"joinable" or "non-joinable".</p>
|
|
||||||
|
|
||||||
<p>Except as described below, the policy used by an implementation of
|
|
||||||
<b>Boost.Threads</b> to schedule transitions between thread states is
|
|
||||||
unspecified.</p>
|
|
||||||
|
|
||||||
<p><b>Note:</b> Just as the lifetime of a file may be different from
|
|
||||||
the lifetime of an iostream object which represents the file, the
|
|
||||||
lifetime of a thread of execution may be different from the <code>
|
|
||||||
thread</code> object which represents the thread of execution. In
|
|
||||||
particular, after a call to <code>join()</code>, the thread of
|
|
||||||
execution will no longer exist even though the <code>thread</code>
|
|
||||||
object continues to exist until the end of its normal lifetime. The
|
|
||||||
converse is also possible; if a <code>thread</code> object is destroyed
|
|
||||||
without <code>join()</code> having first been called, the thread of
|
|
||||||
execution continues until its initial function completes.</p>
|
|
||||||
|
|
||||||
<h2><a name="Header">Header</a></h2>
|
|
||||||
<pre>
|
|
||||||
#include <a href=
|
|
||||||
"../../../boost/thread/thread.hpp"><boost/thread/thread.hpp></a>
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h2><a name="Synopsis">Synopsis</a></h2>
|
|
||||||
<pre>
|
|
||||||
namespace boost {
|
|
||||||
|
|
||||||
class thread : <a href=
|
|
||||||
"../../utility/utility.htm#noncopyable">boost::noncopyable</a> // Exposition only.
|
|
||||||
// Class thread meets the <a href=
|
|
||||||
"overview.html#NonCopyable">NonCopyable</a> requirement.
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
thread();
|
|
||||||
explicit thread(const boost::function0<void>& threadfunc);
|
|
||||||
~thread();
|
|
||||||
|
|
||||||
bool operator==(const thread& rhs) const;
|
|
||||||
bool operator!=(const thread& rhs) const;
|
|
||||||
|
|
||||||
void join();
|
|
||||||
|
|
||||||
static void sleep(const xtime& xt);
|
|
||||||
static void yield();
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace boost
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h2><a name="Members">Members</a></h2>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>Constructors</h3>
|
|
||||||
<pre>
|
|
||||||
thread();
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Effects:</b> Constructs a <code>thread</code> object representing
|
|
||||||
the current thread of execution.</p>
|
|
||||||
|
|
||||||
<p><b>Postcondition:</b> <code>*this</code> is non-joinable.</p>
|
|
||||||
|
|
||||||
<p><b>Danger:</b> <code>*this</code> is valid only within the current
|
|
||||||
thread.</p>
|
|
||||||
<pre>
|
|
||||||
thread(const <a href=
|
|
||||||
"../../function/index.html">boost::function0</a><void>& threadfunc);
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Effects:</b> Starts a new thread of execution and constructs a
|
|
||||||
<code>thread</code> object representing it. Copies <code>
|
|
||||||
threadfunc</code> (which in turn copies the function object wrapped by
|
|
||||||
<code>threadfunc</code>) to an internal location which persists for the
|
|
||||||
lifetime of the new thread of execution. Calls <code>operator()</code>
|
|
||||||
on the copy of the <code>threadfunc</code> function object in the new
|
|
||||||
thread of execution.</p>
|
|
||||||
|
|
||||||
<p><b>Postcondition:</b> <code>*this</code> is joinable.</p>
|
|
||||||
|
|
||||||
<p><b>Throws:</b> <code>boost::thread_resource_error</code> if a new
|
|
||||||
thread of execution cannot be started.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>Destructor</h3>
|
|
||||||
<pre>
|
|
||||||
~thread();
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Effects:</b> Destroys <code>*this</code>. The actual thread of
|
|
||||||
execution may continue to execute after the <code>thread</code> object
|
|
||||||
has been destroyed.</p>
|
|
||||||
|
|
||||||
<p><b>Notes:</b> If <code>*this</code> is joinable the actual thread of
|
|
||||||
execution becomes "detached". Any resources used by the
|
|
||||||
thread will be reclaimed when the thread of execution completes. To
|
|
||||||
ensure such a thread of execution runs to completion before the <code>
|
|
||||||
thread</code> object is destroyed, call <code>join()</code>.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>Comparison Operators</h3>
|
|
||||||
<pre>
|
|
||||||
bool operator==(const thread& rhs);
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Requires:</b> The thread is non-terminated or <code>*this</code>
|
|
||||||
is joinable.</p>
|
|
||||||
|
|
||||||
<p><b>Returns:</b> <code>true</code> if <code>*this</code> and <code>
|
|
||||||
rhs</code> represent the same thread of execution.</p>
|
|
||||||
<pre>
|
|
||||||
bool operator!=(const thread& rhs);
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Returns:</b> <code>!(*this==rhs)</code>.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>join</h3>
|
|
||||||
<pre>
|
|
||||||
void join();
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Requires:</b> <code>*this</code> is joinable.</p>
|
|
||||||
|
|
||||||
<p><b>Effects:</b> The current thread of execution blocks until the
|
|
||||||
initial function of the thread of execution represented by <code>
|
|
||||||
*this</code> finishes and all resources are reclaimed.</p>
|
|
||||||
|
|
||||||
<p><b>Postcondition:</b> <code>*this</code> is non-joinable.</p>
|
|
||||||
|
|
||||||
<p><b>Note:</b> If <code>*this == thread()</code> the result is
|
|
||||||
implementation defined. If the implementation doesn't detect this
|
|
||||||
the result will be <a href="definitions.html#Deadlock">
|
|
||||||
deadlock</a>.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>sleep</h3>
|
|
||||||
<pre>
|
|
||||||
static void sleep(const <a href="xtime.html">xtime</a>& xt);
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Effects:</b> The current thread of execution blocks until <code>
|
|
||||||
xt</code> is reached.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>yield</h3>
|
|
||||||
<pre>
|
|
||||||
static void yield();
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Effects:</b> The current thread of execution is placed in the
|
|
||||||
"ready" state.</p>
|
|
||||||
|
|
||||||
<p><b>Notes:</b> Allow the current thread to give up the rest of its
|
|
||||||
time slice (or other scheduling quota) to another thread. Particularly
|
|
||||||
useful in non-preemptive implementations.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h2><a name="Example">Example Usage</a></h2>
|
|
||||||
<pre>
|
|
||||||
#include <boost/thread/thread.hpp>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
struct thread_alarm
|
|
||||||
{
|
|
||||||
thread_alarm(int secs) : m_secs(secs) { }
|
|
||||||
void operator()()
|
|
||||||
{
|
|
||||||
boost::xtime xt;
|
|
||||||
boost::xtime_get(&xt, boost::TIME_UTC);
|
|
||||||
xt.sec += m_secs;
|
|
||||||
|
|
||||||
boost::thread::sleep(xt);
|
|
||||||
|
|
||||||
std::cout << "alarm sounded..." << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
int m_secs;
|
|
||||||
};
|
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
|
||||||
{
|
|
||||||
int secs = 5;
|
|
||||||
std::cout << "setting alarm for 5 seconds..." << std::endl;
|
|
||||||
boost::thread thrd(thread_alarm(secs));
|
|
||||||
thrd.join();
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>The output is:</p>
|
|
||||||
<pre>
|
|
||||||
setting alarm for 5 seconds...
|
|
||||||
alarm sounded...
|
|
||||||
</pre>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p>Revised
|
|
||||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->05 November, 2001<!--webbot bot="Timestamp" endspan i-checksum="39359" --></p>
|
|
||||||
|
|
||||||
<p><i>© Copyright <a href="mailto:williamkempf@hotmail.com">
|
|
||||||
William E. Kempf</a> 2001 all rights reserved.</i></p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
152
doc/thread.qbk
Normal file
152
doc/thread.qbk
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
[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 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`]]
|
||||||
|
|
||||||
|
[def __lock_guard__ [link thread.synchronization.locks.lock_guard `boost::lock_guard`]]
|
||||||
|
[def __unique_lock__ [link thread.synchronization.locks.unique_lock `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]
|
||||||
@@ -1,182 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content=
|
|
||||||
"text/html; charset=iso-8859-1">
|
|
||||||
<meta name="keywords" content="threads, BTL, thread library, C++">
|
|
||||||
<link rel="stylesheet" type="text/css" href="styles.css">
|
|
||||||
|
|
||||||
<title>Boost.Threads, thread_group</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body bgcolor="#FFFFFF" link="#0000FF" vlink="#800080">
|
|
||||||
<table summary="header" border="0" cellpadding="7" cellspacing="0"
|
|
||||||
width="100%">
|
|
||||||
<tr>
|
|
||||||
<td valign="top" width="300">
|
|
||||||
<h3><img src="../../../c++boost.gif" alt="C++ Boost" width=
|
|
||||||
"277" height="86"></h3>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td valign="top">
|
|
||||||
<h1 align="center">Boost.Threads</h1>
|
|
||||||
|
|
||||||
<h2 align="center">thread_group</h2>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p><a href="#Introduction">Introduction</a><br>
|
|
||||||
<a href="#Header">Header</a><br>
|
|
||||||
<a href="#Synopsis">Synopsis</a><br>
|
|
||||||
<a href="#Members">Members</a><br>
|
|
||||||
<a href="#Example">Example</a></p>
|
|
||||||
|
|
||||||
<h2><a name="Introduction">Introduction</a></h2>
|
|
||||||
|
|
||||||
<p>The <tt>thread_group</tt> class provides a container for easy
|
|
||||||
grouping of threads to simplify several common thread creation and
|
|
||||||
management idioms.</p>
|
|
||||||
|
|
||||||
<p>All <tt>thread_group</tt> member functions are <a href=
|
|
||||||
"definitions.html#thread-safe">thread-safe</a>, except destruction.</p>
|
|
||||||
|
|
||||||
<h2><a name="Header">Header</a></h2>
|
|
||||||
<pre>
|
|
||||||
#include <a href=
|
|
||||||
"../../../boost/thread/thread.hpp"><boost/thread/thread.hpp></a>
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h2><a name="Synopsis">Synopsis</a></h2>
|
|
||||||
<pre>
|
|
||||||
namespace boost
|
|
||||||
{
|
|
||||||
class thread_group : <a href=
|
|
||||||
"../../utility/utility.htm#noncopyable">boost::noncopyable</a>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
thread_group();
|
|
||||||
~thread_group();
|
|
||||||
|
|
||||||
thread* create_thread(const boost::function0<void>& threadfunc);
|
|
||||||
void add_thread(thread* thrd);
|
|
||||||
void remove_thread(thread* thrd);
|
|
||||||
void join_all();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h2><a name="Members">Members</a></h2>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>Constructor</h3>
|
|
||||||
<pre>
|
|
||||||
thread_group();
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Effects:</b> Constructs an empty <tt>thread_group</tt>
|
|
||||||
container.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>Destructor</h3>
|
|
||||||
<pre>
|
|
||||||
~thread_group();
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Effects:</b> Destroys each contained thread object. Destroys
|
|
||||||
<code>*this</code>.</p>
|
|
||||||
|
|
||||||
<p><b>Notes:</b> Behavior is undefined if another thread references
|
|
||||||
*this during the execution of the destructor.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>create_thread</h3>
|
|
||||||
<pre>
|
|
||||||
thread* create_thread(const boost::function0<void>& threadfunc);
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Effects:</b> Creates a new <tt>thread</tt> object that executes
|
|
||||||
<tt>threadfunc</tt> and adds it to the <tt>thread_group</tt> container
|
|
||||||
object's list of managed <tt>thread</tt> objects.</p>
|
|
||||||
|
|
||||||
<p><b>Returns:</b> Pointer to the newly created thread.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>add_thread</h3>
|
|
||||||
<pre>
|
|
||||||
void add_thread(thread* thrd);
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Effects:</b> Adds <tt>thrd</tt> to the <tt>thread_group</tt>
|
|
||||||
object's list of managed <tt>thread</tt> objects. The <tt>thrd</tt>
|
|
||||||
object must have been allocated via operator new and will be deleted
|
|
||||||
when the group is destroyed.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>remove_thread</h3>
|
|
||||||
<pre>
|
|
||||||
void remove_thread(thread* thrd);
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Effects:</b> Removes <code>*this</code>'s list of managed
|
|
||||||
<tt>thread</tt> objects.</p>
|
|
||||||
|
|
||||||
<p><b>Throws:</b> ? if <tt>thrd</tt> is not it <code>*this</code>'s
|
|
||||||
list of managed <tt>thread</tt> objects.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>join_all</h3>
|
|
||||||
<pre>
|
|
||||||
void join_all();
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Effects:</b> Calls <code>join()</code> on each of the managed
|
|
||||||
<tt>thread</tt> objects.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h2><a name="Example">Example</a> Usage</h2>
|
|
||||||
<pre>
|
|
||||||
#include <boost/thread/thread.hpp>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
int count = 0;
|
|
||||||
boost::mutex mutex;
|
|
||||||
|
|
||||||
void increment_count()
|
|
||||||
{
|
|
||||||
boost::mutex::lock lock(mutex);
|
|
||||||
std::cout << "count = " << ++count << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
|
||||||
{
|
|
||||||
boost::thread_group threads;
|
|
||||||
for (int i = 0; i < 10; ++i)
|
|
||||||
threads.create_thread(&increment_count);
|
|
||||||
threads.join_all();
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>The output is:</p>
|
|
||||||
<pre>
|
|
||||||
count = 1
|
|
||||||
count = 2
|
|
||||||
count = 3
|
|
||||||
count = 4
|
|
||||||
count = 5
|
|
||||||
count = 6
|
|
||||||
count = 7
|
|
||||||
count = 8
|
|
||||||
count = 9
|
|
||||||
count = 10
|
|
||||||
</pre>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p>Revised
|
|
||||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->05 November, 2001<!--webbot bot="Timestamp" endspan i-checksum="39359" --></p>
|
|
||||||
|
|
||||||
<p><i>© Copyright <a href="mailto:williamkempf@hotmail.com">
|
|
||||||
William E. Kempf</a> 2001 all rights reserved.</i></p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
1000
doc/thread_ref.qbk
Normal file
1000
doc/thread_ref.qbk
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,78 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content=
|
|
||||||
"text/html; charset=iso-8859-1">
|
|
||||||
<meta name="keywords" content="threads, BTL, thread library, C++">
|
|
||||||
<link rel="stylesheet" type="text/css" href="styles.css">
|
|
||||||
|
|
||||||
<title>Boost.Threads, thread_resource_error</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body bgcolor="#FFFFFF" link="#0000FF" vlink="#800080">
|
|
||||||
<table summary="header" border="0" cellpadding="7" cellspacing="0" width="100%">
|
|
||||||
<tr>
|
|
||||||
<td valign="top" width="300">
|
|
||||||
<h3><img src="../../../c++boost.gif" alt="C++ Boost" width=
|
|
||||||
"277" height="86"></h3>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td valign="top">
|
|
||||||
<h1 align="center">Boost.Threads</h1>
|
|
||||||
|
|
||||||
<h2 align="center">thread_resource_error</h2>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p><a href="#Introduction">Introduction</a><br>
|
|
||||||
<a href="#Header">Header</a><br>
|
|
||||||
<a href="#Synopsis">Synopsis</a><br>
|
|
||||||
<a href="#Members">Members</a><br>
|
|
||||||
<a href="#Example">Example</a></p>
|
|
||||||
|
|
||||||
<h2><a name="Introduction">Introduction</a></h2>
|
|
||||||
|
|
||||||
<p>The <code>thread_resource_error</code> class defines an exception
|
|
||||||
type that is thrown by constructors in the <b>Boost.Threads</b> library
|
|
||||||
when thread related resources can not be acquired. This does not
|
|
||||||
include memory allocation failures which instead throw
|
|
||||||
std::bad_alloc.</p>
|
|
||||||
|
|
||||||
<h2><a name="Header">Header</a></h2>
|
|
||||||
<pre>
|
|
||||||
#include <a href=
|
|
||||||
"../../../boost/thread/thread.hpp"><boost/thread/exceptions.hpp></a>
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h2><a name="Synopsis">Synopsis</a></h2>
|
|
||||||
<pre>
|
|
||||||
namespace boost
|
|
||||||
{
|
|
||||||
class thread_resource_error : public std::runtime_error
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
thread_resource_error();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h2><a name="Members">Members</a></h2>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>Constructor</h3>
|
|
||||||
<pre>
|
|
||||||
thread_resource_error();
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>Constructs a <code>thread_resource_error</code> object.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p>Revised
|
|
||||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->05 November, 2001<!--webbot bot="Timestamp" endspan i-checksum="39359" --></p>
|
|
||||||
|
|
||||||
<p><i>© Copyright <a href="mailto:williamkempf@hotmail.com">
|
|
||||||
William E. Kempf</a> 2001 all rights reserved.</i></p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
@@ -1,223 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content=
|
|
||||||
"text/html; charset=iso-8859-1">
|
|
||||||
<meta name="keywords" content=
|
|
||||||
"threads, Boost.Threads, thread library, C++">
|
|
||||||
<link rel="stylesheet" type="text/css" href="styles.css">
|
|
||||||
|
|
||||||
<title>Boost.Threads, thread_specific_ptr</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body bgcolor="#FFFFFF" link="#0000FF" vlink="#800080">
|
|
||||||
<table summary="header" border="0" cellpadding="7" cellspacing="0"
|
|
||||||
width="100%">
|
|
||||||
<tr>
|
|
||||||
<td valign="top" width="300">
|
|
||||||
<h3><img src="../../../c++boost.gif" alt="C++ Boost" width=
|
|
||||||
"277" height="86"></h3>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td valign="top">
|
|
||||||
<h1 align="center">Boost.Threads</h1>
|
|
||||||
|
|
||||||
<h2 align="center">thread_specific_ptr</h2>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p><a href="#Introduction">Introduction</a><br>
|
|
||||||
<a href="#Header">Header</a><br>
|
|
||||||
<a href="#Synopsis">Synopsis</a><br>
|
|
||||||
<a href="#Members">Members</a><br>
|
|
||||||
<a href="#Example">Example</a></p>
|
|
||||||
|
|
||||||
<h2><a name="Introduction">Introduction</a></h2>
|
|
||||||
|
|
||||||
<p>The <code>thread_specific_ptr</code> class defines an interface for
|
|
||||||
using thread specific storage. Thread specific storage is data
|
|
||||||
associated with individual threads and is often used to make operations
|
|
||||||
<a href="definitions.html#Thread-safe">thread-safe</a> that rely on
|
|
||||||
global data.</p>
|
|
||||||
|
|
||||||
<p>Template <code>thread_specific_ptr</code> stores a pointer to an
|
|
||||||
object obtained via <code>new</code> on a thread-by-thread basis and
|
|
||||||
calls delete on the contained pointer when the thread terminates. Each
|
|
||||||
thread initially stores the null pointer in each <code>
|
|
||||||
thread_specific_ptr</code> instance.</p>
|
|
||||||
|
|
||||||
<p>The template <code>thread_specific_ptr</code> is useful in the
|
|
||||||
following cases:</p>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li>An interface was original written assuming a single thread of
|
|
||||||
control and is being ported to a multi-threaded environment.</li>
|
|
||||||
|
|
||||||
<li>Each thread of control invokes sequences of methods that share
|
|
||||||
data that must be logically accessed through a globally visible
|
|
||||||
access point, but are physically unique for each thread, instead of
|
|
||||||
being explicitly passed.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<h2><a name="Header">Header</a></h2>
|
|
||||||
<pre>
|
|
||||||
#include <a href=
|
|
||||||
"../../../boost/thread/tss.hpp"><boost/thread/tss.hpp></a>
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h2><a name="Synopsis">Synopsis</a></h2>
|
|
||||||
<pre>
|
|
||||||
namespace boost {
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
class thread_specific_ptr : private boost::noncopyable // Exposition only.
|
|
||||||
// Class thread_specific_ptr meets the <a href=
|
|
||||||
"overview.html#NonCopyable">NonCopyable</a> requirement.
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
thread_specific_ptr();
|
|
||||||
~thread_specific_ptr();
|
|
||||||
|
|
||||||
T* get() const;
|
|
||||||
T* operator->() const;
|
|
||||||
T& operator*() const;
|
|
||||||
T* release();
|
|
||||||
void reset(T* p=0);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace boost
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h2><a name="Members">Members</a></h2>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>Constructor</h3>
|
|
||||||
<pre>
|
|
||||||
thread_specific_ptr();
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Postconditions:</b> A thread specific storage has been reserved
|
|
||||||
for use by *this in all threads, with each thread initially storing a
|
|
||||||
null pointer.</p>
|
|
||||||
|
|
||||||
<p><b>Requires:</b> The expression <code>delete get()</code> is well
|
|
||||||
formed.</p>
|
|
||||||
|
|
||||||
<p><b>Throws:</b> <code>boost::thread_resource_error</code> if the
|
|
||||||
necessary resources can not be obtained.</p>
|
|
||||||
|
|
||||||
<p><b>Notes:</b> There is an implementation specific limit to the
|
|
||||||
number of thread specific storage objects that can be created, and this
|
|
||||||
limit may be small.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>Destructor</h3>
|
|
||||||
<pre>
|
|
||||||
~thread_specific_ptr();
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Notes:</b> Does not destroy any data that may be stored in any
|
|
||||||
thread's thread specific storage. For this reason you should not
|
|
||||||
destroy a <code>thread_specific_ptr</code> object until you are certain
|
|
||||||
there are no threads running that have made use of its thread specific
|
|
||||||
storage.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>get</h3>
|
|
||||||
<pre>
|
|
||||||
T* get() const;
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Returns:</b> The object stored in thread specific storage for the
|
|
||||||
current thread for *this.</p>
|
|
||||||
|
|
||||||
<p><b>Notes:</b> Each thread initially returns 0.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>Smart Pointer Operations</h3>
|
|
||||||
<pre>
|
|
||||||
T* operator->() const;
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Returns:</b> <code>get()</code></p>
|
|
||||||
<pre>
|
|
||||||
T& operator*() const;
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Returns:</b> <code>get()</code></p>
|
|
||||||
|
|
||||||
<p><b>Requires:</b> <code>get() != 0</code></p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>Release</h3>
|
|
||||||
<pre>
|
|
||||||
T* release();
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Returns:</b> <code>get()</code></p>
|
|
||||||
|
|
||||||
<p><b>Postcondition:</b> *this holds the null pointer for the current
|
|
||||||
thread.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>Reset</h3>
|
|
||||||
<pre>
|
|
||||||
void reset(T* p=0);
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Effects:</b> If <code>get()!= p</code> then <code>delete
|
|
||||||
get()</code>.</p>
|
|
||||||
|
|
||||||
<p><b>Postconditions:</b> <code>*this</code> holds the pointer <code>
|
|
||||||
p</code> for the current thread.</p>
|
|
||||||
|
|
||||||
<p><b>Notes:</b> The pointer will be deleted when the thread
|
|
||||||
terminates.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h2><a name="Example">Example Usage</a></h2>
|
|
||||||
<pre>
|
|
||||||
#include <a href=
|
|
||||||
"../../../boost/thread/thread.hpp"><boost/thread/thread.hpp></a>
|
|
||||||
#include <a href=
|
|
||||||
"../../../boost/thread/tss.hpp"><boost/thread/tss.hpp></a>
|
|
||||||
#include <cassert>
|
|
||||||
|
|
||||||
boost::thread_specific_ptr<int> value;
|
|
||||||
|
|
||||||
void increment()
|
|
||||||
{
|
|
||||||
int* p = value.get();
|
|
||||||
++*p;
|
|
||||||
}
|
|
||||||
|
|
||||||
void thread_proc()
|
|
||||||
{
|
|
||||||
value.reset(new int(0)); // initialize the thread's storage
|
|
||||||
for (int i=0; i<10; ++i)
|
|
||||||
{
|
|
||||||
increment();
|
|
||||||
int* p = value.get();
|
|
||||||
assert(*p == i+1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
|
||||||
{
|
|
||||||
boost::thread_group threads;
|
|
||||||
for (int i=0; i<5; ++i)
|
|
||||||
threads.create_thread(&thread_proc);
|
|
||||||
threads.join_all();
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p>Revised
|
|
||||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->05 November, 2001<!--webbot bot="Timestamp" endspan i-checksum="39359" --></p>
|
|
||||||
|
|
||||||
<p><i>© Copyright <a href="mailto:williamkempf@hotmail.com">
|
|
||||||
William E. Kempf</a> 2001 all rights reserved.</i></p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
64
doc/time.qbk
Normal file
64
doc/time.qbk
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
[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`]
|
||||||
|
|
||||||
|
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()`]
|
||||||
|
|
||||||
|
system_time get_system_time();
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[Returns:] [The current time.]]
|
||||||
|
|
||||||
|
[[Throws:] [Nothing.]]
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
|
||||||
|
[endsect]
|
||||||
175
doc/tss.qbk
Normal file
175
doc/tss.qbk
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
[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`]
|
||||||
|
|
||||||
|
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]
|
||||||
147
doc/xtime.html
147
doc/xtime.html
@@ -1,147 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content=
|
|
||||||
"text/html; charset=iso-8859-1">
|
|
||||||
<meta name="keywords" content=
|
|
||||||
"threads, Boost.Threads, thread library, C++">
|
|
||||||
<link rel="stylesheet" type="text/css" href="styles.css">
|
|
||||||
|
|
||||||
<title>Boost.Threads, xtime</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body bgcolor="#FFFFFF" link="#0000FF" vlink="#800080">
|
|
||||||
<table summary="header" border="0" cellpadding="7" cellspacing="0"
|
|
||||||
width="100%">
|
|
||||||
<tr>
|
|
||||||
<td valign="top" width="300">
|
|
||||||
<h3><img src="../../../c++boost.gif" alt="C++ Boost" width=
|
|
||||||
"277" height="86"></h3>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td valign="top">
|
|
||||||
<h1 align="center">Boost.Threads</h1>
|
|
||||||
|
|
||||||
<h2 align="center">xtime</h2>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p><a href="#Introduction">Introduction</a><br>
|
|
||||||
<a href="#Header">Header</a><br>
|
|
||||||
<a href="#Synopsis">Synopsis</a><br>
|
|
||||||
<a href="#Reference">Reference</a><br>
|
|
||||||
<a href="#Example">Example</a></p>
|
|
||||||
|
|
||||||
<h2><a name="Introduction">Introduction</a></h2>
|
|
||||||
|
|
||||||
<p>The <code>xtime</code> type is used to represent a point on some
|
|
||||||
time scale or a duration in time. This type may be proposed for the C
|
|
||||||
standard by Markus Kuhn. <b>Boost.Threads</b> provides only a very
|
|
||||||
minimal implementation of this proposal and it's expected that a
|
|
||||||
full implementation will be provided in Boost as a separate library, at
|
|
||||||
which time <b>Boost.Threads</b> will deprecate its implementation.</p>
|
|
||||||
|
|
||||||
<h2><a name="Header">Header</a></h2>
|
|
||||||
<pre>
|
|
||||||
#include <a href=
|
|
||||||
"../../../boost/thread/xtime.hpp"><boost/thread/xtime.hpp></a>
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h2><a name="Synopsis">Synopsis</a></h2>
|
|
||||||
<pre>
|
|
||||||
namespace boost {
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
TIME_UTC=1,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct xtime
|
|
||||||
{
|
|
||||||
#if defined(BOOST_NO_INT64_T)
|
|
||||||
int_fast32_t sec;
|
|
||||||
#else
|
|
||||||
int_fast64_t sec;
|
|
||||||
#endif
|
|
||||||
int_fast32_t nsec;
|
|
||||||
};
|
|
||||||
|
|
||||||
int xtime_get(struct xtime* xtp, int clock_type);
|
|
||||||
|
|
||||||
} // namespace boost
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h2><a name="Reference">Reference</a></h2>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>TIME_UTC</h3>
|
|
||||||
|
|
||||||
<p>The clock type for Coordinated Universal Time (UTC). The epoch for
|
|
||||||
this clock type is 1970-01-01 00:00:00. This is the only clock type
|
|
||||||
supported by <b>Boost.Threads</b>.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>xtime</h3>
|
|
||||||
<pre>
|
|
||||||
struct xtime
|
|
||||||
{
|
|
||||||
#if defined(BOOST_NO_INT64_T)
|
|
||||||
int_fast32_t sec;
|
|
||||||
#else
|
|
||||||
int_fast64_t sec;
|
|
||||||
#endif
|
|
||||||
int_fast32_t nsec;
|
|
||||||
};
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>sec</b> represents the whole seconds that have passed since the
|
|
||||||
epoch.</p>
|
|
||||||
|
|
||||||
<p><b>nsec</b> represents the nanoseconds since <code>sec.</code></p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>xtime_get</h3>
|
|
||||||
<pre>
|
|
||||||
int xtime_get(struct xtime* xtp, int clock_type);
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Postcondition:</b> <code>xtp</code> represents the current point
|
|
||||||
in time as a duration since the epoch specified by the <code>
|
|
||||||
clock_type</code>.</p>
|
|
||||||
|
|
||||||
<p><b>Returns:</b> <code>clock_type</code> if successful, otherwise
|
|
||||||
0.</p>
|
|
||||||
|
|
||||||
<p><b>Notes:</b> The resolution is implementation specific. For many
|
|
||||||
implementations the best resolution of time is far more than one
|
|
||||||
nanosecond, and even when the resolution is reasonably good, the
|
|
||||||
latency of a call to <code>xtime_get()</code> may be significant. For
|
|
||||||
maximum portability, avoid durations of less than one second.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h2><a name="Example">Example Usage</a></h2>
|
|
||||||
<pre>
|
|
||||||
#include <a href=
|
|
||||||
"../../../boost/thread/thread.hpp"><boost/thread/thread.hpp></a>
|
|
||||||
#include <a href=
|
|
||||||
"../../../boost/thread/tss.hpp"><boost/thread/xtime.hpp></a>
|
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
|
||||||
{
|
|
||||||
boost::xtime xt;
|
|
||||||
boost::xtime_get(&xt, boost::TIME_UTC);
|
|
||||||
xt.sec += 1;
|
|
||||||
boost::thread::sleep(xt); // Sleep for 1 second
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p>Revised
|
|
||||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->05 November, 2001<!--webbot bot="Timestamp" endspan i-checksum="39359" --></p>
|
|
||||||
|
|
||||||
<p><i>© Copyright <a href="mailto:williamkempf@hotmail.com">
|
|
||||||
William E. Kempf</a> 2001 all rights reserved.</i></p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
# (C) Copyright William E. Kempf 2001. Permission to copy, use, modify, sell and
|
|
||||||
# distribute this software is granted provided this copyright notice appears
|
|
||||||
# in all copies. This software is provided "as is" without express or implied
|
|
||||||
# warranty, and with no claim as to its suitability for any purpose.
|
|
||||||
#
|
|
||||||
# Boost.Threads build and test Jamfile
|
|
||||||
#
|
|
||||||
# Declares the following targets:
|
|
||||||
# 1. monitor, an example program.
|
|
||||||
# 2. starvephil, an example program.
|
|
||||||
# 3. tennis, an example program.
|
|
||||||
|
|
||||||
# declare the location of this subproject relative to the root
|
|
||||||
subproject libs/thread/example ;
|
|
||||||
|
|
||||||
# Do some OS-specific setup
|
|
||||||
if $(NT)
|
|
||||||
{
|
|
||||||
BOOST_THREADMON_LIB = <lib>../build/libboost_threadmon ;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
BOOST_THREADMON_LIB = ;
|
|
||||||
}
|
|
||||||
|
|
||||||
#######################
|
|
||||||
|
|
||||||
#
|
|
||||||
# Declare the Boost.Threads monitor example program.
|
|
||||||
#
|
|
||||||
|
|
||||||
exe monitor : monitor/monitor.cpp
|
|
||||||
<lib>../build/libboost_thread
|
|
||||||
$(BOOST_THREADMON_LIB)
|
|
||||||
# requirements
|
|
||||||
: <include>$(BOOST_ROOT)
|
|
||||||
<threading>multi
|
|
||||||
: debug release ;
|
|
||||||
|
|
||||||
#######################
|
|
||||||
|
|
||||||
#
|
|
||||||
# Declare the Boost.Threads starvephil example program.
|
|
||||||
#
|
|
||||||
|
|
||||||
exe starvephil : starvephil/starvephil.cpp
|
|
||||||
<lib>../build/libboost_thread
|
|
||||||
$(BOOST_THREADMON_LIB)
|
|
||||||
# requirements
|
|
||||||
: <include>$(BOOST_ROOT)
|
|
||||||
<threading>multi
|
|
||||||
: debug release ;
|
|
||||||
|
|
||||||
#######################
|
|
||||||
|
|
||||||
#
|
|
||||||
# Declare the Boost.Threads tennis example program.
|
|
||||||
#
|
|
||||||
|
|
||||||
exe tennis : tennis/tennis.cpp
|
|
||||||
<lib>../build/libboost_thread
|
|
||||||
$(BOOST_THREADMON_LIB)
|
|
||||||
# requirements
|
|
||||||
: <include>$(BOOST_ROOT)
|
|
||||||
<threading>multi
|
|
||||||
: debug release ;
|
|
||||||
23
example/Jamfile.v2
Normal file
23
example/Jamfile.v2
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# 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)
|
||||||
|
|
||||||
|
project boost/thread/example
|
||||||
|
: requirements <library>../build//boost_thread <threading>multi
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
exe monitor : monitor.cpp ;
|
||||||
|
exe starvephil : starvephil.cpp ;
|
||||||
|
exe tennis : tennis.cpp ;
|
||||||
|
exe condition : condition.cpp ;
|
||||||
|
exe mutex : mutex.cpp ;
|
||||||
|
exe once : once.cpp ;
|
||||||
|
exe recursive_mutex : recursive_mutex.cpp ;
|
||||||
|
exe thread : thread.cpp ;
|
||||||
|
exe thread_group : thread_group.cpp ;
|
||||||
|
exe tss : tss.cpp ;
|
||||||
|
exe xtime : xtime.cpp ;
|
||||||
|
|
||||||
82
example/condition.cpp
Normal file
82
example/condition.cpp
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
// 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 <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <boost/utility.hpp>
|
||||||
|
#include <boost/thread/condition.hpp>
|
||||||
|
#include <boost/thread/thread.hpp>
|
||||||
|
|
||||||
|
class bounded_buffer : private boost::noncopyable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef boost::mutex::scoped_lock lock;
|
||||||
|
|
||||||
|
bounded_buffer(int n) : begin(0), end(0), buffered(0), circular_buf(n) { }
|
||||||
|
|
||||||
|
void send (int m) {
|
||||||
|
lock lk(monitor);
|
||||||
|
while (buffered == circular_buf.size())
|
||||||
|
buffer_not_full.wait(lk);
|
||||||
|
circular_buf[end] = m;
|
||||||
|
end = (end+1) % circular_buf.size();
|
||||||
|
++buffered;
|
||||||
|
buffer_not_empty.notify_one();
|
||||||
|
}
|
||||||
|
int receive() {
|
||||||
|
lock lk(monitor);
|
||||||
|
while (buffered == 0)
|
||||||
|
buffer_not_empty.wait(lk);
|
||||||
|
int i = circular_buf[begin];
|
||||||
|
begin = (begin+1) % circular_buf.size();
|
||||||
|
--buffered;
|
||||||
|
buffer_not_full.notify_one();
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int begin, end, buffered;
|
||||||
|
std::vector<int> circular_buf;
|
||||||
|
boost::condition buffer_not_full, buffer_not_empty;
|
||||||
|
boost::mutex monitor;
|
||||||
|
};
|
||||||
|
|
||||||
|
bounded_buffer buf(2);
|
||||||
|
|
||||||
|
boost::mutex io_mutex;
|
||||||
|
|
||||||
|
void sender() {
|
||||||
|
int n = 0;
|
||||||
|
while (n < 100) {
|
||||||
|
buf.send(n);
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock io_lock(io_mutex);
|
||||||
|
std::cout << "sent: " << n << std::endl;
|
||||||
|
}
|
||||||
|
++n;
|
||||||
|
}
|
||||||
|
buf.send(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void receiver() {
|
||||||
|
int n;
|
||||||
|
do {
|
||||||
|
n = buf.receive();
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock io_lock(io_mutex);
|
||||||
|
std::cout << "received: " << n << std::endl;
|
||||||
|
}
|
||||||
|
} while (n != -1); // -1 indicates end of buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int, char*[])
|
||||||
|
{
|
||||||
|
boost::thread thrd1(&sender);
|
||||||
|
boost::thread thrd2(&receiver);
|
||||||
|
thrd1.join();
|
||||||
|
thrd2.join();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -1,3 +1,9 @@
|
|||||||
|
// 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 <vector>
|
#include <vector>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <boost/thread/condition.hpp>
|
#include <boost/thread/condition.hpp>
|
||||||
@@ -6,21 +12,21 @@
|
|||||||
#include <boost/thread/thread.hpp>
|
#include <boost/thread/thread.hpp>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
const int ITERS = 100;
|
const int ITERS = 100;
|
||||||
boost::mutex io_mutex;
|
boost::mutex io_mutex;
|
||||||
};
|
} // namespace
|
||||||
|
|
||||||
template <typename M>
|
template <typename M>
|
||||||
class buffer_t
|
class buffer_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef typename M::scoped_lock scoped_lock;
|
typedef typename M::scoped_lock scoped_lock;
|
||||||
|
|
||||||
buffer_t(int n)
|
buffer_t(int n)
|
||||||
: p(0), c(0), full(0), buf(n)
|
: p(0), c(0), full(0), buf(n)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void send(int m)
|
void send(int m)
|
||||||
{
|
{
|
||||||
scoped_lock lk(mutex);
|
scoped_lock lk(mutex);
|
||||||
@@ -29,7 +35,7 @@ public:
|
|||||||
buf[p] = m;
|
buf[p] = m;
|
||||||
p = (p+1) % buf.size();
|
p = (p+1) % buf.size();
|
||||||
++full;
|
++full;
|
||||||
cond.notify_all();
|
cond.notify_one();
|
||||||
}
|
}
|
||||||
int receive()
|
int receive()
|
||||||
{
|
{
|
||||||
@@ -39,41 +45,40 @@ public:
|
|||||||
int i = buf[c];
|
int i = buf[c];
|
||||||
c = (c+1) % buf.size();
|
c = (c+1) % buf.size();
|
||||||
--full;
|
--full;
|
||||||
cond.notify_all();
|
cond.notify_one();
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
static buffer_t& get_buffer()
|
static buffer_t& get_buffer()
|
||||||
{
|
{
|
||||||
static buffer_t buf(2);
|
static buffer_t buf(2);
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_sender_thread()
|
static void do_sender_thread()
|
||||||
{
|
{
|
||||||
for (int n = 0; n < ITERS; ++n)
|
for (int n = 0; n < ITERS; ++n)
|
||||||
{
|
{
|
||||||
get_buffer().send(n);
|
|
||||||
{
|
{
|
||||||
boost::mutex::scoped_lock lock(io_mutex);
|
boost::mutex::scoped_lock lock(io_mutex);
|
||||||
std::cout << "sent: " << n << std::endl;
|
std::cout << "sending: " << n << std::endl;
|
||||||
}
|
}
|
||||||
|
get_buffer().send(n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_receiver_thread()
|
static void do_receiver_thread()
|
||||||
{
|
{
|
||||||
int n;
|
for (int x=0; x < (ITERS/2); ++x)
|
||||||
do
|
|
||||||
{
|
{
|
||||||
n = get_buffer().receive();
|
int n = get_buffer().receive();
|
||||||
{
|
{
|
||||||
boost::mutex::scoped_lock lock(io_mutex);
|
boost::mutex::scoped_lock lock(io_mutex);
|
||||||
std::cout << "received: " << n << std::endl;
|
std::cout << "received: " << n << std::endl;
|
||||||
}
|
}
|
||||||
} while (n < ITERS - 1);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
M mutex;
|
M mutex;
|
||||||
boost::condition cond;
|
boost::condition cond;
|
||||||
@@ -86,10 +91,12 @@ void do_test(M* dummy=0)
|
|||||||
{
|
{
|
||||||
typedef buffer_t<M> buffer_type;
|
typedef buffer_t<M> buffer_type;
|
||||||
buffer_type::get_buffer();
|
buffer_type::get_buffer();
|
||||||
boost::thread thrd1(&buffer_type::do_sender_thread);
|
boost::thread thrd1(&buffer_type::do_receiver_thread);
|
||||||
boost::thread thrd2(&buffer_type::do_receiver_thread);
|
boost::thread thrd2(&buffer_type::do_receiver_thread);
|
||||||
|
boost::thread thrd3(&buffer_type::do_sender_thread);
|
||||||
thrd1.join();
|
thrd1.join();
|
||||||
thrd2.join();
|
thrd2.join();
|
||||||
|
thrd3.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_buffer()
|
void test_buffer()
|
||||||
47
example/mutex.cpp
Normal file
47
example/mutex.cpp
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
// 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/mutex.hpp>
|
||||||
|
#include <boost/thread/thread.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
boost::mutex io_mutex; // The iostreams are not guaranteed to be thread-safe!
|
||||||
|
|
||||||
|
class counter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
counter() : count(0) { }
|
||||||
|
|
||||||
|
int increment() {
|
||||||
|
boost::mutex::scoped_lock scoped_lock(mutex);
|
||||||
|
return ++count;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
boost::mutex mutex;
|
||||||
|
int count;
|
||||||
|
};
|
||||||
|
|
||||||
|
counter c;
|
||||||
|
|
||||||
|
void change_count()
|
||||||
|
{
|
||||||
|
int i = c.increment();
|
||||||
|
boost::mutex::scoped_lock scoped_lock(io_mutex);
|
||||||
|
std::cout << "count == " << i << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int, char*[])
|
||||||
|
{
|
||||||
|
const int num_threads = 4;
|
||||||
|
boost::thread_group thrds;
|
||||||
|
for (int i=0; i < num_threads; ++i)
|
||||||
|
thrds.create_thread(&change_count);
|
||||||
|
|
||||||
|
thrds.join_all();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
31
example/once.cpp
Normal file
31
example/once.cpp
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
// 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/thread.hpp>
|
||||||
|
#include <boost/thread/once.hpp>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
int value=0;
|
||||||
|
boost::once_flag once = BOOST_ONCE_INIT;
|
||||||
|
|
||||||
|
void init()
|
||||||
|
{
|
||||||
|
++value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void thread_proc()
|
||||||
|
{
|
||||||
|
boost::call_once(&init, once);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
boost::thread_group threads;
|
||||||
|
for (int i=0; i<5; ++i)
|
||||||
|
threads.create_thread(&thread_proc);
|
||||||
|
threads.join_all();
|
||||||
|
assert(value == 1);
|
||||||
|
}
|
||||||
49
example/recursive_mutex.cpp
Normal file
49
example/recursive_mutex.cpp
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
// 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/recursive_mutex.hpp>
|
||||||
|
#include <boost/thread/thread.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
class counter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
counter() : count(0) { }
|
||||||
|
|
||||||
|
int add(int val) {
|
||||||
|
boost::recursive_mutex::scoped_lock scoped_lock(mutex);
|
||||||
|
count += val;
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
int increment() {
|
||||||
|
boost::recursive_mutex::scoped_lock scoped_lock(mutex);
|
||||||
|
return add(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
boost::recursive_mutex mutex;
|
||||||
|
int count;
|
||||||
|
};
|
||||||
|
|
||||||
|
counter c;
|
||||||
|
|
||||||
|
void change_count()
|
||||||
|
{
|
||||||
|
std::cout << "count == " << c.increment() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int, char*[])
|
||||||
|
{
|
||||||
|
const int num_threads=4;
|
||||||
|
|
||||||
|
boost::thread_group threads;
|
||||||
|
for (int i=0; i < num_threads; ++i)
|
||||||
|
threads.create_thread(&change_count);
|
||||||
|
|
||||||
|
threads.join_all();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
185
example/starvephil.cpp
Normal file
185
example/starvephil.cpp
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
// 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/mutex.hpp>
|
||||||
|
#include <boost/thread/condition.hpp>
|
||||||
|
#include <boost/thread/thread.hpp>
|
||||||
|
#include <boost/thread/xtime.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
boost::mutex iomx;
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
class canteen
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
canteen() : m_chickens(0) { }
|
||||||
|
|
||||||
|
void get(int id)
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(m_mutex);
|
||||||
|
while (m_chickens == 0)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(iomx);
|
||||||
|
std::cout << "(" << clock() << ") Phil" << id <<
|
||||||
|
": wot, no chickens? I'll WAIT ..." << std::endl;
|
||||||
|
}
|
||||||
|
m_condition.wait(lock);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(iomx);
|
||||||
|
std::cout << "(" << clock() << ") Phil" << id <<
|
||||||
|
": those chickens look good ... one please ..." << std::endl;
|
||||||
|
}
|
||||||
|
m_chickens--;
|
||||||
|
}
|
||||||
|
void put(int value)
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(m_mutex);
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(iomx);
|
||||||
|
std::cout << "(" << clock()
|
||||||
|
<< ") Chef: ouch ... make room ... this dish is "
|
||||||
|
<< "very hot ..." << std::endl;
|
||||||
|
}
|
||||||
|
boost::xtime xt;
|
||||||
|
boost::xtime_get(&xt, boost::TIME_UTC);
|
||||||
|
xt.sec += 3;
|
||||||
|
boost::thread::sleep(xt);
|
||||||
|
m_chickens += value;
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(iomx);
|
||||||
|
std::cout << "(" << clock() <<
|
||||||
|
") Chef: more chickens ... " << m_chickens <<
|
||||||
|
" now available ... NOTIFYING ..." << std::endl;
|
||||||
|
}
|
||||||
|
m_condition.notify_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
boost::mutex m_mutex;
|
||||||
|
boost::condition m_condition;
|
||||||
|
int m_chickens;
|
||||||
|
};
|
||||||
|
|
||||||
|
canteen g_canteen;
|
||||||
|
|
||||||
|
void chef()
|
||||||
|
{
|
||||||
|
const int chickens = 4;
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(iomx);
|
||||||
|
std::cout << "(" << clock() << ") Chef: starting ..." << std::endl;
|
||||||
|
}
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(iomx);
|
||||||
|
std::cout << "(" << clock() << ") Chef: cooking ..." << std::endl;
|
||||||
|
}
|
||||||
|
boost::xtime xt;
|
||||||
|
boost::xtime_get(&xt, boost::TIME_UTC);
|
||||||
|
xt.sec += 2;
|
||||||
|
boost::thread::sleep(xt);
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(iomx);
|
||||||
|
std::cout << "(" << clock() << ") Chef: " << chickens
|
||||||
|
<< " chickens, ready-to-go ..." << std::endl;
|
||||||
|
}
|
||||||
|
g_canteen.put(chickens);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct phil
|
||||||
|
{
|
||||||
|
phil(int id) : m_id(id) { }
|
||||||
|
void run() {
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(iomx);
|
||||||
|
std::cout << "(" << clock() << ") Phil" << m_id
|
||||||
|
<< ": starting ..." << std::endl;
|
||||||
|
}
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
if (m_id > 0)
|
||||||
|
{
|
||||||
|
boost::xtime xt;
|
||||||
|
boost::xtime_get(&xt, boost::TIME_UTC);
|
||||||
|
xt.sec += 3;
|
||||||
|
boost::thread::sleep(xt);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(iomx);
|
||||||
|
std::cout << "(" << clock() << ") Phil" << m_id
|
||||||
|
<< ": gotta eat ..." << std::endl;
|
||||||
|
}
|
||||||
|
g_canteen.get(m_id);
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(iomx);
|
||||||
|
std::cout << "(" << clock() << ") Phil" << m_id
|
||||||
|
<< ": mmm ... that's good ..." << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void do_thread(void* param) {
|
||||||
|
static_cast<phil*>(param)->run();
|
||||||
|
}
|
||||||
|
|
||||||
|
int m_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct thread_adapt
|
||||||
|
{
|
||||||
|
thread_adapt(void (*func)(void*), void* param)
|
||||||
|
: _func(func), _param(param)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
int operator()() const
|
||||||
|
{
|
||||||
|
_func(_param);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void (*_func)(void*);
|
||||||
|
void* _param;
|
||||||
|
};
|
||||||
|
|
||||||
|
class thread_adapter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
thread_adapter(void (*func)(void*), void* param)
|
||||||
|
: _func(func), _param(param)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
void operator()() const { _func(_param); }
|
||||||
|
private:
|
||||||
|
void (*_func)(void*);
|
||||||
|
void* _param;
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
boost::thread thrd_chef(&chef);
|
||||||
|
phil p[] = { phil(0), phil(1), phil(2), phil(3), phil(4) };
|
||||||
|
boost::thread thrd_phil0(thread_adapter(&phil::do_thread, &p[0]));
|
||||||
|
boost::thread thrd_phil1(thread_adapter(&phil::do_thread, &p[1]));
|
||||||
|
boost::thread thrd_phil2(thread_adapter(&phil::do_thread, &p[2]));
|
||||||
|
boost::thread thrd_phil3(thread_adapter(&phil::do_thread, &p[3]));
|
||||||
|
boost::thread thrd_phil4(thread_adapter(&phil::do_thread, &p[4]));
|
||||||
|
|
||||||
|
thrd_chef.join();
|
||||||
|
thrd_phil0.join();
|
||||||
|
thrd_phil1.join();
|
||||||
|
thrd_phil2.join();
|
||||||
|
thrd_phil3.join();
|
||||||
|
thrd_phil4.join();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -1,171 +0,0 @@
|
|||||||
#include <boost/thread/mutex.hpp>
|
|
||||||
#include <boost/thread/condition.hpp>
|
|
||||||
#include <boost/thread/thread.hpp>
|
|
||||||
#include <boost/thread/xtime.hpp>
|
|
||||||
#include <iostream>
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
boost::mutex iomx;
|
|
||||||
};
|
|
||||||
|
|
||||||
class canteen
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
canteen() : m_chickens(0) { }
|
|
||||||
|
|
||||||
void get(int id)
|
|
||||||
{
|
|
||||||
boost::mutex::scoped_lock lock(m_mutex);
|
|
||||||
while (m_chickens == 0)
|
|
||||||
{
|
|
||||||
{
|
|
||||||
boost::mutex::scoped_lock lock(iomx);
|
|
||||||
std::cout << "(" << clock() << ") Phil" << id <<
|
|
||||||
": wot, no chickens? I'll WAIT ..." << std::endl;
|
|
||||||
}
|
|
||||||
m_condition.wait(lock);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
boost::mutex::scoped_lock lock(iomx);
|
|
||||||
std::cout << "(" << clock() << ") Phil" << id <<
|
|
||||||
": those chickens look good ... one please ..." << std::endl;
|
|
||||||
}
|
|
||||||
m_chickens--;
|
|
||||||
}
|
|
||||||
void put(int value)
|
|
||||||
{
|
|
||||||
boost::mutex::scoped_lock lock(m_mutex);
|
|
||||||
{
|
|
||||||
boost::mutex::scoped_lock lock(iomx);
|
|
||||||
std::cout << "(" << clock() <<
|
|
||||||
") Chef: ouch ... make room ... this dish is very hot ..." << std::endl;
|
|
||||||
}
|
|
||||||
boost::xtime xt;
|
|
||||||
boost::xtime_get(&xt, boost::TIME_UTC);
|
|
||||||
xt.sec += 3;
|
|
||||||
boost::thread::sleep(xt);
|
|
||||||
m_chickens += value;
|
|
||||||
{
|
|
||||||
boost::mutex::scoped_lock lock(iomx);
|
|
||||||
std::cout << "(" << clock() <<
|
|
||||||
") Chef: more chickens ... " << m_chickens <<
|
|
||||||
" now available ... NOTIFYING ..." << std::endl;
|
|
||||||
}
|
|
||||||
m_condition.notify_all();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
boost::mutex m_mutex;
|
|
||||||
boost::condition m_condition;
|
|
||||||
int m_chickens;
|
|
||||||
};
|
|
||||||
|
|
||||||
canteen g_canteen;
|
|
||||||
|
|
||||||
void chef()
|
|
||||||
{
|
|
||||||
const int chickens = 4;
|
|
||||||
{
|
|
||||||
boost::mutex::scoped_lock lock(iomx);
|
|
||||||
std::cout << "(" << clock() << ") Chef: starting ..." << std::endl;
|
|
||||||
}
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
{
|
|
||||||
boost::mutex::scoped_lock lock(iomx);
|
|
||||||
std::cout << "(" << clock() << ") Chef: cooking ..." << std::endl;
|
|
||||||
}
|
|
||||||
boost::xtime xt;
|
|
||||||
boost::xtime_get(&xt, boost::TIME_UTC);
|
|
||||||
xt.sec += 2;
|
|
||||||
boost::thread::sleep(xt);
|
|
||||||
{
|
|
||||||
boost::mutex::scoped_lock lock(iomx);
|
|
||||||
std::cout << "(" << clock() << ") Chef: " << chickens
|
|
||||||
<< " chickens, ready-to-go ..." << std::endl;
|
|
||||||
}
|
|
||||||
g_canteen.put(chickens);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct phil
|
|
||||||
{
|
|
||||||
phil(int id) : m_id(id) { }
|
|
||||||
void run() {
|
|
||||||
{
|
|
||||||
boost::mutex::scoped_lock lock(iomx);
|
|
||||||
std::cout << "(" << clock() << ") Phil" << m_id << ": starting ..." << std::endl;
|
|
||||||
}
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
if (m_id > 0)
|
|
||||||
{
|
|
||||||
boost::xtime xt;
|
|
||||||
boost::xtime_get(&xt, boost::TIME_UTC);
|
|
||||||
xt.sec += 3;
|
|
||||||
boost::thread::sleep(xt);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
boost::mutex::scoped_lock lock(iomx);
|
|
||||||
std::cout << "(" << clock() << ") Phil" << m_id
|
|
||||||
<< ": gotta eat ..." << std::endl;
|
|
||||||
}
|
|
||||||
g_canteen.get(m_id);
|
|
||||||
{
|
|
||||||
boost::mutex::scoped_lock lock(iomx);
|
|
||||||
std::cout << "(" << clock() << ") Phil" << m_id
|
|
||||||
<< ": mmm ... that's good ..." << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
static void do_thread(void* param) {
|
|
||||||
static_cast<phil*>(param)->run();
|
|
||||||
}
|
|
||||||
|
|
||||||
int m_id;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct thread_adapt
|
|
||||||
{
|
|
||||||
thread_adapt(void (*func)(void*), void* param) : _func(func), _param(param) { }
|
|
||||||
int operator()() const
|
|
||||||
{
|
|
||||||
_func(_param);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void (*_func)(void*);
|
|
||||||
void* _param;
|
|
||||||
};
|
|
||||||
|
|
||||||
class thread_adapter
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
thread_adapter(void (*func)(void*), void* param) : _func(func), _param(param) { }
|
|
||||||
void operator()() const { _func(_param); }
|
|
||||||
private:
|
|
||||||
void (*_func)(void*);
|
|
||||||
void* _param;
|
|
||||||
};
|
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
|
||||||
{
|
|
||||||
boost::thread thrd_chef(&chef);
|
|
||||||
phil p[] = { phil(0), phil(1), phil(2), phil(3), phil(4) };
|
|
||||||
boost::thread thrd_phil0(thread_adapter(&phil::do_thread, &p[0]));
|
|
||||||
boost::thread thrd_phil1(thread_adapter(&phil::do_thread, &p[1]));
|
|
||||||
boost::thread thrd_phil2(thread_adapter(&phil::do_thread, &p[2]));
|
|
||||||
boost::thread thrd_phil3(thread_adapter(&phil::do_thread, &p[3]));
|
|
||||||
boost::thread thrd_phil4(thread_adapter(&phil::do_thread, &p[4]));
|
|
||||||
|
|
||||||
thrd_chef.join();
|
|
||||||
thrd_phil0.join();
|
|
||||||
thrd_phil1.join();
|
|
||||||
thrd_phil2.join();
|
|
||||||
thrd_phil3.join();
|
|
||||||
thrd_phil4.join();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,9 @@
|
|||||||
|
// 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/mutex.hpp>
|
#include <boost/thread/mutex.hpp>
|
||||||
#include <boost/thread/condition.hpp>
|
#include <boost/thread/condition.hpp>
|
||||||
#include <boost/thread/thread.hpp>
|
#include <boost/thread/thread.hpp>
|
||||||
@@ -5,8 +11,8 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#if defined(BOOST_HAS_WINTHREADS)
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
# include <windows.h>
|
# include <windows.h>
|
||||||
# include <process.h>
|
# include <process.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
enum game_state
|
enum game_state
|
||||||
@@ -49,7 +55,10 @@ void player(void* param)
|
|||||||
{
|
{
|
||||||
cond.wait(lock);
|
cond.wait(lock);
|
||||||
if (state == other)
|
if (state == other)
|
||||||
std::cout << "---" << player_name(active) << ": Spurious wakeup!" << std::endl;
|
{
|
||||||
|
std::cout << "---" << player_name(active)
|
||||||
|
<< ": Spurious wakeup!" << std::endl;
|
||||||
|
}
|
||||||
} while (state == other);
|
} while (state == other);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,7 +69,10 @@ void player(void* param)
|
|||||||
|
|
||||||
struct thread_adapt
|
struct thread_adapt
|
||||||
{
|
{
|
||||||
thread_adapt(void (*func)(void*), void* param) : _func(func), _param(param) { }
|
thread_adapt(void (*func)(void*), void* param)
|
||||||
|
: _func(func), _param(param)
|
||||||
|
{
|
||||||
|
}
|
||||||
int operator()() const
|
int operator()() const
|
||||||
{
|
{
|
||||||
_func(_param);
|
_func(_param);
|
||||||
@@ -74,7 +86,10 @@ struct thread_adapt
|
|||||||
class thread_adapter
|
class thread_adapter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
thread_adapter(void (*func)(void*), void* param) : _func(func), _param(param) { }
|
thread_adapter(void (*func)(void*), void* param)
|
||||||
|
: _func(func), _param(param)
|
||||||
|
{
|
||||||
|
}
|
||||||
void operator()() const { _func(_param); }
|
void operator()() const { _func(_param); }
|
||||||
private:
|
private:
|
||||||
void (*_func)(void*);
|
void (*_func)(void*);
|
||||||
35
example/thread.cpp
Normal file
35
example/thread.cpp
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
// 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/thread.hpp>
|
||||||
|
#include <boost/thread/xtime.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
struct thread_alarm
|
||||||
|
{
|
||||||
|
thread_alarm(int secs) : m_secs(secs) { }
|
||||||
|
void operator()()
|
||||||
|
{
|
||||||
|
boost::xtime xt;
|
||||||
|
boost::xtime_get(&xt, boost::TIME_UTC);
|
||||||
|
xt.sec += m_secs;
|
||||||
|
|
||||||
|
boost::thread::sleep(xt);
|
||||||
|
|
||||||
|
std::cout << "alarm sounded..." << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
int m_secs;
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
int secs = 5;
|
||||||
|
std::cout << "setting alarm for 5 seconds..." << std::endl;
|
||||||
|
thread_alarm alarm(secs);
|
||||||
|
boost::thread thrd(alarm);
|
||||||
|
thrd.join();
|
||||||
|
}
|
||||||
25
example/thread_group.cpp
Normal file
25
example/thread_group.cpp
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
// 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/thread.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
boost::mutex mutex;
|
||||||
|
|
||||||
|
void increment_count()
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(mutex);
|
||||||
|
std::cout << "count = " << ++count << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
boost::thread_group threads;
|
||||||
|
for (int i = 0; i < 10; ++i)
|
||||||
|
threads.create_thread(&increment_count);
|
||||||
|
threads.join_all();
|
||||||
|
}
|
||||||
36
example/tss.cpp
Normal file
36
example/tss.cpp
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
// 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/thread.hpp>
|
||||||
|
#include <boost/thread/tss.hpp>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
boost::thread_specific_ptr<int> value;
|
||||||
|
|
||||||
|
void increment()
|
||||||
|
{
|
||||||
|
int* p = value.get();
|
||||||
|
++*p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void thread_proc()
|
||||||
|
{
|
||||||
|
value.reset(new int(0)); // initialize the thread's storage
|
||||||
|
for (int i=0; i<10; ++i)
|
||||||
|
{
|
||||||
|
increment();
|
||||||
|
int* p = value.get();
|
||||||
|
assert(*p == i+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
boost::thread_group threads;
|
||||||
|
for (int i=0; i<5; ++i)
|
||||||
|
threads.create_thread(&thread_proc);
|
||||||
|
threads.join_all();
|
||||||
|
}
|
||||||
16
example/xtime.cpp
Normal file
16
example/xtime.cpp
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
// 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/thread.hpp>
|
||||||
|
#include <boost/thread/xtime.hpp>
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
boost::xtime xt;
|
||||||
|
boost::xtime_get(&xt, boost::TIME_UTC);
|
||||||
|
xt.sec += 1;
|
||||||
|
boost::thread::sleep(xt); // Sleep for 1 second
|
||||||
|
}
|
||||||
25
include/boost/thread.hpp
Normal file
25
include/boost/thread.hpp
Normal file
@@ -0,0 +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_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/thread_time.hpp>
|
||||||
|
#include <boost/thread/locks.hpp>
|
||||||
|
#include <boost/thread/shared_mutex.hpp>
|
||||||
|
#include <boost/thread/barrier.hpp>
|
||||||
|
|
||||||
|
#endif
|
||||||
63
include/boost/thread/barrier.hpp
Normal file
63
include/boost/thread/barrier.hpp
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
// 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)
|
||||||
|
|
||||||
|
#ifndef BOOST_BARRIER_JDM030602_HPP
|
||||||
|
#define BOOST_BARRIER_JDM030602_HPP
|
||||||
|
|
||||||
|
#include <boost/thread/detail/config.hpp>
|
||||||
|
|
||||||
|
#include <boost/thread/mutex.hpp>
|
||||||
|
#include <boost/thread/condition_variable.hpp>
|
||||||
|
#include <string>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include <boost/config/abi_prefix.hpp>
|
||||||
|
|
||||||
|
namespace boost
|
||||||
|
{
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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,159 +1,16 @@
|
|||||||
// Copyright (C) 2001
|
#ifndef BOOST_THREAD_CONDITION_HPP
|
||||||
// William E. Kempf
|
#define BOOST_THREAD_CONDITION_HPP
|
||||||
|
// (C) Copyright 2007 Anthony Williams
|
||||||
//
|
//
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
// Distributed under the Boost Software License, Version 1.0. (See
|
||||||
// and its documentation for any purpose is hereby granted without fee,
|
// accompanying file LICENSE_1_0.txt or copy at
|
||||||
// provided that the above copyright notice appear in all copies and
|
// http://www.boost.org/LICENSE_1_0.txt)
|
||||||
// that both that copyright notice and this permission notice appear
|
|
||||||
// in supporting documentation. William E. Kempf makes no representations
|
|
||||||
// about the suitability of this software for any purpose.
|
|
||||||
// It is provided "as is" without express or implied warranty.
|
|
||||||
|
|
||||||
#ifndef BOOST_CONDITION_WEK070601_HPP
|
#include <boost/thread/condition_variable.hpp>
|
||||||
#define BOOST_CONDITION_WEK070601_HPP
|
|
||||||
|
|
||||||
#include <boost/config.hpp>
|
namespace boost
|
||||||
#ifndef BOOST_HAS_THREADS
|
|
||||||
# error Thread support is unavailable!
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <boost/thread/exceptions.hpp>
|
|
||||||
#include <boost/utility.hpp>
|
|
||||||
#include <boost/thread/detail/lock.hpp>
|
|
||||||
|
|
||||||
#if defined(BOOST_HAS_PTHREADS)
|
|
||||||
# include <pthread.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace boost {
|
|
||||||
|
|
||||||
struct xtime;
|
|
||||||
|
|
||||||
class condition : private noncopyable
|
|
||||||
{
|
{
|
||||||
public:
|
typedef condition_variable_any condition;
|
||||||
condition();
|
}
|
||||||
~condition();
|
|
||||||
|
|
||||||
void notify_one();
|
|
||||||
void notify_all();
|
|
||||||
|
|
||||||
template <typename L>
|
|
||||||
void wait(L& lock)
|
|
||||||
{
|
|
||||||
if (!lock)
|
|
||||||
throw lock_error();
|
|
||||||
|
|
||||||
do_wait(lock.m_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename L, typename Pr>
|
|
||||||
void wait(L& lock, Pr pred)
|
|
||||||
{
|
|
||||||
if (!lock)
|
|
||||||
throw lock_error();
|
|
||||||
|
|
||||||
while (!pred())
|
|
||||||
do_wait(lock.m_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename L>
|
|
||||||
bool timed_wait(L& lock, const xtime& xt)
|
|
||||||
{
|
|
||||||
if (!lock)
|
|
||||||
throw lock_error();
|
|
||||||
|
|
||||||
return do_timed_wait(lock.m_mutex, xt);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename L, typename Pr>
|
|
||||||
bool timed_wait(L& lock, const xtime& xt, Pr pred)
|
|
||||||
{
|
|
||||||
if (!lock)
|
|
||||||
throw lock_error();
|
|
||||||
|
|
||||||
while (!pred())
|
|
||||||
{
|
|
||||||
if (!do_timed_wait(lock.m_mutex, xt))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
template <typename M>
|
|
||||||
void do_wait(M& mutex)
|
|
||||||
{
|
|
||||||
#if defined(BOOST_HAS_WINTHREADS)
|
|
||||||
enter_wait();
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef typename detail::thread::lock_ops<M> lock_ops;
|
|
||||||
lock_ops::lock_state state;
|
|
||||||
lock_ops::unlock(mutex, state);
|
|
||||||
|
|
||||||
#if defined(BOOST_HAS_PTHREADS)
|
|
||||||
do_wait(state.pmutex);
|
|
||||||
#elif defined(BOOST_HAS_WINTHREADS)
|
|
||||||
do_wait();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
lock_ops::lock(mutex, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename M>
|
|
||||||
bool do_timed_wait(M& mutex, const xtime& xt)
|
|
||||||
{
|
|
||||||
#if defined(BOOST_HAS_WINTHREADS)
|
|
||||||
enter_wait();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef typename detail::thread::lock_ops<M> lock_ops;
|
|
||||||
lock_ops::lock_state state;
|
|
||||||
lock_ops::unlock(mutex, state);
|
|
||||||
|
|
||||||
bool ret = false;
|
|
||||||
|
|
||||||
#if defined(BOOST_HAS_PTHREADS)
|
|
||||||
ret = do_timed_wait(xt, state.pmutex);
|
|
||||||
#elif defined(BOOST_HAS_WINTHREADS)
|
|
||||||
ret = do_timed_wait(xt);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
lock_ops::lock(mutex, state);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(BOOST_HAS_WINTHREADS)
|
|
||||||
void enter_wait();
|
|
||||||
void do_wait();
|
|
||||||
bool do_timed_wait(const xtime& xt);
|
|
||||||
#elif defined(BOOST_HAS_PTHREADS)
|
|
||||||
void do_wait(pthread_mutex_t* pmutex);
|
|
||||||
bool do_timed_wait(const xtime& xt, pthread_mutex_t* pmutex);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(BOOST_HAS_WINTHREADS)
|
|
||||||
void* m_gate;
|
|
||||||
void* m_queue;
|
|
||||||
void* m_mutex;
|
|
||||||
unsigned m_gone; // # threads that timed out and never made it to the m_queue
|
|
||||||
unsigned long m_blocked; // # threads m_blocked m_waiting for the condition
|
|
||||||
unsigned m_waiting; // # threads m_waiting no longer m_waiting for the condition but still
|
|
||||||
// m_waiting to be removed from the m_queue
|
|
||||||
#elif defined(BOOST_HAS_PTHREADS)
|
|
||||||
pthread_cond_t m_condition;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace boost
|
|
||||||
|
|
||||||
// Change Log:
|
|
||||||
// 8 Feb 01 WEKEMPF Initial version.
|
|
||||||
// 22 May 01 WEKEMPF Modified to use xtime for time outs.
|
|
||||||
// 23 May 01 WEKEMPF Removed "duration" timed_waits, as they are too difficult
|
|
||||||
// to use with spurious wakeups.
|
|
||||||
|
|
||||||
#endif // BOOST_CONDITION_WEK070601_HPP
|
|
||||||
|
|||||||
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
|
||||||
@@ -1,100 +0,0 @@
|
|||||||
// Copyright (C) 2001
|
|
||||||
// William E. Kempf
|
|
||||||
//
|
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
|
||||||
// and its documentation for any purpose is hereby granted without fee,
|
|
||||||
// provided that the above copyright notice appear in all copies and
|
|
||||||
// that both that copyright notice and this permission notice appear
|
|
||||||
// in supporting documentation. William E. Kempf makes no representations
|
|
||||||
// about the suitability of this software for any purpose.
|
|
||||||
// It is provided "as is" without express or implied warranty.
|
|
||||||
|
|
||||||
// This file is used to configure Boost.Threads during development
|
|
||||||
// in order to decouple dependency on any Boost release. Once
|
|
||||||
// accepted into Boost these contents will be moved to <boost/config>
|
|
||||||
// or some other appropriate build configuration and all
|
|
||||||
// #include <boost/thread/config.hpp> statements will be changed
|
|
||||||
// accordingly.
|
|
||||||
|
|
||||||
#ifndef BOOST_THREAD_CONFIG_WEK070601_HPP
|
|
||||||
#define BOOST_THREAD_CONFIG_WEK070601_HPP
|
|
||||||
|
|
||||||
#include <boost/config.hpp>
|
|
||||||
|
|
||||||
#error "Included <boost/thread/config.hpp>"
|
|
||||||
|
|
||||||
/*// Define if threading support is enabled for the toolset.
|
|
||||||
#undef BOOST_HAS_THREADS
|
|
||||||
|
|
||||||
// Define if threading should be implemented in terms of Win32 threads.
|
|
||||||
#undef BOOST_HAS_WINTHREADS
|
|
||||||
|
|
||||||
// Define if threading should be implemented in terms of POSIX threads.
|
|
||||||
#undef BOOST_HAS_PTHREADS
|
|
||||||
|
|
||||||
// Define if BOOST_HAS_PTHREADS and pthread_delay_np() exists.
|
|
||||||
#undef BOOST_HAS_PTHREAD_DELAY_NP
|
|
||||||
|
|
||||||
// Define if BOOST_HAS_PTHREADS and not BOOST_HAS_PTHREAD_DELAY_NP
|
|
||||||
// but nanosleep can be used instead.
|
|
||||||
#undef BOOST_HAS_NANOSLEEP
|
|
||||||
|
|
||||||
// Define if BOOST_HAS_PTHREADS and pthread_yield() exists.
|
|
||||||
#undef BOOST_HAS_PTHREAD_YIELD
|
|
||||||
|
|
||||||
// Define if BOOST_HAS_PTHREADS and not BOOST_HAS_PTHREAD_YIELD and
|
|
||||||
// sched_yield() exists.
|
|
||||||
#undef BOOST_HAS_SCHED_YIELD
|
|
||||||
|
|
||||||
// Define if gettimeofday() exists.
|
|
||||||
#undef BOOST_HAS_GETTIMEOFDAY
|
|
||||||
|
|
||||||
// Define if not BOOST_HAS_GETTIMEOFDAY and clock_gettime() exists.
|
|
||||||
#undef BOOST_HAS_CLOCK_GETTIME
|
|
||||||
|
|
||||||
// Define if not BOOST_HAS_GETTIMEOFDAY and not BOOST_HAS_CLOCK_GETTIME and
|
|
||||||
// GetSystemTimeAsFileTime() can be called with an FTIME structure.
|
|
||||||
#undef BOOST_HAS_FTIME
|
|
||||||
|
|
||||||
// Define if pthread_mutexattr_settype and pthread_mutexattr_gettype exist.
|
|
||||||
#undef BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE
|
|
||||||
|
|
||||||
// Here we'll set up known compiler options.
|
|
||||||
|
|
||||||
#if defined(BOOST_MSVC)
|
|
||||||
# if defined(_MT)
|
|
||||||
# define BOOST_HAS_THREADS
|
|
||||||
# endif
|
|
||||||
# define BOOST_HAS_WINTHREADS // comment out this to test pthreads-win32.
|
|
||||||
# if !defined(BOOST_HAS_WINTHREADS)
|
|
||||||
# define BOOST_HAS_PTHREADS
|
|
||||||
# define BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE
|
|
||||||
# define PtW32NoCatchWarn
|
|
||||||
# pragma comment(lib, "pthreadVCE.lib")
|
|
||||||
# endif
|
|
||||||
# define BOOST_HAS_FTIME
|
|
||||||
// pdm: this is for linux - is there a better #define to #if on?
|
|
||||||
// wek: not sure how else to do this, but GNU CC on Win32 should probably
|
|
||||||
// use BOOST_HAS_WINTHREADS, and I expect there will be other
|
|
||||||
// platform specific variations for this compiler toolset. Need
|
|
||||||
// to decide how to handle this.
|
|
||||||
#elif defined( __GNUC__ )
|
|
||||||
# define BOOST_HAS_THREADS
|
|
||||||
# define BOOST_HAS_PTHREADS
|
|
||||||
# define BOOST_HAS_NANOSLEEP
|
|
||||||
# define BOOST_HAS_GETTIMEOFDAY
|
|
||||||
// pdm: From the pthread.h header, one of these macros
|
|
||||||
// must be defined for this stuff to exist.
|
|
||||||
// wek: This seems like a harmless enough method to determine these
|
|
||||||
// switches, but one should note that some implementations may not
|
|
||||||
// use these. Notably, pthreads-win32 doesn't define either
|
|
||||||
// __USE_UNIX98 or __USE_GNU.
|
|
||||||
# if defined( __USE_UNIX98 )
|
|
||||||
# define BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE
|
|
||||||
# elif defined( __USE_GNU )
|
|
||||||
# define BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE
|
|
||||||
# define BOOST_HAS_PTHREAD_YIELD
|
|
||||||
# endif
|
|
||||||
#endif*/
|
|
||||||
|
|
||||||
#endif // BOOST_THREAD_CONFIG_WEK070601_HPP
|
|
||||||
94
include/boost/thread/detail/config.hpp
Normal file
94
include/boost/thread/detail/config.hpp
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
// 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)
|
||||||
|
|
||||||
|
#ifndef BOOST_THREAD_CONFIG_WEK01032003_HPP
|
||||||
|
#define BOOST_THREAD_CONFIG_WEK01032003_HPP
|
||||||
|
|
||||||
|
#include <boost/config.hpp>
|
||||||
|
#include <boost/detail/workaround.hpp>
|
||||||
|
|
||||||
|
#if BOOST_WORKAROUND(__BORLANDC__, < 0x600)
|
||||||
|
# pragma warn -8008 // Condition always true/false
|
||||||
|
# pragma warn -8080 // Identifier declared but never used
|
||||||
|
# pragma warn -8057 // Parameter never used
|
||||||
|
# pragma warn -8066 // Unreachable code
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "platform.hpp"
|
||||||
|
|
||||||
|
// compatibility with the rest of Boost's auto-linking code:
|
||||||
|
#if defined(BOOST_THREAD_DYN_DLL) || defined(BOOST_ALL_DYN_LINK)
|
||||||
|
# undef BOOST_THREAD_USE_LIB
|
||||||
|
# define BOOST_THREAD_USE_DLL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(BOOST_THREAD_BUILD_DLL) //Build dll
|
||||||
|
#elif defined(BOOST_THREAD_BUILD_LIB) //Build lib
|
||||||
|
#elif defined(BOOST_THREAD_USE_DLL) //Use dll
|
||||||
|
#elif defined(BOOST_THREAD_USE_LIB) //Use lib
|
||||||
|
#else //Use default
|
||||||
|
# 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
|
||||||
|
# define BOOST_THREAD_USE_LIB
|
||||||
|
# else
|
||||||
|
//For compilers not yet supporting auto-tss cleanup
|
||||||
|
//with Boost.Threads lib, use Boost.Threads dll
|
||||||
|
# define BOOST_THREAD_USE_DLL
|
||||||
|
# endif
|
||||||
|
# else
|
||||||
|
# define BOOST_THREAD_USE_LIB
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(BOOST_HAS_DECLSPEC)
|
||||||
|
# if defined(BOOST_THREAD_BUILD_DLL) //Build dll
|
||||||
|
# define BOOST_THREAD_DECL __declspec(dllexport)
|
||||||
|
# elif defined(BOOST_THREAD_USE_DLL) //Use dll
|
||||||
|
# define BOOST_THREAD_DECL __declspec(dllimport)
|
||||||
|
# else
|
||||||
|
# define BOOST_THREAD_DECL
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# define BOOST_THREAD_DECL
|
||||||
|
#endif // BOOST_HAS_DECLSPEC
|
||||||
|
|
||||||
|
//
|
||||||
|
// Automatically link to the correct build variant where possible.
|
||||||
|
//
|
||||||
|
#if !defined(BOOST_ALL_NO_LIB) && !defined(BOOST_THREAD_NO_LIB) && !defined(BOOST_THREAD_BUILD_DLL) && !defined(BOOST_THREAD_BUILD_LIB)
|
||||||
|
//
|
||||||
|
// Tell the autolink to link dynamically, this will get undef'ed by auto_link.hpp
|
||||||
|
// once it's done with it:
|
||||||
|
//
|
||||||
|
#if defined(BOOST_THREAD_USE_DLL)
|
||||||
|
# define BOOST_DYN_LINK
|
||||||
|
#endif
|
||||||
|
//
|
||||||
|
// Set the name of our library, this will get undef'ed by auto_link.hpp
|
||||||
|
// once it's done with it:
|
||||||
|
//
|
||||||
|
#if defined(BOOST_THREAD_LIB_NAME)
|
||||||
|
# define BOOST_LIB_NAME BOOST_THREAD_LIB_NAME
|
||||||
|
#else
|
||||||
|
# define BOOST_LIB_NAME boost_thread
|
||||||
|
#endif
|
||||||
|
//
|
||||||
|
// If we're importing code from a dll, then tell auto_link.hpp about it:
|
||||||
|
//
|
||||||
|
// And include the header that does the work:
|
||||||
|
//
|
||||||
|
#include <boost/config/auto_link.hpp>
|
||||||
|
#endif // auto-linking disabled
|
||||||
|
|
||||||
|
#endif // BOOST_THREAD_CONFIG_WEK1032003_HPP
|
||||||
|
|
||||||
|
// Change Log:
|
||||||
|
// 22 Jan 05 Roland Schwarz (speedsnail)
|
||||||
|
// Usage of BOOST_HAS_DECLSPEC macro.
|
||||||
|
// Default again is static lib usage.
|
||||||
|
// BOOST_DYN_LINK only defined when autolink included.
|
||||||
39
include/boost/thread/detail/force_cast.hpp
Normal file
39
include/boost/thread/detail/force_cast.hpp
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
// Copyright (C) 2001-2003
|
||||||
|
// Mac Murrett
|
||||||
|
//
|
||||||
|
// 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 http://www.boost.org for most recent version including documentation.
|
||||||
|
|
||||||
|
#ifndef BOOST_FORCE_CAST_MJM012402_HPP
|
||||||
|
#define BOOST_FORCE_CAST_MJM012402_HPP
|
||||||
|
|
||||||
|
#include <boost/thread/detail/config.hpp>
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
namespace detail {
|
||||||
|
namespace thread {
|
||||||
|
|
||||||
|
// force_cast will convert anything to anything.
|
||||||
|
|
||||||
|
// general case
|
||||||
|
template<class Return_Type, class Argument_Type>
|
||||||
|
inline Return_Type &force_cast(Argument_Type &rSrc)
|
||||||
|
{
|
||||||
|
return(*reinterpret_cast<Return_Type *>(&rSrc));
|
||||||
|
}
|
||||||
|
|
||||||
|
// specialization for const
|
||||||
|
template<class Return_Type, class Argument_Type>
|
||||||
|
inline const Return_Type &force_cast(const Argument_Type &rSrc)
|
||||||
|
{
|
||||||
|
return(*reinterpret_cast<const Return_Type *>(&rSrc));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace thread
|
||||||
|
} // namespace detail
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
#endif // BOOST_FORCE_CAST_MJM012402_HPP
|
||||||
@@ -1,207 +0,0 @@
|
|||||||
// Copyright (C) 2001
|
|
||||||
// William E. Kempf
|
|
||||||
//
|
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
|
||||||
// and its documentation for any purpose is hereby granted without fee,
|
|
||||||
// provided that the above copyright notice appear in all copies and
|
|
||||||
// that both that copyright notice and this permission notice appear
|
|
||||||
// in supporting documentation. William E. Kempf makes no representations
|
|
||||||
// about the suitability of this software for any purpose.
|
|
||||||
// It is provided "as is" without express or implied warranty.
|
|
||||||
|
|
||||||
#ifndef BOOST_XLOCK_WEK070601_HPP
|
|
||||||
#define BOOST_XLOCK_WEK070601_HPP
|
|
||||||
|
|
||||||
#include <boost/utility.hpp>
|
|
||||||
#include <boost/thread/exceptions.hpp>
|
|
||||||
|
|
||||||
namespace boost {
|
|
||||||
|
|
||||||
class condition;
|
|
||||||
struct xtime;
|
|
||||||
|
|
||||||
namespace detail { namespace thread {
|
|
||||||
|
|
||||||
template <typename Mutex>
|
|
||||||
class lock_ops : private noncopyable
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
lock_ops() { }
|
|
||||||
|
|
||||||
public:
|
|
||||||
typedef typename Mutex::cv_state lock_state;
|
|
||||||
|
|
||||||
static void lock(Mutex& m)
|
|
||||||
{
|
|
||||||
m.do_lock();
|
|
||||||
}
|
|
||||||
static bool trylock(Mutex& m)
|
|
||||||
{
|
|
||||||
return m.do_trylock();
|
|
||||||
}
|
|
||||||
static bool timedlock(Mutex& m, const xtime& xt)
|
|
||||||
{
|
|
||||||
return m.do_timedlock(xt);
|
|
||||||
}
|
|
||||||
static void unlock(Mutex& m)
|
|
||||||
{
|
|
||||||
m.do_unlock();
|
|
||||||
}
|
|
||||||
static void lock(Mutex& m, lock_state& state)
|
|
||||||
{
|
|
||||||
m.do_lock(state);
|
|
||||||
}
|
|
||||||
static void unlock(Mutex& m, lock_state& state)
|
|
||||||
{
|
|
||||||
m.do_unlock(state);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Mutex>
|
|
||||||
class scoped_lock : private noncopyable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef Mutex mutex_type;
|
|
||||||
|
|
||||||
explicit scoped_lock(Mutex& mx, bool initially_locked=true)
|
|
||||||
: m_mutex(mx), m_locked(false)
|
|
||||||
{
|
|
||||||
if (initially_locked) lock();
|
|
||||||
}
|
|
||||||
~scoped_lock()
|
|
||||||
{
|
|
||||||
if (m_locked) unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void lock()
|
|
||||||
{
|
|
||||||
if (m_locked) throw lock_error();
|
|
||||||
lock_ops<Mutex>::lock(m_mutex);
|
|
||||||
m_locked = true;
|
|
||||||
}
|
|
||||||
void unlock()
|
|
||||||
{
|
|
||||||
if (!m_locked) throw lock_error();
|
|
||||||
lock_ops<Mutex>::unlock(m_mutex);
|
|
||||||
m_locked = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool locked() const { return m_locked; }
|
|
||||||
operator const void*() const { return m_locked ? this : 0; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
friend class boost::condition;
|
|
||||||
|
|
||||||
Mutex& m_mutex;
|
|
||||||
bool m_locked;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename TryMutex>
|
|
||||||
class scoped_try_lock : private noncopyable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef TryMutex mutex_type;
|
|
||||||
|
|
||||||
explicit scoped_try_lock(TryMutex& mx)
|
|
||||||
: m_mutex(mx), m_locked(false)
|
|
||||||
{
|
|
||||||
try_lock();
|
|
||||||
}
|
|
||||||
scoped_try_lock(TryMutex& mx, bool initially_locked)
|
|
||||||
: m_mutex(mx), m_locked(false)
|
|
||||||
{
|
|
||||||
if (initially_locked) lock();
|
|
||||||
}
|
|
||||||
~scoped_try_lock()
|
|
||||||
{
|
|
||||||
if (m_locked) unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void lock()
|
|
||||||
{
|
|
||||||
if (m_locked) throw lock_error();
|
|
||||||
lock_ops<TryMutex>::lock(m_mutex);
|
|
||||||
m_locked = true;
|
|
||||||
}
|
|
||||||
bool try_lock()
|
|
||||||
{
|
|
||||||
if (m_locked) throw lock_error();
|
|
||||||
return (m_locked = lock_ops<TryMutex>::trylock(m_mutex));
|
|
||||||
}
|
|
||||||
void unlock()
|
|
||||||
{
|
|
||||||
if (!m_locked) throw lock_error();
|
|
||||||
lock_ops<TryMutex>::unlock(m_mutex);
|
|
||||||
m_locked = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool locked() const { return m_locked; }
|
|
||||||
operator const void*() const { return m_locked ? this : 0; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
friend class boost::condition;
|
|
||||||
|
|
||||||
TryMutex& m_mutex;
|
|
||||||
bool m_locked;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename TimedMutex>
|
|
||||||
class scoped_timed_lock : private noncopyable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef TimedMutex mutex_type;
|
|
||||||
|
|
||||||
scoped_timed_lock(TimedMutex& mx, const xtime& xt)
|
|
||||||
: m_mutex(mx), m_locked(false)
|
|
||||||
{
|
|
||||||
timed_lock(xt);
|
|
||||||
}
|
|
||||||
scoped_timed_lock(TimedMutex& mx, bool initially_locked)
|
|
||||||
: m_mutex(mx), m_locked(false)
|
|
||||||
{
|
|
||||||
if (initially_locked) lock();
|
|
||||||
}
|
|
||||||
~scoped_timed_lock()
|
|
||||||
{
|
|
||||||
if (m_locked) unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void lock()
|
|
||||||
{
|
|
||||||
if (m_locked) throw lock_error();
|
|
||||||
lock_ops<TimedMutex>::lock(m_mutex);
|
|
||||||
m_locked = true;
|
|
||||||
}
|
|
||||||
bool timed_lock(const xtime& xt)
|
|
||||||
{
|
|
||||||
if (m_locked) throw lock_error();
|
|
||||||
return (m_locked = lock_ops<TimedMutex>::timedlock(m_mutex, xt));
|
|
||||||
}
|
|
||||||
void unlock()
|
|
||||||
{
|
|
||||||
if (!m_locked) throw lock_error();
|
|
||||||
lock_ops<TimedMutex>::unlock(m_mutex);
|
|
||||||
m_locked = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool locked() const { return m_locked; }
|
|
||||||
operator const void*() const { return m_locked ? this : 0; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
friend class boost::condition;
|
|
||||||
|
|
||||||
TimedMutex& m_mutex;
|
|
||||||
bool m_locked;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace thread
|
|
||||||
} // namespace detail
|
|
||||||
} // namespace boost
|
|
||||||
|
|
||||||
// Change Log:
|
|
||||||
// 8 Feb 01 WEKEMPF Initial version.
|
|
||||||
// 22 May 01 WEKEMPF Modified to use xtime for time outs.
|
|
||||||
// 30 Jul 01 WEKEMPF Moved lock types into boost::detail::thread. Renamed some types.
|
|
||||||
// Added locked() methods.
|
|
||||||
|
|
||||||
#endif // BOOST_XLOCK_WEK070601_HPP
|
|
||||||
56
include/boost/thread/detail/move.hpp
Normal file
56
include/boost/thread/detail/move.hpp
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
#include <boost/utility/enable_if.hpp>
|
||||||
|
#include <boost/type_traits/is_convertible.hpp>
|
||||||
|
|
||||||
|
#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&);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
typename enable_if<boost::is_convertible<T&,detail::thread_move_t<T> >, detail::thread_move_t<T> >::type move(T& t)
|
||||||
|
{
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
59
include/boost/thread/detail/singleton.hpp
Normal file
59
include/boost/thread/detail/singleton.hpp
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
// Copyright (C) 2001-2003
|
||||||
|
// Mac Murrett
|
||||||
|
//
|
||||||
|
// 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 http://www.boost.org for most recent version including documentation.
|
||||||
|
|
||||||
|
#ifndef BOOST_SINGLETON_MJM012402_HPP
|
||||||
|
#define BOOST_SINGLETON_MJM012402_HPP
|
||||||
|
|
||||||
|
#include <boost/thread/detail/config.hpp>
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
namespace detail {
|
||||||
|
namespace thread {
|
||||||
|
|
||||||
|
// class singleton has the same goal as all singletons: create one instance of
|
||||||
|
// a class on demand, then dish it out as requested.
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class singleton : private T
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
singleton();
|
||||||
|
~singleton();
|
||||||
|
|
||||||
|
public:
|
||||||
|
static T &instance();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
inline singleton<T>::singleton()
|
||||||
|
{
|
||||||
|
/* no-op */
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
inline singleton<T>::~singleton()
|
||||||
|
{
|
||||||
|
/* no-op */
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
/*static*/ T &singleton<T>::instance()
|
||||||
|
{
|
||||||
|
// function-local static to force this to work correctly at static
|
||||||
|
// initialization time.
|
||||||
|
static singleton<T> s_oT;
|
||||||
|
return(s_oT);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace thread
|
||||||
|
} // namespace detail
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
#endif // BOOST_SINGLETON_MJM012402_HPP
|
||||||
566
include/boost/thread/detail/thread.hpp
Normal file
566
include/boost/thread/detail/thread.hpp
Normal file
@@ -0,0 +1,566 @@
|
|||||||
|
#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
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class F>
|
||||||
|
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 detail::thread_move_t<thread> move(detail::thread_move_t<thread> t)
|
||||||
|
{
|
||||||
|
return 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
|
||||||
82
include/boost/thread/detail/tss_hooks.hpp
Normal file
82
include/boost/thread/detail/tss_hooks.hpp
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
// (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)
|
||||||
|
|
||||||
|
#if !defined(BOOST_TLS_HOOKS_HPP)
|
||||||
|
#define BOOST_TLS_HOOKS_HPP
|
||||||
|
|
||||||
|
#include <boost/thread/detail/config.hpp>
|
||||||
|
|
||||||
|
#include <boost/config/abi_prefix.hpp>
|
||||||
|
|
||||||
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
|
||||||
|
typedef void (__cdecl *thread_exit_handler)(void);
|
||||||
|
|
||||||
|
extern "C" BOOST_THREAD_DECL int at_thread_exit(
|
||||||
|
thread_exit_handler exit_handler
|
||||||
|
);
|
||||||
|
//Add a function to the list of functions that will
|
||||||
|
//be called when a thread is about to exit.
|
||||||
|
//Currently only implemented for Win32, but should
|
||||||
|
//later be implemented for all platforms.
|
||||||
|
//Used by Win32 implementation of Boost.Threads
|
||||||
|
//tss to perform cleanup.
|
||||||
|
//Like the C runtime library atexit() function,
|
||||||
|
//which it mimics, at_thread_exit() returns
|
||||||
|
//zero if successful and a nonzero
|
||||||
|
//value if an error occurs.
|
||||||
|
|
||||||
|
#endif //defined(BOOST_HAS_WINTHREADS)
|
||||||
|
|
||||||
|
#if defined(BOOST_HAS_WINTHREADS)
|
||||||
|
|
||||||
|
extern "C" BOOST_THREAD_DECL void on_process_enter(void);
|
||||||
|
//Function to be called when the exe or dll
|
||||||
|
//that uses Boost.Threads first starts
|
||||||
|
//or is first loaded.
|
||||||
|
//Should be called only before the first call to
|
||||||
|
//on_thread_enter().
|
||||||
|
//Called automatically by Boost.Threads when
|
||||||
|
//a method for doing so has been discovered.
|
||||||
|
//May be omitted; may be called multiple times.
|
||||||
|
|
||||||
|
extern "C" BOOST_THREAD_DECL void on_process_exit(void);
|
||||||
|
//Function to be called when the exe or dll
|
||||||
|
//that uses Boost.Threads first starts
|
||||||
|
//or is first loaded.
|
||||||
|
//Should be called only after the last call to
|
||||||
|
//on_exit_thread().
|
||||||
|
//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" BOOST_THREAD_DECL void on_thread_enter(void);
|
||||||
|
//Function to be called just after a thread starts
|
||||||
|
//in an exe or dll that uses Boost.Threads.
|
||||||
|
//Must be called in the context of the thread
|
||||||
|
//that is starting.
|
||||||
|
//Called automatically by Boost.Threads when
|
||||||
|
//a method for doing so has been discovered.
|
||||||
|
//May be omitted; may be called multiple times.
|
||||||
|
|
||||||
|
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
|
||||||
|
//that is ending.
|
||||||
|
//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
|
||||||
|
//it to be linked into the Boost.Threads library.
|
||||||
|
|
||||||
|
#endif //defined(BOOST_HAS_WINTHREADS)
|
||||||
|
|
||||||
|
#include <boost/config/abi_suffix.hpp>
|
||||||
|
|
||||||
|
#endif //!defined(BOOST_TLS_HOOKS_HPP)
|
||||||
@@ -1,39 +1,114 @@
|
|||||||
// Copyright (C) 2001
|
// Copyright (C) 2001-2003
|
||||||
// William E. Kempf
|
// William E. Kempf
|
||||||
|
// Copyright (C) 2007-8 Anthony Williams
|
||||||
//
|
//
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
// and its documentation for any purpose is hereby granted without fee,
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
// provided that the above copyright notice appear in all copies and
|
|
||||||
// that both that copyright notice and this permission notice appear
|
|
||||||
// in supporting documentation. William E. Kempf makes no representations
|
|
||||||
// about the suitability of this software for any purpose.
|
|
||||||
// It is provided "as is" without express or implied warranty.
|
|
||||||
|
|
||||||
#ifndef BOOST_THREAD_EXCEPTIONS_PDM070801_H
|
#ifndef BOOST_THREAD_EXCEPTIONS_PDM070801_H
|
||||||
#define BOOST_THREAD_EXCEPTIONS_PDM070801_H
|
#define BOOST_THREAD_EXCEPTIONS_PDM070801_H
|
||||||
|
|
||||||
|
#include <boost/thread/detail/config.hpp>
|
||||||
|
|
||||||
// pdm: Sorry, but this class is used all over the place & I end up
|
// pdm: Sorry, but this class is used all over the place & I end up
|
||||||
// with recursive headers if I don't separate it
|
// with recursive headers if I don't separate it
|
||||||
// wek: Not sure why recursive headers would cause compilation problems
|
// wek: Not sure why recursive headers would cause compilation problems
|
||||||
// given the include guards, but regardless it makes sense to
|
// given the include guards, but regardless it makes sense to
|
||||||
// seperate this out any way.
|
// seperate this out any way.
|
||||||
|
|
||||||
|
#include <string>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
namespace boost {
|
#include <boost/config/abi_prefix.hpp>
|
||||||
|
|
||||||
class lock_error : public std::runtime_error
|
namespace boost
|
||||||
|
{
|
||||||
|
|
||||||
|
class BOOST_THREAD_DECL thread_interrupted
|
||||||
|
{};
|
||||||
|
|
||||||
|
class BOOST_THREAD_DECL thread_exception : public std::exception
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
thread_exception();
|
||||||
|
thread_exception(int sys_err_code);
|
||||||
|
|
||||||
|
public:
|
||||||
|
~thread_exception() throw();
|
||||||
|
|
||||||
|
int native_error() const;
|
||||||
|
|
||||||
|
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:
|
public:
|
||||||
lock_error();
|
lock_error();
|
||||||
|
lock_error(int sys_err_code);
|
||||||
|
~lock_error() throw();
|
||||||
|
|
||||||
|
virtual const char* what() const throw();
|
||||||
};
|
};
|
||||||
|
|
||||||
class thread_resource_error : public std::runtime_error
|
class BOOST_THREAD_DECL thread_resource_error : public thread_exception
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
thread_resource_error();
|
thread_resource_error();
|
||||||
|
thread_resource_error(int sys_err_code);
|
||||||
|
~thread_resource_error() throw();
|
||||||
|
|
||||||
|
virtual const char* what() const throw();
|
||||||
|
};
|
||||||
|
|
||||||
|
class BOOST_THREAD_DECL unsupported_thread_option : public thread_exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
unsupported_thread_option();
|
||||||
|
unsupported_thread_option(int sys_err_code);
|
||||||
|
~unsupported_thread_option() throw();
|
||||||
|
|
||||||
|
virtual const char* what() const throw();
|
||||||
|
};
|
||||||
|
|
||||||
|
class BOOST_THREAD_DECL invalid_thread_argument : public thread_exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
invalid_thread_argument();
|
||||||
|
invalid_thread_argument(int sys_err_code);
|
||||||
|
~invalid_thread_argument() throw();
|
||||||
|
|
||||||
|
virtual const char* what() const throw();
|
||||||
|
};
|
||||||
|
|
||||||
|
class BOOST_THREAD_DECL thread_permission_error : public thread_exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
thread_permission_error();
|
||||||
|
thread_permission_error(int sys_err_code);
|
||||||
|
~thread_permission_error() throw();
|
||||||
|
|
||||||
|
virtual const char* what() const throw();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace boost
|
} // namespace boost
|
||||||
|
|
||||||
|
#include <boost/config/abi_suffix.hpp>
|
||||||
|
|
||||||
#endif // BOOST_THREAD_CONFIG_PDM070801_H
|
#endif // BOOST_THREAD_CONFIG_PDM070801_H
|
||||||
|
|
||||||
|
// Change log:
|
||||||
|
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
|
||||||
|
|
||||||
|
|||||||
1135
include/boost/thread/locks.hpp
Normal file
1135
include/boost/thread/locks.hpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,139 +1,21 @@
|
|||||||
// Copyright (C) 2001
|
#ifndef BOOST_THREAD_MUTEX_HPP
|
||||||
// William E. Kempf
|
#define BOOST_THREAD_MUTEX_HPP
|
||||||
|
|
||||||
|
// mutex.hpp
|
||||||
//
|
//
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
// (C) Copyright 2007 Anthony Williams
|
||||||
// and its documentation for any purpose is hereby granted without fee,
|
//
|
||||||
// provided that the above copyright notice appear in all copies and
|
// Distributed under the Boost Software License, Version 1.0. (See
|
||||||
// that both that copyright notice and this permission notice appear
|
// accompanying file LICENSE_1_0.txt or copy at
|
||||||
// in supporting documentation. William E. Kempf makes no representations
|
// http://www.boost.org/LICENSE_1_0.txt)
|
||||||
// about the suitability of this software for any purpose.
|
|
||||||
// It is provided "as is" without express or implied warranty.
|
|
||||||
|
|
||||||
#ifndef BOOST_MUTEX_WEK070601_HPP
|
#include <boost/thread/detail/platform.hpp>
|
||||||
#define BOOST_MUTEX_WEK070601_HPP
|
#if defined(BOOST_THREAD_PLATFORM_WIN32)
|
||||||
|
#include <boost/thread/win32/mutex.hpp>
|
||||||
#include <boost/config.hpp>
|
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
|
||||||
#ifndef BOOST_HAS_THREADS
|
#include <boost/thread/pthread/mutex.hpp>
|
||||||
# error Thread support is unavailable!
|
#else
|
||||||
|
#error "Boost threads unavailable on this platform"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <boost/utility.hpp>
|
|
||||||
#include <boost/thread/detail/lock.hpp>
|
|
||||||
|
|
||||||
#if defined(BOOST_HAS_PTHREADS)
|
|
||||||
# include <pthread.h>
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace boost {
|
|
||||||
|
|
||||||
struct xtime;
|
|
||||||
|
|
||||||
class mutex : private noncopyable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
friend class detail::thread::lock_ops<mutex>;
|
|
||||||
|
|
||||||
typedef detail::thread::scoped_lock<mutex> scoped_lock;
|
|
||||||
|
|
||||||
mutex();
|
|
||||||
~mutex();
|
|
||||||
|
|
||||||
private:
|
|
||||||
#if defined(BOOST_HAS_WINTHREADS)
|
|
||||||
typedef void* cv_state;
|
|
||||||
#elif defined(BOOST_HAS_PTHREADS)
|
|
||||||
struct cv_state
|
|
||||||
{
|
|
||||||
pthread_mutex_t* pmutex;
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
void do_lock();
|
|
||||||
void do_unlock();
|
|
||||||
void do_lock(cv_state& state);
|
|
||||||
void do_unlock(cv_state& state);
|
|
||||||
|
|
||||||
#if defined(BOOST_HAS_WINTHREADS)
|
|
||||||
void* m_mutex;
|
|
||||||
#elif defined(BOOST_HAS_PTHREADS)
|
|
||||||
pthread_mutex_t m_mutex;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
class try_mutex : private noncopyable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
friend class detail::thread::lock_ops<try_mutex>;
|
|
||||||
|
|
||||||
typedef detail::thread::scoped_lock<try_mutex> scoped_lock;
|
|
||||||
typedef detail::thread::scoped_try_lock<try_mutex> scoped_try_lock;
|
|
||||||
|
|
||||||
try_mutex();
|
|
||||||
~try_mutex();
|
|
||||||
|
|
||||||
private:
|
|
||||||
#if defined(BOOST_HAS_WINTHREADS)
|
|
||||||
typedef void* cv_state;
|
|
||||||
#elif defined(BOOST_HAS_PTHREADS)
|
|
||||||
struct cv_state
|
|
||||||
{
|
|
||||||
pthread_mutex_t* pmutex;
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
void do_lock();
|
|
||||||
bool do_trylock();
|
|
||||||
void do_unlock();
|
|
||||||
void do_lock(cv_state& state);
|
|
||||||
void do_unlock(cv_state& state);
|
|
||||||
|
|
||||||
#if defined(BOOST_HAS_WINTHREADS)
|
|
||||||
void* m_mutex;
|
|
||||||
#elif defined(BOOST_HAS_PTHREADS)
|
|
||||||
pthread_mutex_t m_mutex;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
class timed_mutex : private noncopyable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
friend class detail::thread::lock_ops<timed_mutex>;
|
|
||||||
|
|
||||||
typedef detail::thread::scoped_lock<timed_mutex> scoped_lock;
|
|
||||||
typedef detail::thread::scoped_try_lock<timed_mutex> scoped_try_lock;
|
|
||||||
typedef detail::thread::scoped_timed_lock<timed_mutex> scoped_timed_lock;
|
|
||||||
|
|
||||||
timed_mutex();
|
|
||||||
~timed_mutex();
|
|
||||||
|
|
||||||
private:
|
|
||||||
#if defined(BOOST_HAS_WINTHREADS)
|
|
||||||
typedef void* cv_state;
|
|
||||||
#elif defined(BOOST_HAS_PTHREADS)
|
|
||||||
struct cv_state
|
|
||||||
{
|
|
||||||
pthread_mutex_t* pmutex;
|
|
||||||
};
|
|
||||||
#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;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace boost
|
|
||||||
|
|
||||||
// Change Log:
|
|
||||||
// 8 Feb 01 WEKEMPF Initial version.
|
|
||||||
// 22 May 01 WEKEMPF Modified to use xtime for time outs. Factored out
|
|
||||||
// to three classes, mutex, try_mutex and timed_mutex.
|
|
||||||
|
|
||||||
#endif // BOOST_MUTEX_WEK070601_HPP
|
|
||||||
|
|||||||
@@ -1,45 +1,33 @@
|
|||||||
// Copyright (C) 2001
|
#ifndef BOOST_THREAD_ONCE_HPP
|
||||||
// William E. Kempf
|
#define BOOST_THREAD_ONCE_HPP
|
||||||
|
|
||||||
|
// once.hpp
|
||||||
//
|
//
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
// (C) Copyright 2006-7 Anthony Williams
|
||||||
// and its documentation for any purpose is hereby granted without fee,
|
//
|
||||||
// provided that the above copyright notice appear in all copies and
|
// Distributed under the Boost Software License, Version 1.0. (See
|
||||||
// that both that copyright notice and this permission notice appear
|
// accompanying file LICENSE_1_0.txt or copy at
|
||||||
// in supporting documentation. William E. Kempf makes no representations
|
// http://www.boost.org/LICENSE_1_0.txt)
|
||||||
// about the suitability of this software for any purpose.
|
|
||||||
// It is provided "as is" without express or implied warranty.
|
|
||||||
|
|
||||||
#ifndef BOOST_ONCE_WEK080101_HPP
|
#include <boost/thread/detail/platform.hpp>
|
||||||
#define BOOST_ONCE_WEK080101_HPP
|
#if defined(BOOST_THREAD_PLATFORM_WIN32)
|
||||||
|
#include <boost/thread/win32/once.hpp>
|
||||||
#include <boost/config.hpp>
|
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
|
||||||
#ifndef BOOST_HAS_THREADS
|
#include <boost/thread/pthread/once.hpp>
|
||||||
# error Thread support is unavailable!
|
#else
|
||||||
|
#error "Boost threads unavailable on this platform"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(BOOST_HAS_PTHREADS)
|
#include <boost/config/abi_prefix.hpp>
|
||||||
# include <pthread.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace boost {
|
namespace boost
|
||||||
|
{
|
||||||
|
inline void call_once(void (*func)(),once_flag& flag)
|
||||||
|
{
|
||||||
|
call_once(flag,func);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(BOOST_HAS_PTHREADS)
|
#include <boost/config/abi_suffix.hpp>
|
||||||
|
|
||||||
typedef pthread_once_t once_flag;
|
|
||||||
#define BOOST_ONCE_INIT PTHREAD_ONCE_INIT
|
|
||||||
|
|
||||||
#elif defined(BOOST_HAS_WINTHREADS)
|
|
||||||
|
|
||||||
typedef bool once_flag;
|
|
||||||
#define BOOST_ONCE_INIT false
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void call_once(void (*func)(), once_flag& flag);
|
|
||||||
|
|
||||||
} // namespace boost
|
|
||||||
|
|
||||||
// Change Log:
|
|
||||||
// 1 Aug 01 WEKEMPF Initial version.
|
|
||||||
|
|
||||||
#endif // BOOST_ONCE_WEK080101_HPP
|
|
||||||
|
|||||||
165
include/boost/thread/pthread/condition_variable.hpp
Normal file
165
include/boost/thread/pthread/condition_variable.hpp
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
#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,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
|
||||||
87
include/boost/thread/pthread/condition_variable_fwd.hpp
Normal file
87
include/boost/thread/pthread/condition_variable_fwd.hpp
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
#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);
|
||||||
|
|
||||||
|
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
|
||||||
205
include/boost/thread/pthread/mutex.hpp
Normal file
205
include/boost/thread/pthread/mutex.hpp
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
#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/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);
|
||||||
|
}
|
||||||
|
|
||||||
|
#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==EBUSY);
|
||||||
|
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 lock(state_change);
|
||||||
|
|
||||||
|
while(state.exclusive || state.exclusive_waiting_blocked)
|
||||||
|
{
|
||||||
|
shared_cond.wait(lock);
|
||||||
|
}
|
||||||
|
++state.shared_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool try_lock_shared()
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(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 lock(state_change);
|
||||||
|
|
||||||
|
while(state.exclusive || state.exclusive_waiting_blocked)
|
||||||
|
{
|
||||||
|
if(!shared_cond.timed_wait(lock,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 lock(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 lock(state_change);
|
||||||
|
|
||||||
|
while(state.shared_count || state.exclusive)
|
||||||
|
{
|
||||||
|
state.exclusive_waiting_blocked=true;
|
||||||
|
exclusive_cond.wait(lock);
|
||||||
|
}
|
||||||
|
state.exclusive=true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool timed_lock(system_time const& timeout)
|
||||||
|
{
|
||||||
|
boost::this_thread::disable_interruption do_not_disturb;
|
||||||
|
boost::mutex::scoped_lock lock(state_change);
|
||||||
|
|
||||||
|
while(state.shared_count || state.exclusive)
|
||||||
|
{
|
||||||
|
state.exclusive_waiting_blocked=true;
|
||||||
|
if(!exclusive_cond.timed_wait(lock,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 lock(state_change);
|
||||||
|
|
||||||
|
if(state.shared_count || state.exclusive)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
state.exclusive=true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void unlock()
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(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 lock(state_change);
|
||||||
|
while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
|
||||||
|
{
|
||||||
|
shared_cond.wait(lock);
|
||||||
|
}
|
||||||
|
++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 lock(state_change);
|
||||||
|
while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
|
||||||
|
{
|
||||||
|
if(!shared_cond.timed_wait(lock,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 lock(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 lock(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 lock(state_change);
|
||||||
|
--state.shared_count;
|
||||||
|
while(state.shared_count)
|
||||||
|
{
|
||||||
|
upgrade_cond.wait(lock);
|
||||||
|
}
|
||||||
|
state.upgrade=false;
|
||||||
|
state.exclusive=true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void unlock_and_lock_upgrade()
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(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 lock(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 lock(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,160 +1,21 @@
|
|||||||
// Copyright (C) 2001
|
#ifndef BOOST_THREAD_RECURSIVE_MUTEX_HPP
|
||||||
// William E. Kempf
|
#define BOOST_THREAD_RECURSIVE_MUTEX_HPP
|
||||||
|
|
||||||
|
// recursive_mutex.hpp
|
||||||
//
|
//
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
// (C) Copyright 2007 Anthony Williams
|
||||||
// and its documentation for any purpose is hereby granted without fee,
|
//
|
||||||
// provided that the above copyright notice appear in all copies and
|
// Distributed under the Boost Software License, Version 1.0. (See
|
||||||
// that both that copyright notice and this permission notice appear
|
// accompanying file LICENSE_1_0.txt or copy at
|
||||||
// in supporting documentation. William E. Kempf makes no representations
|
// http://www.boost.org/LICENSE_1_0.txt)
|
||||||
// about the suitability of this software for any purpose.
|
|
||||||
// It is provided "as is" without express or implied warranty.
|
|
||||||
|
|
||||||
#ifndef BOOST_RECURSIVE_MUTEX_WEK070601_HPP
|
#include <boost/thread/detail/platform.hpp>
|
||||||
#define BOOST_RECURSIVE_MUTEX_WEK070601_HPP
|
#if defined(BOOST_THREAD_PLATFORM_WIN32)
|
||||||
|
#include <boost/thread/win32/recursive_mutex.hpp>
|
||||||
#include <boost/config.hpp>
|
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
|
||||||
#ifndef BOOST_HAS_THREADS
|
#include <boost/thread/pthread/recursive_mutex.hpp>
|
||||||
# error Thread support is unavailable!
|
#else
|
||||||
|
#error "Boost threads unavailable on this platform"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <boost/utility.hpp>
|
|
||||||
#include <boost/thread/detail/lock.hpp>
|
|
||||||
|
|
||||||
#if defined(BOOST_HAS_PTHREADS)
|
|
||||||
# include <pthread.h>
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace boost {
|
|
||||||
|
|
||||||
struct xtime;
|
|
||||||
|
|
||||||
class recursive_mutex : private noncopyable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
friend class detail::thread::lock_ops<recursive_mutex>;
|
|
||||||
|
|
||||||
typedef detail::thread::scoped_lock<recursive_mutex> scoped_lock;
|
|
||||||
|
|
||||||
recursive_mutex();
|
|
||||||
~recursive_mutex();
|
|
||||||
|
|
||||||
private:
|
|
||||||
#if defined(BOOST_HAS_WINTHREADS)
|
|
||||||
typedef std::size_t cv_state;
|
|
||||||
#elif defined(BOOST_HAS_PTHREADS)
|
|
||||||
struct cv_state
|
|
||||||
{
|
|
||||||
long count;
|
|
||||||
pthread_mutex_t* pmutex;
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
void do_lock();
|
|
||||||
void do_unlock();
|
|
||||||
void do_lock(cv_state& state);
|
|
||||||
void do_unlock(cv_state& state);
|
|
||||||
|
|
||||||
#if defined(BOOST_HAS_WINTHREADS)
|
|
||||||
void* m_mutex;
|
|
||||||
unsigned long m_count;
|
|
||||||
#elif defined(BOOST_HAS_PTHREADS)
|
|
||||||
pthread_mutex_t m_mutex;
|
|
||||||
unsigned m_count;
|
|
||||||
# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
|
|
||||||
pthread_cond_t m_unlocked;
|
|
||||||
pthread_t m_thread_id;
|
|
||||||
bool m_valid_id;
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
class recursive_try_mutex : private noncopyable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
friend class detail::thread::lock_ops<recursive_try_mutex>;
|
|
||||||
|
|
||||||
typedef detail::thread::scoped_lock<recursive_try_mutex> scoped_lock;
|
|
||||||
typedef detail::thread::scoped_try_lock<recursive_try_mutex> scoped_try_lock;
|
|
||||||
|
|
||||||
recursive_try_mutex();
|
|
||||||
~recursive_try_mutex();
|
|
||||||
|
|
||||||
private:
|
|
||||||
#if defined(BOOST_HAS_WINTHREADS)
|
|
||||||
typedef std::size_t cv_state;
|
|
||||||
#elif defined(BOOST_HAS_PTHREADS)
|
|
||||||
struct cv_state
|
|
||||||
{
|
|
||||||
long count;
|
|
||||||
pthread_mutex_t* pmutex;
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
void do_lock();
|
|
||||||
bool do_trylock();
|
|
||||||
void do_unlock();
|
|
||||||
void do_lock(cv_state& state);
|
|
||||||
void do_unlock(cv_state& state);
|
|
||||||
|
|
||||||
#if defined(BOOST_HAS_WINTHREADS)
|
|
||||||
void* m_mutex;
|
|
||||||
unsigned long m_count;
|
|
||||||
#elif defined(BOOST_HAS_PTHREADS)
|
|
||||||
pthread_mutex_t m_mutex;
|
|
||||||
unsigned m_count;
|
|
||||||
# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
|
|
||||||
pthread_cond_t m_unlocked;
|
|
||||||
pthread_t m_thread_id;
|
|
||||||
bool m_valid_id;
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
class recursive_timed_mutex : private noncopyable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
friend class detail::thread::lock_ops<recursive_timed_mutex>;
|
|
||||||
|
|
||||||
typedef detail::thread::scoped_lock<recursive_timed_mutex> scoped_lock;
|
|
||||||
typedef detail::thread::scoped_try_lock<recursive_timed_mutex> scoped_try_lock;
|
|
||||||
typedef detail::thread::scoped_timed_lock<recursive_timed_mutex> scoped_timed_lock;
|
|
||||||
|
|
||||||
recursive_timed_mutex();
|
|
||||||
~recursive_timed_mutex();
|
|
||||||
|
|
||||||
private:
|
|
||||||
#if defined(BOOST_HAS_WINTHREADS)
|
|
||||||
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;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace boost
|
|
||||||
|
|
||||||
// Change Log:
|
|
||||||
// 8 Feb 01 WEKEMPF Initial version.
|
|
||||||
// 1 Jun 01 WEKEMPF Modified to use xtime for time outs. Factored out
|
|
||||||
// to three classes, mutex, try_mutex and timed_mutex.
|
|
||||||
// 11 Jun 01 WEKEMPF Modified to use PTHREAD_MUTEX_RECURSIVE if available.
|
|
||||||
|
|
||||||
#endif // BOOST_RECURSIVE_MUTEX_WEK070601_HPP
|
|
||||||
|
|||||||
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,84 +1,25 @@
|
|||||||
// Copyright (C) 2001
|
#ifndef BOOST_THREAD_THREAD_HPP
|
||||||
// William E. Kempf
|
#define BOOST_THREAD_THREAD_HPP
|
||||||
|
|
||||||
|
// thread.hpp
|
||||||
//
|
//
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
// (C) Copyright 2007-8 Anthony Williams
|
||||||
// and its documentation for any purpose is hereby granted without fee,
|
//
|
||||||
// provided that the above copyright notice appear in all copies and
|
// Distributed under the Boost Software License, Version 1.0. (See
|
||||||
// that both that copyright notice and this permission notice appear
|
// accompanying file LICENSE_1_0.txt or copy at
|
||||||
// in supporting documentation. William E. Kempf makes no representations
|
// http://www.boost.org/LICENSE_1_0.txt)
|
||||||
// about the suitability of this software for any purpose.
|
|
||||||
// It is provided "as is" without express or implied warranty.
|
|
||||||
|
|
||||||
#ifndef BOOST_THREAD_WEK070601_HPP
|
#include <boost/thread/detail/platform.hpp>
|
||||||
#define BOOST_THREAD_WEK070601_HPP
|
|
||||||
|
|
||||||
#include <boost/config.hpp>
|
#if defined(BOOST_THREAD_PLATFORM_WIN32)
|
||||||
#ifndef BOOST_HAS_THREADS
|
#include <boost/thread/win32/thread_data.hpp>
|
||||||
# error Thread support is unavailable!
|
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
|
||||||
|
#include <boost/thread/pthread/thread_data.hpp>
|
||||||
|
#else
|
||||||
|
#error "Boost threads unavailable on this platform"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <boost/utility.hpp>
|
#include <boost/thread/detail/thread.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>
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace boost {
|
|
||||||
|
|
||||||
struct xtime;
|
|
||||||
|
|
||||||
class thread : private noncopyable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
thread();
|
|
||||||
explicit thread(const function0<void>& threadfunc);
|
|
||||||
~thread();
|
|
||||||
|
|
||||||
bool operator==(const thread& other) const;
|
|
||||||
bool operator!=(const thread& other) const;
|
|
||||||
|
|
||||||
void join();
|
|
||||||
|
|
||||||
static void sleep(const xtime& xt);
|
|
||||||
static void yield();
|
|
||||||
|
|
||||||
private:
|
|
||||||
#if defined(BOOST_HAS_WINTHREADS)
|
|
||||||
void* m_thread;
|
|
||||||
unsigned int m_id;
|
|
||||||
#elif defined(BOOST_HAS_PTHREADS)
|
|
||||||
private:
|
|
||||||
pthread_t m_thread;
|
|
||||||
#endif
|
|
||||||
bool m_joinable;
|
|
||||||
};
|
|
||||||
|
|
||||||
class thread_group : private noncopyable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
thread_group();
|
|
||||||
~thread_group();
|
|
||||||
|
|
||||||
thread* create_thread(const function0<void>& threadfunc);
|
|
||||||
void add_thread(thread* thrd);
|
|
||||||
void remove_thread(thread* thrd);
|
|
||||||
void join_all();
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::list<thread*> m_threads;
|
|
||||||
mutex m_mutex;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace boost
|
|
||||||
|
|
||||||
// Change Log:
|
|
||||||
// 8 Feb 01 WEKEMPF Initial version.
|
|
||||||
// 1 Jun 01 WEKEMPF Added boost::thread initial implementation.
|
|
||||||
// 3 Jul 01 WEKEMPF Redesigned boost::thread to be noncopyable.
|
|
||||||
|
|
||||||
#endif // BOOST_THREAD_WEK070601_HPP
|
|
||||||
|
|||||||
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,72 +1,110 @@
|
|||||||
// Copyright (C) 2001
|
#ifndef BOOST_THREAD_TSS_HPP
|
||||||
// William E. Kempf
|
#define BOOST_THREAD_TSS_HPP
|
||||||
//
|
// Distributed under the Boost Software License, Version 1.0. (See
|
||||||
// Permission to use, copy, modify, distribute and sell this software
|
// accompanying file LICENSE_1_0.txt or copy at
|
||||||
// and its documentation for any purpose is hereby granted without fee,
|
// http://www.boost.org/LICENSE_1_0.txt)
|
||||||
// provided that the above copyright notice appear in all copies and
|
// (C) Copyright 2007-8 Anthony Williams
|
||||||
// that both that copyright notice and this permission notice appear
|
|
||||||
// in supporting documentation. William E. Kempf makes no representations
|
|
||||||
// about the suitability of this software for any purpose.
|
|
||||||
// It is provided "as is" without express or implied warranty.
|
|
||||||
|
|
||||||
#ifndef BOOST_TSS_WEK070601_HPP
|
#include <boost/shared_ptr.hpp>
|
||||||
#define BOOST_TSS_WEK070601_HPP
|
#include <boost/thread/detail/thread_heap_alloc.hpp>
|
||||||
|
|
||||||
#include <boost/config.hpp>
|
#include <boost/config/abi_prefix.hpp>
|
||||||
#ifndef BOOST_HAS_THREADS
|
|
||||||
# error Thread support is unavailable!
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <boost/utility.hpp>
|
namespace boost
|
||||||
|
{
|
||||||
#if defined(BOOST_HAS_PTHREADS)
|
namespace detail
|
||||||
# include <pthread.h>
|
{
|
||||||
#endif
|
struct tss_cleanup_function
|
||||||
|
|
||||||
namespace boost {
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
class tss : private noncopyable
|
|
||||||
{
|
{
|
||||||
public:
|
virtual ~tss_cleanup_function()
|
||||||
tss(void (*cleanup)(void*)=0);
|
{}
|
||||||
~tss();
|
|
||||||
|
virtual void operator()(void* data)=0;
|
||||||
void* get() const;
|
|
||||||
bool set(void* value);
|
|
||||||
|
|
||||||
private:
|
|
||||||
#if defined(BOOST_HAS_WINTHREADS)
|
|
||||||
unsigned long m_key;
|
|
||||||
void (*m_cleanup)(void*);
|
|
||||||
#elif defined(BOOST_HAS_PTHREADS)
|
|
||||||
pthread_key_t m_key;
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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>
|
template <typename T>
|
||||||
class thread_specific_ptr : private noncopyable
|
class thread_specific_ptr
|
||||||
{
|
{
|
||||||
public:
|
private:
|
||||||
thread_specific_ptr() : m_tss(&thread_specific_ptr<T>::cleanup) { }
|
thread_specific_ptr(thread_specific_ptr&);
|
||||||
|
thread_specific_ptr& operator=(thread_specific_ptr&);
|
||||||
|
|
||||||
T* get() const { return static_cast<T*>(m_tss.get()); }
|
struct delete_data:
|
||||||
T* operator->() const { return get(); }
|
detail::tss_cleanup_function
|
||||||
T& operator*() const { return *get(); }
|
{
|
||||||
T* release() { T* temp = get(); m_tss.set(0); return temp; }
|
void operator()(void* data)
|
||||||
void reset(T* p=0) { T* cur = get(); if (cur == p) return; delete cur; m_tss.set(p); }
|
{
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
|
||||||
static void cleanup(void* p) { delete static_cast<T*>(p); }
|
|
||||||
|
|
||||||
mutable detail::tss m_tss;
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace boost
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Change Log:
|
#include <boost/config/abi_suffix.hpp>
|
||||||
// 6 Jun 01 WEKEMPF Initial version.
|
|
||||||
|
|
||||||
#endif // BOOST_TSS_WEK070601_HPP
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
130
include/boost/thread/win32/basic_recursive_mutex.hpp
Normal file
130
include/boost/thread/win32/basic_recursive_mutex.hpp
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
#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);
|
||||||
|
}
|
||||||
|
|
||||||
|
long get_active_count()
|
||||||
|
{
|
||||||
|
return mutex.get_active_count();
|
||||||
|
}
|
||||||
|
|
||||||
|
void unlock()
|
||||||
|
{
|
||||||
|
if(!--recursion_count)
|
||||||
|
{
|
||||||
|
BOOST_INTERLOCKED_EXCHANGE(&locking_thread_id,0);
|
||||||
|
mutex.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool locked()
|
||||||
|
{
|
||||||
|
return mutex.locked();
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
182
include/boost/thread/win32/basic_timed_mutex.hpp
Normal file
182
include/boost/thread/win32/basic_timed_mutex.hpp
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
#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/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);
|
||||||
|
}
|
||||||
|
|
||||||
|
long get_active_count()
|
||||||
|
{
|
||||||
|
return ::boost::detail::interlocked_read_acquire(&active_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool locked()
|
||||||
|
{
|
||||||
|
return get_active_count()>=lock_flag_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
639
include/boost/thread/win32/shared_mutex.hpp
Normal file
639
include/boost/thread/win32/shared_mutex.hpp
Normal file
@@ -0,0 +1,639 @@
|
|||||||
|
#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;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
#ifdef BOOST_MSVC
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable:4127)
|
||||||
|
#endif
|
||||||
|
while(true);
|
||||||
|
#ifdef BOOST_MSVC
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
#ifdef BOOST_MSVC
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable:4127)
|
||||||
|
#endif
|
||||||
|
while(true)
|
||||||
|
#ifdef BOOST_MSVC
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
state_data old_state=state;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
#ifdef BOOST_MSVC
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable:4127)
|
||||||
|
#endif
|
||||||
|
while(true);
|
||||||
|
#ifdef BOOST_MSVC
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
#ifdef BOOST_MSVC
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable:4127)
|
||||||
|
#endif
|
||||||
|
while(true);
|
||||||
|
#ifdef BOOST_MSVC
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
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;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
#ifdef BOOST_MSVC
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable:4127)
|
||||||
|
#endif
|
||||||
|
while(true);
|
||||||
|
#ifdef BOOST_MSVC
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
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 timed_lock(boost::system_time const& wait_until)
|
||||||
|
{
|
||||||
|
#ifdef BOOST_MSVC
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable:4127)
|
||||||
|
#endif
|
||||||
|
while(true)
|
||||||
|
#ifdef BOOST_MSVC
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
state_data old_state=state;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
#ifdef BOOST_MSVC
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable:4127)
|
||||||
|
#endif
|
||||||
|
while(true);
|
||||||
|
#ifdef BOOST_MSVC
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
#ifdef BOOST_MSVC
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable:4127)
|
||||||
|
#endif
|
||||||
|
while(true);
|
||||||
|
#ifdef BOOST_MSVC
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
if(!old_state.shared_count && !old_state.exclusive)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
BOOST_ASSERT(wait_res<2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void unlock()
|
||||||
|
{
|
||||||
|
state_data old_state=state;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
#ifdef BOOST_MSVC
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable:4127)
|
||||||
|
#endif
|
||||||
|
while(true);
|
||||||
|
#ifdef BOOST_MSVC
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
release_waiters(old_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void lock_upgrade()
|
||||||
|
{
|
||||||
|
#ifdef BOOST_MSVC
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable:4127)
|
||||||
|
#endif
|
||||||
|
while(true)
|
||||||
|
#ifdef BOOST_MSVC
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
state_data old_state=state;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
#ifdef BOOST_MSVC
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable:4127)
|
||||||
|
#endif
|
||||||
|
while(true);
|
||||||
|
#ifdef BOOST_MSVC
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if(!(old_state.exclusive|| old_state.exclusive_waiting_blocked|| old_state.upgrade))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_VERIFY(!detail::win32::WaitForSingleObject(unlock_sem,detail::win32::infinite));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void unlock_upgrade()
|
||||||
|
{
|
||||||
|
state_data old_state=state;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
#ifdef BOOST_MSVC
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable:4127)
|
||||||
|
#endif
|
||||||
|
while(true);
|
||||||
|
#ifdef BOOST_MSVC
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void unlock_upgrade_and_lock()
|
||||||
|
{
|
||||||
|
state_data old_state=state;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
#ifdef BOOST_MSVC
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable:4127)
|
||||||
|
#endif
|
||||||
|
while(true);
|
||||||
|
#ifdef BOOST_MSVC
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void unlock_and_lock_upgrade()
|
||||||
|
{
|
||||||
|
state_data old_state=state;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
#ifdef BOOST_MSVC
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable:4127)
|
||||||
|
#endif
|
||||||
|
while(true);
|
||||||
|
#ifdef BOOST_MSVC
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
release_waiters(old_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void unlock_and_lock_shared()
|
||||||
|
{
|
||||||
|
state_data old_state=state;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
#ifdef BOOST_MSVC
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable:4127)
|
||||||
|
#endif
|
||||||
|
while(true);
|
||||||
|
#ifdef BOOST_MSVC
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
release_waiters(old_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void unlock_upgrade_and_lock_shared()
|
||||||
|
{
|
||||||
|
state_data old_state=state;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
#ifdef BOOST_MSVC
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable:4127)
|
||||||
|
#endif
|
||||||
|
while(true);
|
||||||
|
#ifdef BOOST_MSVC
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
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
|
||||||
397
include/boost/thread/win32/thread_primitives.hpp
Normal file
397
include/boost/thread/win32/thread_primitives.hpp
Normal file
@@ -0,0 +1,397 @@
|
|||||||
|
#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)
|
||||||
|
#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)
|
||||||
|
|
||||||
|
namespace boost
|
||||||
|
{
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
namespace win32
|
||||||
|
{
|
||||||
|
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
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user